diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index b4be21987cf72..04e7bab0542bd 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -357,8 +357,10 @@ public class GpsNetInitiatedHandler { } } - // Sets the NI notification. - private synchronized void setNiNotification(GpsNiNotification notif) { + /** + * Posts a notification in the status bar using the contents in {@code notif} object. + */ + public synchronized void setNiNotification(GpsNiNotification notif) { NotificationManager notificationManager = (NotificationManager) mContext .getSystemService(Context.NOTIFICATION_SERVICE); if (notificationManager == null) { @@ -539,14 +541,14 @@ public class GpsNetInitiatedHandler { */ static private String decodeString(String original, boolean isHex, int coding) { + if (coding == GPS_ENC_NONE) { + return original; + } + String decoded = original; byte[] input = stringToByteArray(original, isHex); switch (coding) { - case GPS_ENC_NONE: - decoded = original; - break; - case GPS_ENC_SUPL_GSM_DEFAULT: decoded = decodeGSMPackedString(input); break; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 44228eec8e945..52c14251de85a 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -2055,7 +2055,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements setupNativeGnssService(); if (native_is_gnss_visibility_control_supported()) { - mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper); + mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper, mNIHandler); } // load default GPS configuration diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java index c3626d2373ea9..8601386755296 100644 --- a/services/core/java/com/android/server/location/GnssVisibilityControl.java +++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java @@ -33,6 +33,9 @@ import android.util.ArrayMap; import android.util.Log; import android.util.StatsLog; +import com.android.internal.R; +import com.android.internal.location.GpsNetInitiatedHandler; + import java.util.Arrays; import java.util.List; import java.util.Map; @@ -65,6 +68,7 @@ class GnssVisibilityControl { private final Handler mHandler; private final Context mContext; + private final GpsNetInitiatedHandler mNiHandler; private boolean mIsGpsEnabled; @@ -76,11 +80,12 @@ class GnssVisibilityControl { private PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener = uid -> runOnHandler(() -> handlePermissionsChanged(uid)); - GnssVisibilityControl(Context context, Looper looper) { + GnssVisibilityControl(Context context, Looper looper, GpsNetInitiatedHandler niHandler) { mContext = context; PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); mHandler = new Handler(looper); + mNiHandler = niHandler; mAppOps = mContext.getSystemService(AppOpsManager.class); mPackageManager = mContext.getPackageManager(); @@ -250,6 +255,9 @@ class GnssVisibilityControl { private static final byte NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED = 1; private static final byte NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED = 2; + // This must match with NfwProtocolStack enum in IGnssVisibilityControlCallback.hal. + private static final byte NFW_PROTOCOL_STACK_SUPL = 1; + private final String mProxyAppPackageName; private final byte mProtocolStack; private final String mOtherProtocolStackName; @@ -299,6 +307,10 @@ class GnssVisibilityControl { return mResponseType != NfwNotification.NFW_RESPONSE_TYPE_REJECTED; } + private boolean isLocationProvided() { + return mResponseType == NfwNotification.NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED; + } + private boolean isRequestAttributedToProxyApp() { return !TextUtils.isEmpty(mProxyAppPackageName); } @@ -306,6 +318,10 @@ class GnssVisibilityControl { private boolean isEmergencyRequestNotification() { return mInEmergencyMode && !isRequestAttributedToProxyApp(); } + + private boolean isRequestTypeSupl() { + return mProtocolStack == NFW_PROTOCOL_STACK_SUPL; + } } private void handlePermissionsChanged(int uid) { @@ -430,16 +446,15 @@ class GnssVisibilityControl { return; } - Log.e(TAG, "ProxyAppPackageName field is not set. AppOps service not notified " - + "for non-framework location access notification: " + nfwNotification); + Log.e(TAG, "ProxyAppPackageName field is not set. AppOps service not notified" + + " for notification: " + nfwNotification); return; } if (isLocationPermissionEnabled == null) { - Log.w(TAG, "Could not find proxy app with name: " + proxyAppPkgName + " in the " - + "value specified for config parameter: " - + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". AppOps service not notified " - + "for non-framework location access notification: " + nfwNotification); + Log.w(TAG, "Could not find proxy app " + proxyAppPkgName + " in the value specified for" + + " config parameter: " + GnssConfiguration.CONFIG_NFW_PROXY_APPS + + ". AppOps service not notified for notification: " + nfwNotification); return; } @@ -447,8 +462,7 @@ class GnssVisibilityControl { final ApplicationInfo proxyAppInfo = getProxyAppInfo(proxyAppPkgName); if (proxyAppInfo == null) { Log.e(TAG, "Proxy app " + proxyAppPkgName + " is not found. AppOps service not " - + "notified for non-framework location access notification: " - + nfwNotification); + + "notified for notification: " + nfwNotification); return; } @@ -465,13 +479,40 @@ class GnssVisibilityControl { } private void handleEmergencyNfwNotification(NfwNotification nfwNotification) { - boolean isPermissionMismatched = - (nfwNotification.mResponseType == NfwNotification.NFW_RESPONSE_TYPE_REJECTED); - if (isPermissionMismatched) { + boolean isPermissionMismatched = false; + if (!nfwNotification.isRequestAccepted()) { Log.e(TAG, "Emergency non-framework location request incorrectly rejected." + " Notification: " + nfwNotification); + isPermissionMismatched = true; } + + if (!mNiHandler.getInEmergency()) { + Log.w(TAG, "Emergency state mismatch. Device currently not in user initiated emergency" + + " session. Notification: " + nfwNotification); + isPermissionMismatched = true; + } + logEvent(nfwNotification, isPermissionMismatched); + + if (nfwNotification.isLocationProvided()) { + // Emulate deprecated IGnssNi.hal user notification of emergency NI requests. + GpsNetInitiatedHandler.GpsNiNotification notification = + new GpsNetInitiatedHandler.GpsNiNotification(); + notification.notificationId = 0; + notification.niType = nfwNotification.isRequestTypeSupl() + ? GpsNetInitiatedHandler.GPS_NI_TYPE_EMERGENCY_SUPL + : GpsNetInitiatedHandler.GPS_NI_TYPE_UMTS_CTRL_PLANE; + notification.needNotify = true; + notification.needVerify = false; + notification.privacyOverride = false; + notification.timeout = 0; + notification.defaultResponse = GpsNetInitiatedHandler.GPS_NI_RESPONSE_NORESP; + notification.requestorId = nfwNotification.mRequestorId; + notification.requestorIdEncoding = GpsNetInitiatedHandler.GPS_ENC_NONE; + notification.text = mContext.getString(R.string.global_action_emergency); + notification.textEncoding = GpsNetInitiatedHandler.GPS_ENC_NONE; + mNiHandler.setNiNotification(notification); + } } private void logEvent(NfwNotification notification, boolean isPermissionMismatched) {