1 /*
2  * Copyright (C) 2020 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.gnss;
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 import com.android.server.location.CallerIdentity;
28 import com.android.server.location.RemoteListenerHelper;
29 
30 /**
31  * An base implementation for GPS navigation messages provider.
32  * It abstracts out the responsibility of handling listeners, while still allowing technology
33  * specific implementations to be built.
34  *
35  * @hide
36  */
37 public abstract class GnssNavigationMessageProvider
38         extends RemoteListenerHelper<Void, IGnssNavigationMessageListener> {
39     private static final String TAG = "GnssNavigationMessageProvider";
40     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
41 
42     private final GnssNavigationMessageProviderNative mNative;
43     private boolean mCollectionStarted;
44 
GnssNavigationMessageProvider(Context context, Handler handler)45     protected GnssNavigationMessageProvider(Context context, Handler handler) {
46         this(context, handler, new GnssNavigationMessageProviderNative());
47     }
48 
49     @VisibleForTesting
GnssNavigationMessageProvider(Context context, Handler handler, GnssNavigationMessageProviderNative aNative)50     public GnssNavigationMessageProvider(Context context, Handler handler,
51             GnssNavigationMessageProviderNative aNative) {
52         super(context, handler, TAG);
53         mNative = aNative;
54     }
55 
resumeIfStarted()56     void resumeIfStarted() {
57         if (DEBUG) {
58             Log.d(TAG, "resumeIfStarted");
59         }
60         if (mCollectionStarted) {
61             mNative.startNavigationMessageCollection();
62         }
63     }
64 
65     @Override
isAvailableInPlatform()66     protected boolean isAvailableInPlatform() {
67         return mNative.isNavigationMessageSupported();
68     }
69 
70     @Override
registerWithService()71     protected int registerWithService() {
72         boolean result = mNative.startNavigationMessageCollection();
73         if (result) {
74             mCollectionStarted = true;
75             return RemoteListenerHelper.RESULT_SUCCESS;
76         } else {
77             return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
78         }
79     }
80 
81     @Override
unregisterFromService()82     protected void unregisterFromService() {
83         boolean stopped = mNative.stopNavigationMessageCollection();
84         if (stopped) {
85             mCollectionStarted = false;
86         }
87     }
88 
onNavigationMessageAvailable(final GnssNavigationMessage event)89     public void onNavigationMessageAvailable(final GnssNavigationMessage event) {
90         foreach((IGnssNavigationMessageListener listener, CallerIdentity callerIdentity) -> {
91                     listener.onGnssNavigationMessageReceived(event);
92                 }
93         );
94     }
95 
96     /** Handle GNSS capabilities update from the GNSS HAL implementation */
onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported)97     public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) {
98         setSupported(isGnssNavigationMessageSupported);
99         updateResult();
100     }
101 
onGpsEnabledChanged()102     public void onGpsEnabledChanged() {
103         tryUpdateRegistrationWithService();
104         updateResult();
105     }
106 
107     @Override
getHandlerOperation(int result)108     protected ListenerOperation<IGnssNavigationMessageListener> getHandlerOperation(int result) {
109         int status;
110         switch (result) {
111             case RESULT_SUCCESS:
112                 status = GnssNavigationMessage.Callback.STATUS_READY;
113                 break;
114             case RESULT_NOT_AVAILABLE:
115             case RESULT_NOT_SUPPORTED:
116             case RESULT_INTERNAL_ERROR:
117                 status = GnssNavigationMessage.Callback.STATUS_NOT_SUPPORTED;
118                 break;
119             case RESULT_GPS_LOCATION_DISABLED:
120                 status = GnssNavigationMessage.Callback.STATUS_LOCATION_DISABLED;
121                 break;
122             case RESULT_UNKNOWN:
123                 return null;
124             default:
125                 Log.v(TAG, "Unhandled addListener result: " + result);
126                 return null;
127         }
128         return new StatusChangedOperation(status);
129     }
130 
131     private static class StatusChangedOperation
132             implements ListenerOperation<IGnssNavigationMessageListener> {
133         private final int mStatus;
134 
StatusChangedOperation(int status)135         public StatusChangedOperation(int status) {
136             mStatus = status;
137         }
138 
139         @Override
execute(IGnssNavigationMessageListener listener, CallerIdentity callerIdentity)140         public void execute(IGnssNavigationMessageListener listener,
141                 CallerIdentity callerIdentity) throws RemoteException {
142             listener.onStatusChanged(mStatus);
143         }
144     }
145 
146     @VisibleForTesting
147     public static class GnssNavigationMessageProviderNative {
isNavigationMessageSupported()148         public boolean isNavigationMessageSupported() {
149             return native_is_navigation_message_supported();
150         }
151 
startNavigationMessageCollection()152         public boolean startNavigationMessageCollection() {
153             return native_start_navigation_message_collection();
154         }
155 
stopNavigationMessageCollection()156         public boolean stopNavigationMessageCollection() {
157             return native_stop_navigation_message_collection();
158         }
159     }
160 
native_is_navigation_message_supported()161     private static native boolean native_is_navigation_message_supported();
162 
native_start_navigation_message_collection()163     private static native boolean native_start_navigation_message_collection();
164 
native_stop_navigation_message_collection()165     private static native boolean native_stop_navigation_message_collection();
166 }
167