Merge "make callerInfo a systemAPI"
diff --git a/ecc/conversion_toolset_v1/gen_eccdata.sh b/ecc/conversion_toolset_v1/gen_eccdata.sh
index 803f39b..9fc0efc 100644
--- a/ecc/conversion_toolset_v1/gen_eccdata.sh
+++ b/ecc/conversion_toolset_v1/gen_eccdata.sh
@@ -19,8 +19,7 @@
 source "${LOCAL_TOOLSET_DIR}/env.sh"
 
 echo "Converting eccdata..."
-${ANDROID_BUILD_TOP}/prebuilts/misc/${KERNEL}-x86/protobuf/aprotoc \
-  --encode=ecc.AllInfo proto/protobuf_ecc_data.proto \
+aprotoc --encode=ecc.AllInfo proto/protobuf_ecc_data.proto \
   < "${INPUT_DATA}" > "${RAW_DATA}"
 
 echo "Compressing eccdata..."
diff --git a/ecc/gen_eccdata.sh b/ecc/gen_eccdata.sh
index 4c1f616..2888585 100755
--- a/ecc/gen_eccdata.sh
+++ b/ecc/gen_eccdata.sh
@@ -20,24 +20,8 @@
   exit 1
 fi
 
-case $(uname -s) in
-  Darwin)
-    KERNEL=darwin
-    ;;
-  Linux)
-    KERNEL=linux
-    ;;
-  *)
-    echo "Unknown kernel \"`uname -s`\"" 1>&2
-    exit 1
-    ;;
-esac
-
-read -d "" PROTOC_COMMAND << END || :
-${ANDROID_BUILD_TOP}/prebuilts/misc/${KERNEL}-x86/protobuf/aprotoc
-END
-if ! [ -x "${PROTOC_COMMAND}" ] ; then
-  echo "Missing ${PROTOC_COMMAND}." 1>&2
+if ! [ -x "$(which aprotoc)" ] ; then
+  echo "Missing aprotoc, build it with 'm aprotoc'." 1>&2
   exit 1
 fi
 
diff --git a/sip/src/com/android/services/telephony/sip/SipProfileDb.java b/sip/src/com/android/services/telephony/sip/SipProfileDb.java
index bb1c7ec..812ebb4 100644
--- a/sip/src/com/android/services/telephony/sip/SipProfileDb.java
+++ b/sip/src/com/android/services/telephony/sip/SipProfileDb.java
@@ -16,11 +16,10 @@
 
 package com.android.services.telephony.sip;
 
-import com.android.internal.os.AtomicFile;
-
 import android.content.Context;
 import android.net.sip.SipProfile;
 import android.text.TextUtils;
+import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
 
diff --git a/src/com/android/phone/EmergencyActionGroup.java b/src/com/android/phone/EmergencyActionGroup.java
index b8bf7a8..c090af7 100644
--- a/src/com/android/phone/EmergencyActionGroup.java
+++ b/src/com/android/phone/EmergencyActionGroup.java
@@ -161,7 +161,10 @@
             case R.id.action1:
             case R.id.action2:
             case R.id.action3:
