1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.location;
18 
19 import android.content.Context;
20 import android.location.GnssNavigationMessage;
21 import android.location.IGnssNavigationMessageListener;
22 import android.os.Handler;
23 import android.os.RemoteException;
24 import android.util.Log;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 
28 /**
29  * An base implementation for GPS navigation messages provider.
30  * It abstracts out the responsibility of handling listeners, while still allowing technology
31  * specific implementations to be built.
32  *
33  * @hide
34  */
35 public abstract class GnssNavigationMessageProvider
36         extends RemoteListenerHelper<IGnssNavigationMessageListener> {
37     private static final String TAG = "GnssNavigationMessageProvider";
38     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
39 
40     private final GnssNavigationMessageProviderNative mNative;
41     private boolean mCollectionStarted;
42 
GnssNavigationMessageProvider(Context context, Handler handler)43     protected GnssNavigationMessageProvider(Context context, Handler handler) {
44         this(context, handler, new GnssNavigationMessageProviderNative());
45     }
46 
47     @VisibleForTesting
GnssNavigationMessageProvider(Context context, Handler handler, GnssNavigationMessageProviderNative aNative)48     GnssNavigationMessageProvider(Context context, Handler handler,
49             GnssNavigationMessageProviderNative aNative) {
50         super(context, handler, TAG);
51         mNative = aNative;
52     }
53 
resumeIfStarted()54     void resumeIfStarted() {
55         if (DEBUG) {
56             Log.d(TAG, "resumeIfStarted");
57         }
58         if (mCollectionStarted) {
59             mNative.startNavigationMessageCollection();
60         }
61     }
62 
63     @Override
isAvailableInPlatform()64     protected boolean isAvailableInPlatform() {
65         return mNative.isNavigationMessageSupported();
66     }
67 
68     @Override
registerWithService()69     protected int registerWithService() {
70         boolean result = mNative.startNavigationMessageCollection();
71         if (result) {
72             mCollectionStarted = true;
73             return RemoteListenerHelper.RESULT_SUCCESS;
74         } else {
75             return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
76         }
77     }
78 
79     @Override
unregisterFromService()80     protected void unregisterFromService() {
81         boolean stopped = mNative.stopNavigationMessageCollection();
82         if (stopped) {
83             mCollectionStarted = false;
84         }
85     }
86 
onNavigationMessageAvailable(final GnssNavigationMessage event)87     public void onNavigationMessageAvailable(final GnssNavigationMessage event) {
88         foreach((IGnssNavigationMessageListener listener, CallerIdentity callerIdentity) -> {
89                     listener.onGnssNavigationMessageReceived(event);
90                 }
91         );
92     }
93 
94     /** Handle GNSS capabilities update from the GNSS HAL implementation */
onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported)95     public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) {
96         setSupported(isGnssNavigationMessageSupported);
97         updateResult();
98     }
99 
onGpsEnabledChanged()100     public void onGpsEnabledChanged() {
101         tryUpdateRegistrationWithService();
102         updateResult();
103     }
104 
105     @Override
getHandlerOperation(int result)106     protected ListenerOperation<IGnssNavigationMessageListener> getHandlerOperation(int result) {
107         int status;
108         switch (result) {
109             case RESULT_SUCCESS:
110                 status = GnssNavigationMessage.Callback.STATUS_READY;
111                 break;
112             case RESULT_NOT_AVAILABLE:
113             case RESULT_NOT_SUPPORTED:
114             case RESULT_INTERNAL_ERROR:
115                 status = GnssNavigationMessage.Callback.STATUS_NOT_SUPPORTED;
116                 break;
117             case RESULT_GPS_LOCATION_DISABLED:
118                 status = GnssNavigationMessage.Callback.STATUS_LOCATION_DISABLED;
119                 break;
120             case RESULT_UNKNOWN:
121                 return null;
122             default:
123                 Log.v(TAG, "Unhandled addListener result: " + result);
124                 return null;
125         }
126         return new StatusChangedOperation(status);
127     }
128 
129     private static class StatusChangedOperation
130             implements ListenerOperation<IGnssNavigationMessageListener> {
131         private final int mStatus;
132 
StatusChangedOperation(int status)133         public StatusChangedOperation(int status) {
134             mStatus = status;
135         }
136 
137         @Override
execute(IGnssNavigationMessageListener listener, CallerIdentity callerIdentity)138         public void execute(IGnssNavigationMessageListener listener,
139                 CallerIdentity callerIdentity) throws RemoteException {
140             listener.onStatusChanged(mStatus);
141         }
142     }
143 
144     @VisibleForTesting
145     static class GnssNavigationMessageProviderNative {
isNavigationMessageSupported()146         public boolean isNavigationMessageSupported() {
147             return native_is_navigation_message_supported();
148         }
149 
startNavigationMessageCollection()150         public boolean startNavigationMessageCollection() {
151             return native_start_navigation_message_collection();
152         }
153 
stopNavigationMessageCollection()154         public boolean stopNavigationMessageCollection() {
155             return native_stop_navigation_message_collection();
156         }
157     }
158 
native_is_navigation_message_supported()159     private static native boolean native_is_navigation_message_supported();
160 
native_start_navigation_message_collection()161     private static native boolean native_start_navigation_message_collection();
162 
native_stop_navigation_message_collection()163     private static native boolean native_stop_navigation_message_collection();
164 }
165