cold sim clean up

- add a new field: provisioningNotificationEnabled from NetworkMisc. set
  to false if we want to hide "sign in" notification and placed
  carrier-specific notification instead. it is set on connect, once set,
  it is carrier-app's responsibility to post new UI to users
- rework on the interaction between carrier app and framework
- code cleanup
- unit test support

Bug: 28567303
Change-Id: Ic84db7ffbb920d15344717f104496d3cb82e1a85
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 5511a24..69f50a2 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -52,6 +52,15 @@
     public boolean acceptUnvalidated;
 
     /**
+     * Set to avoid surfacing the "Sign in to network" notification.
+     * if carrier receivers/apps are registered to handle the carrier-specific provisioning
+     * procedure, a carrier specific provisioning notification will be placed.
+     * only one notification should be displayed. This field is set based on
+     * which notification should be used for provisioning.
+     */
+    public boolean provisioningNotificationDisabled;
+
+    /**
      * For mobile networks, this is the subscriber ID (such as IMSI).
      */
     public String subscriberId;
@@ -65,6 +74,7 @@
             explicitlySelected = nm.explicitlySelected;
             acceptUnvalidated = nm.acceptUnvalidated;
             subscriberId = nm.subscriberId;
+            provisioningNotificationDisabled = nm.provisioningNotificationDisabled;
         }
     }
 
@@ -79,6 +89,7 @@
         out.writeInt(explicitlySelected ? 1 : 0);
         out.writeInt(acceptUnvalidated ? 1 : 0);
         out.writeString(subscriberId);
+        out.writeInt(provisioningNotificationDisabled ? 1 : 0);
     }
 
     public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@@ -89,6 +100,7 @@
             networkMisc.explicitlySelected = in.readInt() != 0;
             networkMisc.acceptUnvalidated = in.readInt() != 0;
             networkMisc.subscriberId = in.readString();
+            networkMisc.provisioningNotificationDisabled = in.readInt() != 0;
             return networkMisc;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index a633241..b27bfcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -810,7 +810,7 @@
 
     private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
         SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
-                null, 0, 0, "", SubscriptionManager.SIM_PROVISIONED);
+                null, 0, 0, "");
         mMobileSignalControllers.put(id, new MobileSignalController(mContext,
                 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
                 mSubDefaults, mReceiverHandler.getLooper()));
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5118b3f..50c1ca0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2150,9 +2150,11 @@
                             loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
                             break;
                         }
-                        setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
-                                nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
-                                (PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
+                        if (!nai.networkMisc.provisioningNotificationDisabled) {
+                            setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
+                                    nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
+                                    (PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
+                        }
                     }
                     break;
                 }
@@ -2553,6 +2555,7 @@
 
         PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+
         setProvNotificationVisibleIntent(true, nai.network.netId, NotificationType.NO_INTERNET,
                 nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(), pendingIntent, true);
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index f4e1424..ddaebfa 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -66,7 +66,6 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.WakeupMessage;
-import com.android.server.connectivity.NetworkAgentInfo;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
@@ -618,7 +617,7 @@
 
         @Override
         public void exit() {
-             removeMessages(CMD_CAPTIVE_PORTAL_RECHECK);
+            removeMessages(CMD_CAPTIVE_PORTAL_RECHECK);
         }
     }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 22e2882..0d1067c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -662,18 +662,37 @@
     public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
 
     /**
-     * If carriers require differentiate un-provisioned status: cold sim or out of credit sim
-     * a package name and activity name can be provided to launch a supported carrier application
-     * that check the sim provisioning status
-     * The first element is the package name and the second element is the activity name
-     * of the provisioning app
-     * example:
-     * <item>com.google.android.carrierPackageName</item>
-     * <item>com.google.android.carrierPackageName.CarrierActivityName</item>
+     * A list of component name of carrier signalling receivers which are interested in intent
+     * android.intent.action.CARRIER_SIGNAL_REDIRECTED.
+     * Example:
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
      * @hide
      */
-     public static final String KEY_SIM_PROVISIONING_STATUS_DETECTION_CARRIER_APP_STRING_ARRAY =
-            "sim_state_detection_carrier_app_string_array";
+    public static final String KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY =
+            "signal_redirection_receiver_string_array";
+
+    /**
+     * A list of component name of carrier signalling receivers which are interested in intent
+     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED.
+     * Example:
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
+     * @hide
+     */
+    public static final String KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY =
+            "signal_dcfailure_receiver_string_array";
+
+    /**
+     * A list of component name of carrier signalling receivers which are interested in intent
+     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE.
+     * Example:
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
+     * @hide
+     */
+    public static final String KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY =
+            "signal_pco_receiver_string_array";
 
     /**
      * Determines whether the carrier supports making non-emergency phone calls while the phone is
@@ -849,9 +868,10 @@
         sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
         sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
 
-        // Used for Sim card State detection app
-        sDefaults.putStringArray(KEY_SIM_PROVISIONING_STATUS_DETECTION_CARRIER_APP_STRING_ARRAY,
-                null);
+        // Carrier Signalling Receivers
+        sDefaults.putStringArray(KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY, null);
     }
 
     /**
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index b5cf212..6229ed9 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -90,14 +90,6 @@
     private int mDataRoaming;
 
     /**
-     * Sim Provisioning Status:
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     */
-    private int mSimProvisioningStatus;
-
-    /**
      * SIM Icon bitmap
      */
     private Bitmap mIconBitmap;
