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