/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.server.location; import android.content.Context; import android.location.GnssMeasurementsEvent; import android.location.IGnssMeasurementsListener; import android.os.Handler; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; /** * An base implementation for GPS measurements provider. * It abstracts out the responsibility of handling listeners, while still allowing technology * specific implementations to be built. * * @hide */ public abstract class GnssMeasurementsProvider extends RemoteListenerHelper { private static final String TAG = "GnssMeasurementsProvider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Context mContext; private final GnssMeasurementProviderNative mNative; private boolean mIsCollectionStarted; private boolean mEnableFullTracking; protected GnssMeasurementsProvider(Context context, Handler handler) { this(context, handler, new GnssMeasurementProviderNative()); } @VisibleForTesting GnssMeasurementsProvider(Context context, Handler handler, GnssMeasurementProviderNative aNative) { super(handler, TAG); mContext = context; mNative = aNative; } // TODO(b/37460011): Use this with death recovery logic. void resumeIfStarted() { if (DEBUG) { Log.d(TAG, "resumeIfStarted"); } if (mIsCollectionStarted) { mNative.startMeasurementCollection(mEnableFullTracking); } } @Override public boolean isAvailableInPlatform() { return mNative.isMeasurementSupported(); } @Override protected int registerWithService() { int devOptions = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0); int fullTrackingToggled = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, 0); boolean enableFullTracking = (devOptions == 1 /* Developer Mode enabled */) && (fullTrackingToggled == 1 /* Raw Measurements Full Tracking enabled */); boolean result = mNative.startMeasurementCollection(enableFullTracking); if (result) { mIsCollectionStarted = true; mEnableFullTracking = enableFullTracking; return RemoteListenerHelper.RESULT_SUCCESS; } else { return RemoteListenerHelper.RESULT_INTERNAL_ERROR; } } @Override protected void unregisterFromService() { boolean stopped = mNative.stopMeasurementCollection(); if (stopped) { mIsCollectionStarted = false; } } public void onMeasurementsAvailable(final GnssMeasurementsEvent event) { ListenerOperation operation = listener -> listener.onGnssMeasurementsReceived(event); foreach(operation); } public void onCapabilitiesUpdated(boolean isGnssMeasurementsSupported) { setSupported(isGnssMeasurementsSupported); updateResult(); } public void onGpsEnabledChanged() { tryUpdateRegistrationWithService(); updateResult(); } @Override protected ListenerOperation getHandlerOperation(int result) { int status; switch (result) { case RESULT_SUCCESS: status = GnssMeasurementsEvent.Callback.STATUS_READY; break; case RESULT_NOT_AVAILABLE: case RESULT_NOT_SUPPORTED: case RESULT_INTERNAL_ERROR: status = GnssMeasurementsEvent.Callback.STATUS_NOT_SUPPORTED; break; case RESULT_NOT_ALLOWED: status = GnssMeasurementsEvent.Callback.STATUS_NOT_ALLOWED; break; case RESULT_GPS_LOCATION_DISABLED: status = GnssMeasurementsEvent.Callback.STATUS_LOCATION_DISABLED; break; case RESULT_UNKNOWN: return null; default: Log.v(TAG, "Unhandled addListener result: " + result); return null; } return new StatusChangedOperation(status); } private static class StatusChangedOperation implements ListenerOperation { private final int mStatus; public StatusChangedOperation(int status) { mStatus = status; } @Override public void execute(IGnssMeasurementsListener listener) throws RemoteException { listener.onStatusChanged(mStatus); } } @VisibleForTesting static class GnssMeasurementProviderNative { public boolean isMeasurementSupported() { return native_is_measurement_supported(); } public boolean startMeasurementCollection(boolean enableFullTracking) { return native_start_measurement_collection(enableFullTracking); } public boolean stopMeasurementCollection() { return native_stop_measurement_collection(); } } private static native boolean native_is_measurement_supported(); private static native boolean native_start_measurement_collection(boolean enableFullTracking); private static native boolean native_stop_measurement_collection(); }