@@ -122,7 +114,7 @@
      */
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
-            Bitmap icon, int mcc, int mnc, String countryIso, int simProvisioningStatus) {
+            Bitmap icon, int mcc, int mnc, String countryIso) {
         this.mId = id;
         this.mIccId = iccId;
         this.mSimSlotIndex = simSlotIndex;
@@ -136,7 +128,6 @@
         this.mMcc = mcc;
         this.mMnc = mnc;
         this.mCountryIso = countryIso;
-        this.mSimProvisioningStatus = simProvisioningStatus;
     }
 
     /**
@@ -273,17 +264,6 @@
     }
 
     /**
-     * @return Sim Provisioning Status
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     * @hide
-     */
-    public int getSimProvisioningStatus() {
-        return this.mSimProvisioningStatus;
-    }
-
-    /**
      * @return the MCC.
      */
     public int getMcc() {
@@ -319,12 +299,10 @@
             int mcc = source.readInt();
             int mnc = source.readInt();
             String countryIso = source.readString();
-            int simProvisioningStatus = source.readInt();
             Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
 
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
-                    nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
-                    simProvisioningStatus);
+                    nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso);
         }
 
         @Override
@@ -347,7 +325,6 @@
         dest.writeInt(mMcc);
         dest.writeInt(mMnc);
         dest.writeString(mCountryIso);
-        dest.writeInt(mSimProvisioningStatus);
         mIconBitmap.writeToParcel(dest, flags);
     }
 
@@ -378,6 +355,6 @@
                 + " displayName=" + mDisplayName + " carrierName=" + mCarrierName
                 + " nameSource=" + mNameSource + " iconTint=" + mIconTint
                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
-                + " mnc " + mMnc + " SimProvisioningStatus " + mSimProvisioningStatus +"}";
+                + " mnc " + mMnc + "}";
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index c49966a..dd6f9cb 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -232,25 +232,12 @@
     /** Indicates that data roaming is disabled for a subscription */
     public static final int DATA_ROAMING_DISABLE = 0;
 
-    /** Sim provisioning status: provisioned */
-    /** @hide */
-    public static final int SIM_PROVISIONED = 0;
-
-    /** Sim provisioning status: un-provisioned due to cold sim */
-    /** @hide */
-    public static final int SIM_UNPROVISIONED_COLD = 1;
-
-    /** Sim provisioning status: un-provisioned due to out of credit */
-    /** @hide */
-    public static final int SIM_UNPROVISIONED_OUT_OF_CREDIT = 2;
-
-    /** Maximum possible sim provisioning status */
-    /** @hide */
-    public static final int MAX_SIM_PROVISIONING_STATUS = SIM_UNPROVISIONED_OUT_OF_CREDIT;
-
     /** @hide */
     public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
 
+    /** @hide */
+    public static final int SIM_PROVISIONED = 0;
+
     /**
      * TelephonyProvider column name for the MCC associated with a SIM.
      * <P>Type: INTEGER (int)</P>
@@ -843,40 +830,6 @@
     }
 
     /**
-     * Set Sim Provisioning Status by subscription ID
-     * @param simProvisioningStatus with the subscription
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     * @param subId the unique SubInfoRecord index in database
-     * @return the number of records updated
-     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
-     * @hide
-     */
-    public int setSimProvisioningStatus(int simProvisioningStatus, int subId) {
-        if (VDBG) {
-            logd("[setSimProvisioningStatus]+ status:" + simProvisioningStatus + " subId:" + subId);
-        }
-        if (simProvisioningStatus < 0 || simProvisioningStatus > MAX_SIM_PROVISIONING_STATUS ||
-                !isValidSubscriptionId(subId)) {
-            logd("[setSimProvisioningStatus]- fail");
-            return -1;
-        }
-
-        int result = 0;
-
-        try {
-            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
-            if (iSub != null) {
-                result = iSub.setSimProvisioningStatus(simProvisioningStatus, subId);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return result;
-    }
-
-    /**
      * Get slotId associated with the subscription.
      * @return slotId as a positive integer or a negative value if an error either
      * SIM_NOT_INSERTED or < 0 if an invalid slot index
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 736539c..e72fe49 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5479,4 +5479,41 @@
         }
         return new ArrayList<CarrierIdentifier>(0);
     }
+
+    /**
+     * Action set from carrier signalling broadcast receivers to enable/disable metered apns
+     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * @param subId the subscription ID that this action applies to.
+     * @param enabled control enable or disable metered apns.
+     * @hide
+     */
+    public void carrierActionSetMeteredApnsEnabled(int subId, boolean enabled) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                service.carrierActionSetMeteredApnsEnabled(subId, enabled);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#carrierActionSetMeteredApnsEnabled", e);
+        }
+    }
+
+    /**
+     * Action set from carrier signalling broadcast receivers to enable/disable radio
+     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * @param subId the subscription ID that this action applies to.
+     * @param enabled control enable or disable radio.
+     * @hide
+     */
+    public void carrierActionSetRadioEnabled(int subId, boolean enabled) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                service.carrierActionSetRadioEnabled(subId, enabled);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#carrierActionSetRadioEnabled", e);
+        }
+    }
 }
