Merge "Add an adapter to bridge ECC data and emergency dialer UI"
diff --git a/src/com/android/phone/CellInfoUtil.java b/src/com/android/phone/CellInfoUtil.java
index 2c5f2a8..462cafe 100644
--- a/src/com/android/phone/CellInfoUtil.java
+++ b/src/com/android/phone/CellInfoUtil.java
@@ -26,7 +26,6 @@
 import android.telephony.CellInfoGsm;
 import android.telephony.CellInfoLte;
 import android.telephony.CellInfoWcdma;
-import android.telephony.TelephonyManager;
 import android.text.BidiFormatter;
 import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
@@ -47,47 +46,6 @@
     }
 
     /**
-     * Get the network type from a CellInfo. Network types include
-     * {@link TelephonyManager#NETWORK_TYPE_LTE}, {@link TelephonyManager#NETWORK_TYPE_UMTS},
-     * {@link TelephonyManager#NETWORK_TYPE_GSM}, {@link TelephonyManager#NETWORK_TYPE_CDMA} and
-     * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN}
-     * @return network types
-     */
-    public static int getNetworkType(CellInfo cellInfo) {
-        if (cellInfo instanceof CellInfoLte) {
-            return TelephonyManager.NETWORK_TYPE_LTE;
-        } else if (cellInfo instanceof CellInfoWcdma) {
-            return TelephonyManager.NETWORK_TYPE_UMTS;
-        } else if (cellInfo instanceof CellInfoGsm) {
-            return TelephonyManager.NETWORK_TYPE_GSM;
-        } else if (cellInfo instanceof CellInfoCdma) {
-            return TelephonyManager.NETWORK_TYPE_CDMA;
-        } else {
-            Log.e(TAG, "Invalid CellInfo type");
-            return TelephonyManager.NETWORK_TYPE_UNKNOWN;
-        }
-    }
-
-    /**
-     * Get signal level as an int from 0..4.
-     * @return Signal strength level
-     */
-    public static int getLevel(CellInfo cellInfo) {
-        if (cellInfo instanceof CellInfoLte) {
-            return ((CellInfoLte) cellInfo).getCellSignalStrength().getLevel();
-        } else if (cellInfo instanceof CellInfoWcdma) {
-            return ((CellInfoWcdma) cellInfo).getCellSignalStrength().getLevel();
-        } else if (cellInfo instanceof CellInfoGsm) {
-            return ((CellInfoGsm) cellInfo).getCellSignalStrength().getLevel();
-        } else if (cellInfo instanceof CellInfoCdma) {
-            return ((CellInfoCdma) cellInfo).getCellSignalStrength().getLevel();
-        } else {
-            Log.e(TAG, "Invalid CellInfo type");
-            return 0;
-        }
-    }
-
-    /**
      * Wrap a CellIdentity into a CellInfo.
      */
     public static CellInfo wrapCellInfoWithCellIdentity(CellIdentity cellIdentity) {
diff --git a/src/com/android/phone/GsmUmtsAdditionalCallOptions.java b/src/com/android/phone/GsmUmtsAdditionalCallOptions.java
index 082eaa9..b79cdd8 100644
--- a/src/com/android/phone/GsmUmtsAdditionalCallOptions.java
+++ b/src/com/android/phone/GsmUmtsAdditionalCallOptions.java
@@ -2,8 +2,10 @@
 
 import android.app.ActionBar;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
+import android.telephony.CarrierConfigManager;
 import android.util.Log;
 import android.view.MenuItem;
 
@@ -26,6 +28,9 @@
     private Phone mPhone;
     private SubscriptionInfoHelper mSubscriptionInfoHelper;
 
+    private boolean mShowCLIRButton;
+    private boolean mShowCWButton;
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -41,24 +46,60 @@
         mCLIRButton = (CLIRListPreference) prefSet.findPreference(BUTTON_CLIR_KEY);
         mCWButton = (CallWaitingSwitchPreference) prefSet.findPreference(BUTTON_CW_KEY);
 
-        mPreferences.add(mCLIRButton);
-        mPreferences.add(mCWButton);
-
-        if (icicle == null) {
-            if (DBG) Log.d(LOG_TAG, "start to init ");
-            mCLIRButton.init(this, false, mPhone);
+        PersistableBundle b = null;
+        if (mSubscriptionInfoHelper.hasSubId()) {
+            b = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+                    mSubscriptionInfoHelper.getSubId());
         } else {
-            if (DBG) Log.d(LOG_TAG, "restore stored states");
-            mInitIndex = mPreferences.size();
-            mCLIRButton.init(this, true, mPhone);
-            mCWButton.init(this, true, mPhone);
-            int[] clirArray = icicle.getIntArray(mCLIRButton.getKey());
-            if (clirArray != null) {
-                if (DBG) Log.d(LOG_TAG, "onCreate:  clirArray[0]="
-                        + clirArray[0] + ", clirArray[1]=" + clirArray[1]);
-                mCLIRButton.handleGetCLIRResult(clirArray);
+            b = PhoneGlobals.getInstance().getCarrierConfig();
+        }
+
+        if (b != null) {
+            mShowCLIRButton = b.getBoolean(
+                    CarrierConfigManager.KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL);
+            mShowCWButton = b.getBoolean(
+                    CarrierConfigManager.KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL);
+        }
+
+        if (mCLIRButton != null) {
+            if (mShowCLIRButton) {
+                mPreferences.add(mCLIRButton);
             } else {
-                mCLIRButton.init(this, false, mPhone);
+                prefSet.removePreference(mCLIRButton);
+            }
+        }
+
+        if (mCWButton != null) {
+            if (mShowCWButton) {
+                mPreferences.add(mCWButton);
+            } else {
+                prefSet.removePreference(mCWButton);
+            }
+        }
+
+        if (mPreferences.size() != 0) {
+            if (icicle == null) {
+                if (DBG) Log.d(LOG_TAG, "start to init ");
+                doPreferenceInit(mInitIndex);
+            } else {
+                if (DBG) Log.d(LOG_TAG, "restore stored states");
+                mInitIndex = mPreferences.size();
+                if (mShowCWButton) {
+                    mCWButton.init(this, true, mPhone);
+                }
+                if (mShowCLIRButton) {
+                    mCLIRButton.init(this, true, mPhone);
+                    int[] clirArray = icicle.getIntArray(mCLIRButton.getKey());
+                    if (clirArray != null) {
+                        if (DBG) {
+                            Log.d(LOG_TAG, "onCreate:  clirArray[0]="
+                                    + clirArray[0] + ", clirArray[1]=" + clirArray[1]);
+                        }
+                        mCLIRButton.handleGetCLIRResult(clirArray);
+                    } else {
+                        mCLIRButton.init(this, false, mPhone);
+                    }
+                }
             }
         }
 
@@ -73,7 +114,7 @@
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        if (mCLIRButton.clirArray != null) {
+        if (mShowCLIRButton && mCLIRButton.clirArray != null) {
             outState.putIntArray(mCLIRButton.getKey(), mCLIRButton.clirArray);
         }
     }
@@ -82,10 +123,7 @@
     public void onFinished(Preference preference, boolean reading) {
         if (mInitIndex < mPreferences.size()-1 && !isFinishing()) {
             mInitIndex++;
-            Preference pref = mPreferences.get(mInitIndex);
-            if (pref instanceof CallWaitingSwitchPreference) {
-                ((CallWaitingSwitchPreference) pref).init(this, false, mPhone);
-            }
+            doPreferenceInit(mInitIndex);
         }
         super.onFinished(preference, reading);
     }
@@ -99,4 +137,15 @@
         }
         return super.onOptionsItemSelected(item);
     }