-                if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
+                AccessibilityManager accessibilityMgr =
+                        (AccessibilityManager) mContext.getSystemService(
+                                Context.ACCESSIBILITY_SERVICE);
+                if (accessibilityMgr.isTouchExplorationEnabled()) {
                     getContext().startActivity(intent);
                 } else {
                     revealTheButton(v);
diff --git a/src/com/android/phone/EmergencyAssistanceHelper.java b/src/com/android/phone/EmergencyAssistanceHelper.java
index 33788d3..79ee515 100644
--- a/src/com/android/phone/EmergencyAssistanceHelper.java
+++ b/src/com/android/phone/EmergencyAssistanceHelper.java
@@ -31,8 +31,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.internal.util.CollectionUtils;
-
 import java.util.List;
 
 /**
@@ -120,8 +118,9 @@
     private static String getDefaultEmergencyPackage(Context context) {
         long identity = Binder.clearCallingIdentity();
         try {
-            return CollectionUtils.firstOrNull(context.getSystemService(RoleManager.class)
-                    .getRoleHolders(RoleManager.ROLE_EMERGENCY));
+            List<String> roleHolders = context.getSystemService(RoleManager.class)
+                    .getRoleHolders(RoleManager.ROLE_EMERGENCY);
+            return roleHolders.isEmpty() ? null : roleHolders.get(0);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 3cf74c8..42209c7 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -23,6 +23,7 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
+import android.app.WallpaperColors;
 import android.app.WallpaperManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -31,6 +32,7 @@
 import android.database.DataSetObserver;
 import android.graphics.Color;
 import android.graphics.Point;
+import android.graphics.drawable.ColorDrawable;
 import android.media.AudioManager;
 import android.media.ToneGenerator;
 import android.net.Uri;
@@ -68,9 +70,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.TextView;
 
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.drawable.ScrimDrawable;
 import com.android.phone.EmergencyDialerMetricsLogger.DialedFrom;
 import com.android.phone.EmergencyDialerMetricsLogger.PhoneNumberType;
 import com.android.phone.EmergencyDialerMetricsLogger.UiModeErrorCode;
@@ -100,7 +99,8 @@
  */
 public class EmergencyDialer extends Activity implements View.OnClickListener,
         View.OnLongClickListener, View.OnKeyListener, TextWatcher,
-        DialpadKeyButton.OnPressedListener, ColorExtractor.OnColorsChangedListener,
+        DialpadKeyButton.OnPressedListener,
+        WallpaperManager.OnColorsChangedListener,
         EmergencyShortcutButton.OnConfirmClickListener,
         EmergencyInfoGroup.OnConfirmClickListener {
 
@@ -212,8 +212,7 @@
     private String mLastNumber; // last number we tried to dial. Used to restore error dialog.
 
     // Background gradient
-    private ColorExtractor mColorExtractor;
-    private ScrimDrawable mBackgroundDrawable;
+    private ColorDrawable mBackgroundDrawable;
     private boolean mSupportsDarkText;
 
     private boolean mIsWfcEmergencyCallingWarningEnabled;
@@ -276,15 +275,13 @@
         Log.d(LOG_TAG, "Enable emergency dialer shortcut: "
                 + mShortcutViewConfig.isEnabled());
 
-        mColorExtractor = new ColorExtractor(this);
-
         if (mShortcutViewConfig.isEnabled()) {
             // Shortcut view doesn't support dark text theme.
             updateTheme(false);
         } else {
-            GradientColors lockScreenColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
-                    ColorExtractor.TYPE_EXTRA_DARK);
-            updateTheme(lockScreenColors.supportsDarkText());
+            WallpaperColors wallpaperColors =
+                    getWallpaperManager().getWallpaperColors(WallpaperManager.FLAG_LOCK);
+            updateTheme(supportsDarkText(wallpaperColors));
         }
 
         setContentView(R.layout.emergency_dialer);
@@ -298,7 +295,7 @@
         mDefaultDigitsTextSize = mDigits.getScaledTextSize();
         maybeAddNumberFormatting();
 
-        mBackgroundDrawable = new ScrimDrawable();
+        mBackgroundDrawable = new ColorDrawable();
         Point displaySize = new Point();
         ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay().getSize(displaySize);
@@ -647,15 +644,18 @@
 
         if (mShortcutViewConfig.isEnabled()) {
             // Shortcut view doesn't support dark text theme.
-            mBackgroundDrawable.setColor(Color.BLACK, false);
+            mBackgroundDrawable.setColor(Color.BLACK);
             updateTheme(false);
         } else {
-            mColorExtractor.addOnColorsChangedListener(this);
-            GradientColors lockScreenColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
-                    ColorExtractor.TYPE_EXTRA_DARK);
-            // Do not animate when view isn't visible yet, just set an initial state.
-            mBackgroundDrawable.setColor(lockScreenColors.getMainColor(), false);
-            updateTheme(lockScreenColors.supportsDarkText());
+            WallpaperManager wallpaperManager = getWallpaperManager();
+            if (wallpaperManager.isWallpaperSupported()) {
+                wallpaperManager.addOnColorsChangedListener(this, null);
+            }
+
+            WallpaperColors wallpaperColors =
+                    wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK);
+            mBackgroundDrawable.setColor(getPrimaryColor(wallpaperColors));
+            updateTheme(supportsDarkText(wallpaperColors));
         }
 
         if (mShortcutViewConfig.isEnabled()) {
@@ -696,7 +696,11 @@
     @Override
     protected void onStop() {
         super.onStop();
-        mColorExtractor.removeOnColorsChangedListener(this);
+
+        WallpaperManager wallpaperManager = getWallpaperManager();
+        if (wallpaperManager.isWallpaperSupported()) {
+            wallpaperManager.removeOnColorsChangedListener(this);
+        }
     }
 
     /**
@@ -937,12 +941,10 @@
     }
 
     @Override
-    public void onColorsChanged(ColorExtractor extractor, int which) {
+    public void onColorsChanged(WallpaperColors colors, int which) {
         if ((which & WallpaperManager.FLAG_LOCK) != 0) {
-            GradientColors colors = extractor.getColors(WallpaperManager.FLAG_LOCK,
-                    ColorExtractor.TYPE_EXTRA_DARK);
-            mBackgroundDrawable.setColor(colors.getMainColor(), true /* animated */);
-            updateTheme(colors.supportsDarkText());
+            mBackgroundDrawable.setColor(getPrimaryColor(colors));
+            updateTheme(supportsDarkText(colors));
         }
     }
 