+
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index c61ed2a..f6aef08 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -118,17 +118,6 @@
     int setDisplayName(String displayName, int subId);
 
     /**
-     * Set Sim Provisioning Status by subscription ID
-     * @param simProvisionStatus with the subscription:
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     * @param subId the unique SubInfoRecord index in database
-     * @return the number of records updated
-     */
-    int setSimProvisioningStatus(int simProvisioningStatus, int subId);
-
-    /**
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
      * @param subId the unique SubscriptionInfo index in database
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index aa0be49..2171c9e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1132,4 +1132,22 @@
      * means all carriers are allowed.
      */
     List<CarrierIdentifier> getAllowedCarriers(int slotId);
+
+   /**
+    * Action set from carrier signalling broadcast receivers to enable/disable metered apns
+    * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+    * @param subId the subscription ID that this action applies to.
+    * @param enabled control enable or disable metered apns.
+    * @hide
+    */
+    void carrierActionSetMeteredApnsEnabled(int subId, boolean visible);
+
+    /**
+     * Action set from carrier signalling broadcast receivers to enable/disable radio
+     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * @param subId the subscription ID that this action applies to.
+     * @param enabled control enable or disable radio.
+     * @hide
+     */
+    void carrierActionSetRadioEnabled(int subId, boolean enabled);
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 46b0fbd..49a7672 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -402,34 +402,54 @@
     /**
      * <p>Broadcast Action: when data connections get redirected with validation failure.
      * intended for sim/account status checks and only sent to the specified carrier app
-     * feedback is via carrier/system APIs to report cold-sim, out-of-credit-sim, etc
      * The intent will have the following extra values:</p>
      * <ul>
-     *   <li>redirectUrl</li><dd>A string with the redirection url info.</dd>
-     *   <li>subId</li><dd>Sub Id which associated the data redirection.</dd>
+     *   <li>apnType</li><dd>A string with the apn type.</dd>
+     *   <li>redirectionUrl</li><dd>redirection url string</dd>
+     *   <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system.</p>
      */
-    public static final String ACTION_DATA_CONNECTION_REDIRECTED =
-            "android.intent.action.REDIRECTION_DETECTED";
+    public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
+            "android.intent.action.CARRIER_SIGNAL_REDIRECTED";
     /**
      * <p>Broadcast Action: when data connections setup fails.
      * intended for sim/account status checks and only sent to the specified carrier app
-     * feedback is via carrier/system APIs to report cold-sim, out-of-credit-sim, etc
      * The intent will have the following extra values:</p>
      * <ul>
      *   <li>apnType</li><dd>A string with the apn type.</dd>
      *   <li>errorCode</li><dd>A integer with dataFailCause.</dd>
-     *   <li>subId</dt><li>Sub Id which associated the data redirection.</dd>
+     *   <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
      */
-    public static final String ACTION_REQUEST_NETWORK_FAILED =
-            "android.intent.action.REQUEST_NETWORK_FAILED";
+    public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
+            "android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
 
     /**
-     * Broadcast action to trigger CI OMA-DM Session.
+     * <p>Broadcast Action: when pco value is available.
+     * intended for sim/account status checks and only sent to the specified carrier app
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li>apnType</li><dd>A string with the apn type.</dd>
+     *   <li>pcoValue</li><dd>A integer read from modem.</dd>
+     *   <li>subId</dt><li>Sub Id which associated the data connection.</dd>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent by the system. </p>
      */
+    public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
+            "android.intent.action.CARRIER_SIGNAL_PCO_VALUE";
+
+    // CARRIER_SIGNAL_ACTION extra keys
+    public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
+    public static final String EXTRA_ERROR_CODE_KEY = "errorCode";
+    public static final String EXTRA_APN_TYPE_KEY = "apnType";
+    public static final String EXTRA_PCO_KEY = "pco";
+
+
+   /**
+     * Broadcast action to trigger CI OMA-DM Session.
+    */
     public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE =
             "com.android.omadm.service.CONFIGURATION_UPDATE";
 }