+
+    private void doPreferenceInit(int index) {
+        if (mPreferences.size() != 0) {
+            Preference pref = mPreferences.get(index);
+            if (pref instanceof CallWaitingSwitchPreference) {
+                ((CallWaitingSwitchPreference) pref).init(this, false, mPhone);
+            } else if (pref instanceof CLIRListPreference) {
+                ((CLIRListPreference) pref).init(this, false, mPhone);
+            }
+        }
+    }
 }
diff --git a/src/com/android/phone/GsmUmtsCallBarringOptions.java b/src/com/android/phone/GsmUmtsCallBarringOptions.java
index 4b875ee..a6f9844 100644
--- a/src/com/android/phone/GsmUmtsCallBarringOptions.java
+++ b/src/com/android/phone/GsmUmtsCallBarringOptions.java
@@ -18,12 +18,15 @@
 
 import android.app.ActionBar;
 import android.app.Dialog;
+import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
+import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -360,6 +363,25 @@
             Log.d(LOG_TAG, "onCreate, reading callbarring_options.xml file finished!");
         }
 
+        CarrierConfigManager configManager = (CarrierConfigManager)
+                mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle carrierConfig;
+        if (mSubscriptionInfoHelper.hasSubId()) {
+            carrierConfig = configManager.getConfigForSubId(mSubscriptionInfoHelper.getSubId());
+        } else {
+            carrierConfig = configManager.getConfig();
+        }
+        boolean isPwChangeButtonVisible = true;
+        boolean isDisableAllButtonVisible = true;
+        if (carrierConfig != null) {
+            isPwChangeButtonVisible = carrierConfig.getBoolean(
+                    CarrierConfigManager.KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true);
+            isDisableAllButtonVisible = carrierConfig.getBoolean(
+                    CarrierConfigManager.KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true);
+        } else {
+            Log.w(LOG_TAG, "Couldn't access CarrierConfig bundle");
+        }
+
         // Get UI object references
         PreferenceScreen prefSet = getPreferenceScreen();
         mButtonBAOC = (CallBarringEditPreference) prefSet.findPreference(BUTTON_BAOC_KEY);
