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.GnssMeasurementsEvent;
21 import android.location.GnssRequest;
22 import android.location.IGnssMeasurementsListener;
23 import android.os.Handler;
24 import android.os.RemoteException;
25 import android.provider.Settings;
26 import android.util.Log;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.server.location.CallerIdentity;
30 import com.android.server.location.RemoteListenerHelper;
31 
32 /**
33  * An base implementation for GPS measurements provider. It abstracts out the responsibility of
34  * handling listeners, while still allowing technology specific implementations to be built.
35  *
36  * @hide
37  */
38 public abstract class GnssMeasurementsProvider
39         extends RemoteListenerHelper<GnssRequest, IGnssMeasurementsListener> {
40     private static final String TAG = "GnssMeasProvider";
41     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
42 
43     private final GnssMeasurementProviderNative mNative;
44 
45     private boolean mStartedCollection;
46     private boolean mStartedFullTracking;
47 
GnssMeasurementsProvider(Context context, Handler handler)48     protected GnssMeasurementsProvider(Context context, Handler handler) {
49         this(context, handler, new GnssMeasurementProviderNative());
50     }
51 
52     @VisibleForTesting
GnssMeasurementsProvider( Context context, Handler handler, GnssMeasurementProviderNative aNative)53     public GnssMeasurementsProvider(
54             Context context, Handler handler, GnssMeasurementProviderNative aNative) {
55         super(context, handler, TAG);
56         mNative = aNative;
57     }
58 
resumeIfStarted()59     void resumeIfStarted() {
60         if (DEBUG) {
61             Log.d(TAG, "resumeIfStarted");
62         }
63         if (mStartedCollection) {
64             mNative.startMeasurementCollection(mStartedFullTracking);
65         }
66     }
67 
68     @Override
isAvailableInPlatform()69     public boolean isAvailableInPlatform() {
70         return mNative.isMeasurementSupported();
71     }
72 
getMergedFullTracking()73     private boolean getMergedFullTracking() {
74         int devOptions = Settings.Secure.getInt(mContext.getContentResolver(),
75                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
76         int enableFullTracking = Settings.Global.getInt(mContext.getContentResolver(),
77                 Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, 0);
78         boolean enableFullTrackingBySetting = (devOptions == 1 /* Developer Mode enabled */)
79                 && (enableFullTracking == 1 /* Raw Measurements Full Tracking enabled */);
80         if (enableFullTrackingBySetting) {
81             return true;
82         }
83 
84         synchronized (mListenerMap) {
85             for (IdentifiedListener identifiedListener : mListenerMap.values()) {
86                 GnssRequest request = identifiedListener.getRequest();
87                 if (request != null && request.isFullTracking()) {
88                     return true;
89                 }
90             }
91         }
92         return false;
93     }
94 
95     @Override
registerWithService()96     protected int registerWithService() {
97         boolean enableFullTracking = getMergedFullTracking();
98         boolean result = mNative.startMeasurementCollection(enableFullTracking);
99         if (result) {
100             mStartedCollection = true;
101             mStartedFullTracking = enableFullTracking;
102             return RemoteListenerHelper.RESULT_SUCCESS;
103         } else {
104             return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
105         }
106     }
107 
108     @Override
unregisterFromService()109     protected void unregisterFromService() {
110         boolean stopped = mNative.stopMeasurementCollection();
111         if (stopped) {
112             mStartedCollection = false;
113         }
114     }
115 
onMeasurementsAvailable(final GnssMeasurementsEvent event)116     public void onMeasurementsAvailable(final GnssMeasurementsEvent event) {
117         foreach((IGnssMeasurementsListener listener, CallerIdentity callerIdentity) -> {
118             if (!hasPermission(mContext, callerIdentity)) {
119                 logPermissionDisabledEventNotReported(
120                         TAG, callerIdentity.packageName, "GNSS measurements");
121                 return;
122             }
123             listener.onGnssMeasurementsReceived(event);
124         });
125     }
126 
127     /** Handle GNSS capabilities update from the GNSS HAL implementation. */
onCapabilitiesUpdated(boolean isGnssMeasurementsSupported)128     public void onCapabilitiesUpdated(boolean isGnssMeasurementsSupported) {
129         setSupported(isGnssMeasurementsSupported);
130         updateResult();
131     }
132 
onGpsEnabledChanged()133     public void onGpsEnabledChanged() {
134         tryUpdateRegistrationWithService();
135         updateResult();
136     }
137 
138     @Override
getHandlerOperation(int result)139     protected ListenerOperation<IGnssMeasurementsListener> getHandlerOperation(int result) {
140         int status;
141         switch (result) {
142             case RESULT_SUCCESS:
143                 status = GnssMeasurementsEvent.Callback.STATUS_READY;
144                 break;
145             case RESULT_NOT_AVAILABLE:
146             case RESULT_NOT_SUPPORTED:
147             case RESULT_INTERNAL_ERROR:
148                 status = GnssMeasurementsEvent.Callback.STATUS_NOT_SUPPORTED;
149                 break;
150             case RESULT_NOT_ALLOWED:
151                 status = GnssMeasurementsEvent.Callback.STATUS_NOT_ALLOWED;
152                 break;
153             case RESULT_GPS_LOCATION_DISABLED:
154                 status = GnssMeasurementsEvent.Callback.STATUS_LOCATION_DISABLED;
155                 break;
156             case RESULT_UNKNOWN:
157                 return null;
158             default:
159                 Log.v(TAG, "Unhandled addListener result: " + result);
160                 return null;
161         }
162         return new StatusChangedOperation(status);
163     }
164 
165     private static class StatusChangedOperation
166             implements ListenerOperation<IGnssMeasurementsListener> {
167         private final int mStatus;
168 
StatusChangedOperation(int status)169         public StatusChangedOperation(int status) {
170             mStatus = status;
171         }
172 
173         @Override
execute(IGnssMeasurementsListener listener, CallerIdentity callerIdentity)174         public void execute(IGnssMeasurementsListener listener,
175                 CallerIdentity callerIdentity) throws RemoteException {
176             listener.onStatusChanged(mStatus);
177         }
178     }
179 
180     @VisibleForTesting
181     public static class GnssMeasurementProviderNative {
isMeasurementSupported()182         public boolean isMeasurementSupported() {
183             return native_is_measurement_supported();
184         }
185 
startMeasurementCollection(boolean enableFullTracking)186         public boolean startMeasurementCollection(boolean enableFullTracking) {
187             return native_start_measurement_collection(enableFullTracking);
188         }
189 
stopMeasurementCollection()190         public boolean stopMeasurementCollection() {
191             return native_stop_measurement_collection();
192         }
193     }
194 
native_is_measurement_supported()195     private static native boolean native_is_measurement_supported();
196 
native_start_measurement_collection(boolean enableFullTracking)197     private static native boolean native_start_measurement_collection(boolean enableFullTracking);
198 
native_stop_measurement_collection()199     private static native boolean native_stop_measurement_collection();
200 }
201