Update non-framework emergency location request notification

- Incorporate notification text feedback in b/116328114 so that
  it translates well in different locales.
- Implement PWG recommendation to always notify user of non-framework
  location requests and not make it configurable. Remove es_notify_int
  configuration parameter.

Bug: 116328114
Bug: 130892418
Test: Manual plus existing tests pass.
Change-Id: Iad972eb1a6fe6c6ed5646edb00c1ea483a077553
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 04e7bab..e890514 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -360,7 +360,7 @@
     /**
      * Posts a notification in the status bar using the contents in {@code notif} object.
      */
-    public synchronized void setNiNotification(GpsNiNotification notif) {
+    private synchronized void setNiNotification(GpsNiNotification notif) {
         NotificationManager notificationManager = (NotificationManager) mContext
                 .getSystemService(Context.NOTIFICATION_SERVICE);
         if (notificationManager == null) {
@@ -541,35 +541,26 @@
      */
     static private String decodeString(String original, boolean isHex, int coding)
     {
-        if (coding == GPS_ENC_NONE) {
+        if (coding == GPS_ENC_NONE || coding == GPS_ENC_UNKNOWN) {
             return original;
         }
 
-        String decoded = original;
         byte[] input = stringToByteArray(original, isHex);
 
         switch (coding) {
-        case GPS_ENC_SUPL_GSM_DEFAULT:
-            decoded = decodeGSMPackedString(input);
-            break;
+            case GPS_ENC_SUPL_GSM_DEFAULT:
+                return decodeGSMPackedString(input);
 
-        case GPS_ENC_SUPL_UTF8:
-            decoded = decodeUTF8String(input);
-            break;
+            case GPS_ENC_SUPL_UTF8:
+                return decodeUTF8String(input);
 
-        case GPS_ENC_SUPL_UCS2:
-            decoded = decodeUCS2String(input);
-            break;
+            case GPS_ENC_SUPL_UCS2:
+                return decodeUCS2String(input);
 
-        case GPS_ENC_UNKNOWN:
-            decoded = original;
-            break;
-
-        default:
-            Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
-            break;
+            default:
+                Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
+                return original;
         }
-        return decoded;
     }
 
     // change this to configure notification display
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index aa51aec..86a84e3 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -70,7 +70,6 @@
     private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
     private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
     public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
-    public static final String CONFIG_ES_NOTIFY_INT = "ES_NOTIFY_INT";
 
     // Limit on NI emergency mode time extension after emergency sessions ends
     private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
@@ -200,14 +199,6 @@
     }
 
     /**
-     * Returns the value of config parameter ES_NOTIFY_INT or {@code defaulEsNotify} if no
-     * value is provided or if there is an error parsing the configured value.
-     */
-    int getEsNotify(int defaulEsNotify) {
-        return getIntConfig(CONFIG_ES_NOTIFY_INT, defaulEsNotify);
-    }
-
-    /**
      * Updates the GNSS HAL satellite blacklist.
      */
     void setSatelliteBlacklist(int[] constellations, int[] svids) {
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index c49d900..b7e0a0f 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -18,6 +18,9 @@
 
 import android.annotation.SuppressLint;
 import android.app.AppOpsManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -35,6 +38,7 @@
 
 import com.android.internal.R;
 import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.notification.SystemNotificationChannels;
 
 import java.util.Arrays;
 import java.util.List;
@@ -58,11 +62,6 @@
     // Max wait time for synchronous method onGpsEnabledChanged() to run.
     private static final long ON_GPS_ENABLED_CHANGED_TIMEOUT_MILLIS = 3 * 1000;
 
-    // Valid values for config parameter es_notify_int for posting notification in the status
-    // bar for non-framework location requests in user-initiated emergency use cases.
-    private static final int ES_NOTIFY_NONE = 0;
-    private static final int ES_NOTIFY_ALL = 1;
-
     // Wakelocks
     private static final String WAKELOCK_KEY = TAG;
     private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
@@ -74,9 +73,9 @@
     private final Handler mHandler;
     private final Context mContext;
     private final GpsNetInitiatedHandler mNiHandler;
+    private final Notification mEmergencyLocationUserNotification;
 
     private boolean mIsGpsEnabled;
-    private boolean mEsNotify;
 
     // Number of non-framework location access proxy apps is expected to be small (< 5).
     private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
@@ -94,6 +93,7 @@
         mNiHandler = niHandler;
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mPackageManager = mContext.getPackageManager();
+        mEmergencyLocationUserNotification = createEmergencyLocationUserNotification(mContext);
 
         // Complete initialization as the first event to run in mHandler thread. After that,
         // all object state read/update events run in the mHandler thread.
@@ -135,22 +135,7 @@
     void onConfigurationUpdated(GnssConfiguration configuration) {
         // The configuration object must be accessed only in the caller thread and not in mHandler.
         List<String> nfwLocationAccessProxyApps = configuration.getProxyApps();
-        int esNotify = configuration.getEsNotify(ES_NOTIFY_NONE);
-        runOnHandler(() -> {
-            setEsNotify(esNotify);
-            handleUpdateProxyApps(nfwLocationAccessProxyApps);
-        });
-    }
-
-    private void setEsNotify(int esNotify) {
-        if (esNotify != ES_NOTIFY_NONE && esNotify != ES_NOTIFY_ALL) {
-            Log.e(TAG, "Config parameter " + GnssConfiguration.CONFIG_ES_NOTIFY_INT
-                    + " is set to invalid value: " + esNotify
-                    + ". Using default value: " + ES_NOTIFY_NONE);
-            esNotify = ES_NOTIFY_NONE;
-        }
-
-        mEsNotify = (esNotify == ES_NOTIFY_ALL);
+        runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
     }
 
     private void handleInitialize() {
@@ -278,9 +263,6 @@
         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;
@@ -341,10 +323,6 @@
         private boolean isEmergencyRequestNotification() {
             return mInEmergencyMode && !isRequestAttributedToProxyApp();
         }
-
-        private boolean isRequestTypeSupl() {
-            return mProtocolStack == NFW_PROTOCOL_STACK_SUPL;
-        }
     }
 
     private void handlePermissionsChanged(int uid) {
@@ -517,27 +495,44 @@
 
         logEvent(nfwNotification, isPermissionMismatched);
 
-        if (mEsNotify && 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);
+        if (nfwNotification.isLocationProvided()) {
+            postEmergencyLocationUserNotification(nfwNotification);
         }
     }
 
+    private void postEmergencyLocationUserNotification(NfwNotification nfwNotification) {
+        // Emulate deprecated IGnssNi.hal user notification of emergency NI requests.
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+        if (notificationManager == null) {
+            Log.w(TAG, "Could not notify user of emergency location request. Notification: "
+                    + nfwNotification);
+            return;
+        }
+
+        notificationManager.notifyAsUser(/* tag= */ null, /* notificationId= */ 0,
+                mEmergencyLocationUserNotification, UserHandle.ALL);
+    }
+
+    private static Notification createEmergencyLocationUserNotification(Context context) {
+        String firstLineText = context.getString(R.string.gpsNotifTitle);
+        String secondLineText =  context.getString(R.string.global_action_emergency);
+        String accessibilityServicesText = firstLineText + " (" + secondLineText + ")";
+        return new Notification.Builder(context, SystemNotificationChannels.NETWORK_ALERTS)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
+                .setWhen(0)
+                .setOngoing(true)
+                .setAutoCancel(true)
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setDefaults(0)
+                .setTicker(accessibilityServicesText)
+                .setContentTitle(firstLineText)
+                .setContentText(secondLineText)
+                .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(), 0))
+                .build();
+    }
+
     private void logEvent(NfwNotification notification, boolean isPermissionMismatched) {
         StatsLog.write(StatsLog.GNSS_NFW_NOTIFICATION_REPORTED,
                 notification.mProxyAppPackageName,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6ba359b..5175c1d 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2794,14 +2794,6 @@
          */
         public static final String KEY_NFW_PROXY_APPS_STRING = KEY_PREFIX + "nfw_proxy_apps";
 
-        /**
-         * Specify whether to post a notification on the status bar whenever device location is
-         * provided for non-framework location requests in user-initiated emergency use cases.
-         * 0 - Do not post notification. This is default.
-         * 1 - Post notification for all request types.
-         */
-        public static final String KEY_ES_NOTIFY_INT = KEY_PREFIX + "es_notify_int";
-
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
@@ -2816,7 +2808,6 @@
             defaults.putString(KEY_GPS_LOCK_STRING, "3");
             defaults.putString(KEY_ES_EXTENSION_SEC_STRING, "0");
             defaults.putString(KEY_NFW_PROXY_APPS_STRING, "");
-            defaults.putInt(KEY_ES_NOTIFY_INT, 0);
             return defaults;
         }
     }