@@ -371,6 +393,15 @@
                 prefSet.findPreference(BUTTON_BA_ALL_KEY);
         mButtonChangePW = (EditPinPreference) prefSet.findPreference(BUTTON_BA_CHANGE_PW_KEY);
 
+        // Some carriers do not use PW change and disable all buttons. Hide them if this is the
+        // case.
+        if (!isDisableAllButtonVisible) {
+            prefSet.removePreference(mButtonDisableAll);
+        }
+        if (!isPwChangeButtonVisible) {
+            prefSet.removePreference(mButtonChangePW);
+        }
+
         // Assign click listener and update state
         mButtonBAOC.setOnPinEnteredListener(this);
         mButtonBAOIC.setOnPinEnteredListener(this);
diff --git a/src/com/android/phone/GsmUmtsCallOptions.java b/src/com/android/phone/GsmUmtsCallOptions.java
index 5358db9..ab44b54 100644
--- a/src/com/android/phone/GsmUmtsCallOptions.java
+++ b/src/com/android/phone/GsmUmtsCallOptions.java
@@ -62,25 +62,45 @@
     }
 
     public static void init(PreferenceScreen prefScreen, SubscriptionInfoHelper subInfoHelper) {
-        Preference callForwardingPref = prefScreen.findPreference(CALL_FORWARDING_KEY);
-        callForwardingPref.setIntent(subInfoHelper.getIntent(GsmUmtsCallForwardOptions.class));
-
-        Preference additionalGsmSettingsPref =
-                prefScreen.findPreference(ADDITIONAL_GSM_SETTINGS_KEY);
-        additionalGsmSettingsPref.setIntent(
-                subInfoHelper.getIntent(GsmUmtsAdditionalCallOptions.class));
-
-        Preference callBarringPref = prefScreen.findPreference(CALL_BARRING_KEY);
         PersistableBundle b = null;
         if (subInfoHelper.hasSubId()) {
             b = PhoneGlobals.getInstance().getCarrierConfigForSubId(subInfoHelper.getSubId());
         } else {
             b = PhoneGlobals.getInstance().getCarrierConfig();
         }
-        if (b != null && b.getBoolean(CarrierConfigManager.KEY_CALL_BARRING_VISIBILITY_BOOL)) {
-            callBarringPref.setIntent(subInfoHelper.getIntent(GsmUmtsCallBarringOptions.class));
-        } else {
-            prefScreen.removePreference(callBarringPref);
+
+        Preference callForwardingPref = prefScreen.findPreference(CALL_FORWARDING_KEY);
+        if (callForwardingPref != null) {
+            if (b != null && b.getBoolean(
+                    CarrierConfigManager.KEY_CALL_FORWARDING_VISIBILITY_BOOL)) {
+                callForwardingPref.setIntent(
+                        subInfoHelper.getIntent(GsmUmtsCallForwardOptions.class));
+            } else {
+                prefScreen.removePreference(callForwardingPref);
+            }
+        }
+
+        Preference additionalGsmSettingsPref =
+                prefScreen.findPreference(ADDITIONAL_GSM_SETTINGS_KEY);
+        if (additionalGsmSettingsPref != null) {
+            if (b != null && (b.getBoolean(
+                    CarrierConfigManager.KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL)
+                    || b.getBoolean(
+                    CarrierConfigManager.KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL))) {
+                additionalGsmSettingsPref.setIntent(
+                        subInfoHelper.getIntent(GsmUmtsAdditionalCallOptions.class));
+            } else {
+                prefScreen.removePreference(additionalGsmSettingsPref);
+            }
+        }
+
+        Preference callBarringPref = prefScreen.findPreference(CALL_BARRING_KEY);
+        if (callBarringPref != null) {
+            if (b != null && b.getBoolean(CarrierConfigManager.KEY_CALL_BARRING_VISIBILITY_BOOL)) {
+                callBarringPref.setIntent(subInfoHelper.getIntent(GsmUmtsCallBarringOptions.class));
+            } else {
+                prefScreen.removePreference(callBarringPref);
+            }
         }
     }
 }
