create a new notification channel for high prio sim alert

create a high priority notification channel for sim releated alert
in some scenario, we want users to know that they cannot completely
rely on their ability to make a phone call and data call with the
SIM and this may apply to emergency situations.

Bug: 134790138
Test: Manual test
Change-Id: Ia3c6d568d424bf501d77336e3dcb940f4c8179a4
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 942c1e2..3b9f996 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.READ_PHONE_STATE;
 
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -62,6 +63,7 @@
 import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.phone.settings.VoicemailSettingsActivity;
 
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -92,6 +94,7 @@
     static final int CALL_FORWARD_NOTIFICATION = 4;
     static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
     static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
+    static final int LIMITED_SIM_FUNCTION_NOTIFICATION = 7;
 
     // Event for network selection notification.
     private static final int EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION = 1;
@@ -101,6 +104,8 @@
 
     private static final int STATE_UNKNOWN_SERVICE = -1;
 
+    private static final String ACTION_MOBILE_NETWORK_LIST = "android.settings.MOBILE_NETWORK_LIST";
+
     /** The singleton NotificationMgr instance. */
     private static NotificationMgr sInstance;
 
@@ -118,6 +123,9 @@
     // used to track the notification of selected network unavailable, per subscription id.
     private SparseArray<Boolean> mSelectedUnavailableNotify = new SparseArray<>();
 
+    // used to track the notification of limited sim function under dual sim, per subscription id.
+    private Set<Integer> mLimitedSimFunctionNotify = new HashSet<>();
+
     // used to track whether the message waiting indicator is visible, per subscription id.
     private ArrayMap<Integer, Boolean> mMwiVisible = new ArrayMap<Integer, Boolean>();
 
@@ -597,6 +605,88 @@
     }
 
     /**
+     * Shows the "Limited SIM functionality" warning notification, which appears when using a
+     * special carrier under dual sim. limited function applies for DSDS in general when two SIM
+     * cards share a single radio, thus the voice & data maybe impaired under certain scenarios.
+     */
+    public void showLimitedSimFunctionWarningNotification(int subId, @Nullable String carrierName) {
+        if (DBG) log("showLimitedSimFunctionWarningNotification carrier: " + carrierName
+                + " subId: " + subId);
+        if (mLimitedSimFunctionNotify.contains(subId)) {
+            // handle the case that user swipe the notification but condition triggers
+            // frequently which cause the same notification consistently displayed.
+            if (DBG) log("showLimitedSimFunctionWarningNotification, "
+                    + "not display again if already displayed");
+            return;
+        }
+        // Navigate to "Network Selection Settings" which list all subscriptions.
+        PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0,
+                new Intent(ACTION_MOBILE_NETWORK_LIST), 0);
+        String line1Num = mTelephonyManager.getLine1Number(subId);
+
+        final CharSequence contentText = TextUtils.isEmpty(line1Num) ?
+            String.format(mContext.getText(
+                R.string.limited_sim_function_notification_message).toString(),
+                carrierName, line1Num) :
+            String.format(mContext.getText(
+                R.string.limited_sim_function_with_phone_num_notification_message).toString(),
+                carrierName);
+        final Notification.Builder builder = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.ic_sim_card)
+                .setContentTitle(mContext.getText(
+                        R.string.limited_sim_function_notification_title))
+                .setContentText(contentText)
+                .setOnlyAlertOnce(true)
+                .setOngoing(true)
+                .setChannel(NotificationChannelController.CHANNEL_ID_SIM_HIGH_PRIORITY)
+                .setContentIntent(contentIntent);
+        final Notification notification = new Notification.BigTextStyle(builder).bigText(
+                contentText).build();
+
+        mNotificationManager.notifyAsUser(Integer.toString(subId),
+                LIMITED_SIM_FUNCTION_NOTIFICATION,
+                notification, UserHandle.ALL);
+        mLimitedSimFunctionNotify.add(subId);
+    }
+
+    /**
+     * Dismiss the "Limited SIM functionality" warning notification for the given subId.
+     */
+    public void dismissLimitedSimFunctionWarningNotification(int subId) {
+        if (DBG) log("dismissLimitedSimFunctionWarningNotification subId: " + subId);
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            // dismiss all notifications
+            for (int id : mLimitedSimFunctionNotify) {
+                mNotificationManager.cancelAsUser(Integer.toString(id),
+                        LIMITED_SIM_FUNCTION_NOTIFICATION, UserHandle.ALL);
+            }
+            mLimitedSimFunctionNotify.clear();
+        } else if (mLimitedSimFunctionNotify.contains(subId)) {
+            mNotificationManager.cancelAsUser(Integer.toString(subId),
+                    LIMITED_SIM_FUNCTION_NOTIFICATION, UserHandle.ALL);
+            mLimitedSimFunctionNotify.remove(subId);
+        }
+    }
+
+    /**
+     * Dismiss the "Limited SIM functionality" warning notification for all inactive subscriptions.
+     */
+    public void dismissLimitedSimFunctionWarningNotificationForInactiveSubs() {
+        if (DBG) log("dismissLimitedSimFunctionWarningNotificationForInactiveSubs");
+        // dismiss notification for inactive subscriptions.
+        // handle the corner case that SIM change by SIM refresh doesn't clear the notification
+        // from the old SIM if both old & new SIM configured to display the notification.
+        mLimitedSimFunctionNotify.removeIf(id -> {
+            if (!mSubscriptionManager.isActiveSubId(id)) {
+                mNotificationManager.cancelAsUser(Integer.toString(id),
+                        LIMITED_SIM_FUNCTION_NOTIFICATION, UserHandle.ALL);
+                return true;
+            }
+            return false;
+        });
+    }
+
+    /**
      * Display the network selection "no service" notification
      * @param operator is the numeric operator number
      * @param subId is the subscription ID