@@ -1236,4 +1238,28 @@
                 return "Unknown-" + callSource;
         }
     }
+
+    private WallpaperManager getWallpaperManager() {
+        return getSystemService(WallpaperManager.class);
+    }
+
+    private static boolean supportsDarkText(WallpaperColors colors) {
+        if (colors != null) {
+            return (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
+        }
+        // It's possible that wallpaper colors are null (e.g. when colors are being
+        // processed or a live wallpaper is used). In this case, fallback to same
+        // behavior as when shortcut view is enabled.
+        return false;
+    }
+
+    private static int getPrimaryColor(WallpaperColors colors) {
+        if (colors != null) {
+            return colors.getPrimaryColor().toArgb();
+        }
+        // It's possible that wallpaper colors are null (e.g. when colors are being
+        // processed or a live wallpaper is used). In this case, fallback to same
+        // behavior as when shortcut view is enabled.
+        return Color.BLACK;
+    }
 }
diff --git a/src/com/android/phone/EmergencyInfoGroup.java b/src/com/android/phone/EmergencyInfoGroup.java
index 14c24d8..5120bc8 100644
--- a/src/com/android/phone/EmergencyInfoGroup.java
+++ b/src/com/android/phone/EmergencyInfoGroup.java
@@ -210,7 +210,10 @@
     public void onClick(View view) {
         switch (view.getId()) {
             case R.id.emergency_info_view:
-                if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
+                AccessibilityManager accessibilityMgr =
+                        (AccessibilityManager) mContext.getSystemService(
+                                Context.ACCESSIBILITY_SERVICE);
+                if (accessibilityMgr.isTouchExplorationEnabled()) {
                     if (mOnConfirmClickListener != null) {
                         mOnConfirmClickListener.onConfirmClick(this);
                     }
diff --git a/src/com/android/phone/EmergencyShortcutButton.java b/src/com/android/phone/EmergencyShortcutButton.java
index 59b3794..f77595b 100644
--- a/src/com/android/phone/EmergencyShortcutButton.java
+++ b/src/com/android/phone/EmergencyShortcutButton.java
@@ -195,7 +195,10 @@
     public void onClick(View view) {
         switch (view.getId()) {
             case R.id.emergency_call_number_info_view:
-                if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
+                AccessibilityManager accessibilityMgr =
+                        (AccessibilityManager) mContext.getSystemService(
+                                Context.ACCESSIBILITY_SERVICE);
+                if (accessibilityMgr.isTouchExplorationEnabled()) {
                     // TalkBack itself includes a prompt to confirm click action implicitly,
                     // so we don't need an additional confirmation with second tap on button.
                     if (mOnConfirmClickListener != null) {
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index e5e9fe7..a2cbaf8 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -63,6 +63,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CarrierRestrictionRules;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
 import android.telephony.CellInfoWcdma;
@@ -259,6 +260,8 @@
     private static final int EVENT_ENABLE_MODEM_DONE = 69;
     private static final int CMD_GET_MODEM_STATUS = 70;
     private static final int EVENT_GET_MODEM_STATUS_DONE = 71;
+    private static final int CMD_SET_FORBIDDEN_PLMNS = 72;
+    private static final int EVENT_SET_FORBIDDEN_PLMNS_DONE = 73;
 
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
@@ -1166,6 +1169,50 @@
                     }
                     notifyRequester(request);
                     break;
+                case EVENT_SET_FORBIDDEN_PLMNS_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    if (ar.exception == null && ar.result != null) {
+                        request.result = ar.result;
+                    } else {
+                        request.result = -1;
+                        loge("Failed to set Forbidden Plmns");
+                        if (ar.result == null) {
+                            loge("setForbidenPlmns: Empty response");
+                        } else if (ar.exception != null) {
+                            loge("setForbiddenPlmns: Exception: " + ar.exception);
+                            request.result = -1;
+                        } else {
+                            loge("setForbiddenPlmns: Unknown exception");
+                        }
+                    }
+                    notifyRequester(request);
+                    break;
+                case CMD_SET_FORBIDDEN_PLMNS:
+                    request = (MainThreadRequest) msg.obj;
+                    uiccCard = getUiccCardFromRequest(request);
+                    if (uiccCard == null) {
+                        loge("setForbiddenPlmns: UiccCard is null");
+                        request.result = -1;
+                        notifyRequester(request);
+                        break;
+                    }
+                    Pair<Integer, List<String>> setFplmnsArgs =
+                            (Pair<Integer, List<String>>) request.argument;
+                    appType = setFplmnsArgs.first;
+                    List<String> fplmns = setFplmnsArgs.second;
+                    uiccApp = uiccCard.getApplicationByType(appType);
+                    if (uiccApp == null) {
+                        loge("setForbiddenPlmns: no app with specified type -- " + appType);
+                        request.result = -1;
+                        loge("Failed to get UICC App");
+                        notifyRequester(request);
+                    } else {
+                        onCompleted = obtainMessage(EVENT_SET_FORBIDDEN_PLMNS_DONE, request);
+                        ((SIMRecords) uiccApp.getIccRecords())
+                                .setForbiddenPlmns(onCompleted, fplmns);
+                    }
+                    break;
                 default:
                     Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
                     break;
@@ -4031,7 +4078,7 @@
             if (response instanceof String[]) {
                 return (String[]) response;
             }
-            // Response is an Exception of some kind,
+            // Response is an Exception of some kind
             // which is signalled to the user as a NULL retval
             return null;
         } finally {
@@ -4039,6 +4086,47 @@
         }
     }
 
+    /**
+     * Set the forbidden PLMN list from the given app type (ex APPTYPE_USIM) on a particular
+     * subscription.
+     *
+     * @param subId the id of the subscription.
+     * @param appType the uicc app type, must be USIM or SIM.
+     * @param fplmns the Forbiden plmns list that needed to be written to the SIM.
+     * @param callingPackage the op Package name.
+     * @return number of fplmns that is successfully written to the SIM.
+     */
+    public int setForbiddenPlmns(
+            int subId, int appType, List<String> fplmns, String callingPackage) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                mApp, subId, callingPackage, "setForbiddenPlmns")) {
+            if (DBG) logv("no permissions for setForbiddenplmns");
+            throw new IllegalStateException("No Permissions for setForbiddenPlmns");
+        }
+        if (appType != TelephonyManager.APPTYPE_USIM && appType != TelephonyManager.APPTYPE_SIM) {
+            loge("setForbiddenPlmnList(): App Type must be USIM or SIM");
+            throw new IllegalArgumentException("Invalid appType: App Type must be USIM or SIM");
+        }
+        if (fplmns == null) {
+            throw new IllegalArgumentException("Fplmn List provided is null");
+        }
+        for (String fplmn : fplmns) {
+            if (!CellIdentity.isValidPlmn(fplmn)) {
+                throw new IllegalArgumentException("Invalid fplmn provided: " + fplmn);
+            }
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Object response = sendRequest(
+                    CMD_SET_FORBIDDEN_PLMNS,
+                    new Pair<Integer, List<String>>(new Integer(appType), fplmns),
+                    subId);
+            return (int) response;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public String sendEnvelopeWithStatus(int subId, String content) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
diff --git a/src/com/android/phone/euicc/EuiccResolutionUiDispatcherActivity.java b/src/com/android/phone/euicc/EuiccResolutionUiDispatcherActivity.java
index 0f083c9..fd741a0 100644
--- a/src/com/android/phone/euicc/EuiccResolutionUiDispatcherActivity.java
+++ b/src/com/android/phone/euicc/EuiccResolutionUiDispatcherActivity.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.service.euicc.EuiccService;
 import android.telephony.euicc.EuiccManager;
+import android.util.ArraySet;
 import android.util.Log;
 
 /**
@@ -33,6 +34,14 @@
 public class EuiccResolutionUiDispatcherActivity extends EuiccUiDispatcherActivity {
     private static final String TAG = "EuiccResUiDispatcher";
 
+    /** List of all valid resolution actions for validation purposes. */
+    private static final ArraySet<String> RESOLUTION_ACTIONS = new ArraySet<>();
+    static {
+        RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM);
+        RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES);
+        RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_RESOLVABLE_ERRORS);
+    }
+
     @Override
     @Nullable
     protected Intent getEuiccUiIntent() {
@@ -45,7 +54,7 @@
         String euiccUiAction =
                 getIntent().getStringExtra(
                         EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION);
-        if (!EuiccService.RESOLUTION_ACTIONS.contains(euiccUiAction)) {
+        if (!RESOLUTION_ACTIONS.contains(euiccUiAction)) {
             Log.w(TAG, "Unknown resolution action: " + euiccUiAction);
             return null;
         }
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index 223616f..a2ced9e 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -54,6 +54,14 @@
     private static final int EVENT_CDMA_CALL_WAITING = 101;
     private static final int EVENT_UNKNOWN_CONNECTION = 102;
 
+    /**
+     * The max amount of time to wait before hanging up a call that was for number verification.
+     *
+     * The delay is so that the remote end has time to hang up the call after receiving the
+     * verification signal so that the call doesn't go to voicemail.
+     */
+    private static final int MAX_NUMBER_VERIFICATION_HANGUP_DELAY_MILLIS = 10000;
+
     /** The phone object to listen to. */
     private final Phone mPhone;
 
@@ -131,12 +139,16 @@
             if (connection.getAddress() != null) {
                 if (NumberVerificationManager.getInstance()
                         .checkIncomingCall(connection.getAddress())) {
-                    // Disconnect the call if it matches
-                    try {
-                        connection.hangup();
-                    } catch (CallStateException e) {
-                        Log.e(this, e, "Error hanging up potential number verification call");
-                    }
+                    // Disconnect the call if it matches, after a delay
+                    mHandler.postDelayed(() -> {
+                        try {
+                            connection.hangup();
+                        } catch (CallStateException e) {
+                            Log.i(this, "Remote end hung up call verification call");
+                        }
+                        // TODO: use an app-supplied delay (needs new API), not to exceed the
+                        // existing max.
+                    }, MAX_NUMBER_VERIFICATION_HANGUP_DELAY_MILLIS);
                     return;
                 }
             }
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 6bbcdc4..1e681e8 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -820,6 +820,15 @@
         }
     };
 
+    private BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.i(this, "Locale change; re-registering phone accounts.");
+            tearDownAccounts();
+            setupAccounts();
+        }
+    };
+
     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
         @Override
         public void onServiceStateChanged(ServiceState serviceState) {
@@ -1083,6 +1092,11 @@
         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         mContext.registerReceiver(mReceiver, filter);
 
+        //We also need to listen for locale changes
+        //(e.g. system language changed -> SIM card name changed)
+        mContext.registerReceiver(mLocaleChangeReceiver,
+                new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
+
         // Listen to the RTT system setting so that we update it when the user flips it.
         ContentObserver rttUiSettingObserver = new ContentObserver(
                 new Handler(Looper.getMainLooper())) {