diff --git a/src/com/android/phone/NetworkOperatorPreference.java b/src/com/android/phone/NetworkOperatorPreference.java
index 85adf16..e582924 100644
--- a/src/com/android/phone/NetworkOperatorPreference.java
+++ b/src/com/android/phone/NetworkOperatorPreference.java
@@ -24,7 +24,6 @@
 import android.preference.Preference;
 import android.telephony.CellInfo;
 import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.view.Gravity;
 
@@ -71,7 +70,7 @@
             networkTitle += " " + getContext().getResources().getString(R.string.forbidden_network);
         }
         setTitle(networkTitle);
-        int level = CellInfoUtil.getLevel(mCellInfo);
+        int level = mCellInfo.getCellSignalStrength().getLevel();
         if (DBG) Log.d(TAG, "refresh level: " + String.valueOf(level));
         if (mLevel != level) {
             mLevel = level;
@@ -86,17 +85,15 @@
         updateIcon(level);
     }
 
-    private int getIconId(int networkType) {
-        if (networkType == TelephonyManager.NETWORK_TYPE_CDMA) {
-            return R.drawable.signal_strength_1x;
-        } else if (networkType == TelephonyManager.NETWORK_TYPE_LTE) {
-            return R.drawable.signal_strength_lte;
-        } else if (networkType == TelephonyManager.NETWORK_TYPE_UMTS) {
-            return R.drawable.signal_strength_3g;
-        } else if (networkType == TelephonyManager.NETWORK_TYPE_GSM) {
-            return R.drawable.signal_strength_g;
-        } else {
-            return 0;
+    private static int getIconIdForCell(CellInfo ci) {
+        final int type = ci.getCellIdentity().getType();
+        switch (type) {
+            case CellInfo.TYPE_GSM: return R.drawable.signal_strength_g;
+            case CellInfo.TYPE_WCDMA: // fall through
+            case CellInfo.TYPE_TDSCDMA: return R.drawable.signal_strength_3g;
+            case CellInfo.TYPE_LTE: return R.drawable.signal_strength_lte;
+            case CellInfo.TYPE_CDMA: return R.drawable.signal_strength_1x;
+            default: return 0;
         }
     }
 
@@ -113,7 +110,7 @@
         signalDrawable.setDarkIntensity(0);
 
         // Make the network type drawable
-        int iconType = getIconId(CellInfoUtil.getNetworkType(mCellInfo));
+        int iconType = getIconIdForCell(mCellInfo);
         Drawable networkDrawable =
                 iconType == NO_CELL_DATA_CONNECTED_ICON
                         ? EMPTY_DRAWABLE
diff --git a/src/com/android/phone/NetworkSelectSetting.java b/src/com/android/phone/NetworkSelectSetting.java
index 96e4a26..6bb42c8 100644
--- a/src/com/android/phone/NetworkSelectSetting.java
+++ b/src/com/android/phone/NetworkSelectSetting.java
@@ -560,8 +560,8 @@
                 map.put(plmn, cellInfo);
             } else {
                 if (map.get(plmn).isRegistered()
-                        || CellInfoUtil.getLevel(map.get(plmn))
-                        > CellInfoUtil.getLevel(cellInfo)) {
+                        || map.get(plmn).getCellSignalStrength().getLevel()
+                        > cellInfo.getCellSignalStrength().getLevel()) {
                     // Skip if the stored cellInfo is registered or has higher signal strength level
                     continue;
                 }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index a97c4b3..51ffbd8 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -1922,7 +1922,10 @@
     @SuppressWarnings("unchecked")
     public List<NeighboringCellInfo>
             getNeighboringCellInfo(String callingPackage, int targetSdk) {
-        if (targetSdk > android.os.Build.VERSION_CODES.P) return null;
+        if (targetSdk >= android.os.Build.VERSION_CODES.Q) {
+            throw new SecurityException(
+                    "getNeighboringCellInfo() is unavailable to callers targeting Q+ SDK levels.");
+        }
 
         if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
@@ -4359,7 +4362,7 @@
             synchronized (mLastModemActivityInfo) {
                 ModemActivityInfo info = (ModemActivityInfo) sendRequest(CMD_GET_MODEM_ACTIVITY_INFO,
                         null);
-                if (info != null) {
+                if (isModemActivityInfoValid(info)) {
                     int[] mergedTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
                     for (int i = 0; i < mergedTxTimeMs.length; i++) {
                         mergedTxTimeMs[i] =
@@ -4391,6 +4394,25 @@
         }
     }
 
+    // Checks that ModemActivityInfo is valid. Sleep time, Idle time, Rx time and Tx time should be
+    // less than total activity duration.
+    private boolean isModemActivityInfoValid(ModemActivityInfo info) {
+        if (info == null) {
+            return false;
+        }
+        int activityDurationMs =
+                (int) (info.getTimestamp() - mLastModemActivityInfo.getTimestamp());
+        int totalTxTimeMs = 0;
+        for (int i = 0; i < info.getTxTimeMillis().length; i++) {
+            totalTxTimeMs += info.getTxTimeMillis()[i];
+        }
+        return (info.isValid()
+            && (info.getSleepTimeMillis() <= activityDurationMs)
+            && (info.getIdleTimeMillis() <= activityDurationMs)
+            && (info.getRxTimeMillis() <= activityDurationMs)
+            && (totalTxTimeMs <= activityDurationMs));
+    }
+
     /**
      * {@hide}
      * Returns the service state information on specified subscription.