Merge "Fix null pointer in SubscriptionUtil" into qt-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b7fd299..9dd4732 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -102,13 +102,15 @@
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
 
+    <protected-broadcast android:name="com.android.settings.DELETE_SIM_PROFILE_RESULT"/>
+
     <application android:label="@string/settings_label"
             android:icon="@drawable/ic_launcher_settings"
             android:theme="@style/Theme.Settings"
             android:hardwareAccelerated="true"
             android:requiredForAllUsers="true"
             android:supportsRtl="true"
-            android:allowBackup="false"
+            android:backupAgent="com.android.settings.backup.SettingsBackupHelper"
             android:usesCleartextTraffic="true"
             android:defaultToDeviceProtectedStorage="true"
             android:directBootAware="true"
@@ -136,6 +138,7 @@
             <intent-filter android:priority="1">
                 <action android:name="android.settings.NETWORK_OPERATOR_SETTINGS" />
                 <action android:name="android.settings.DATA_ROAMING_SETTINGS" />
+                <action android:name="android.settings.MMS_MESSAGE_SETTING" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
@@ -2622,6 +2625,7 @@
         <receiver android:name=".sim.SimSelectNotification">
             <intent-filter>
                 <action android:name="android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED"/>
+                <action android:name="android.settings.ENABLE_MMS_DATA_REQUEST"/>
             </intent-filter>
         </receiver>
 
diff --git a/res/drawable/ic_settings_gestures.xml b/res/drawable/ic_settings_gestures.xml
index 4fe0bf3..c75e7c3 100644
--- a/res/drawable/ic_settings_gestures.xml
+++ b/res/drawable/ic_settings_gestures.xml
@@ -20,9 +20,6 @@
         android:viewportHeight="32.0"
         android:tint="?android:attr/colorControlNormal">
     <path
-        android:fillColor="#FF000000"
-        android:pathData="M20,20.2V24H6V5.3h8.7l2.4,-4H7.6c-2.2,0 -4,1.8 -4,4v21.3c0,2.2 1.8,4 4,4h10.7c2.2,0 4,-1.8 4,-4V14.9L20,20.2zM15.6,28h-5.3v-1.3h5.3V28z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M28.5,7l1.1,-2.4L32,3.5l-2.4,-1.1L28.5,0l-1.1,2.4L25,3.5l2.4,1.1L28.5,7zM21,7.4l-2.2,-4.8l-2.2,4.8l-4.8,2.2l4.8,2.2l2.2,4.8l2.2,-4.8l4.8,-2.2L21,7.4zM28.5,12.2l-1.1,2.4L25,15.6l2.4,1.1l1.1,2.4l1.1,-2.4l2.4,-1.1l-2.4,-1.1L28.5,12.2z"/>
+        android:fillColor="@android:color/white"
+        android:pathData="M4.59 6.89c0.7-0.71 1.4-1.35 1.71-1.22 0.5 0.2 0 1.03-0.3 1.52-0.25 0.42 -2.86 3.89-2.86 6.31 0 1.28 0.48 2.34 1.34 2.98 0.75 0.56 1.74 0.73 2.64 0.46 1.07-0.31 1.95-1.4 3.06-2.77 1.21-1.49 2.83-3.44 4.08-3.44 1.63 0 1.65 1.01 1.76 1.79-3.78 0.64 -5.38 3.67-5.38 5.37 0 1.7 1.44 3.09 3.21 3.09 1.63 0 4.29-1.33 4.69-6.1H21v-2.5h-2.47c-0.15-1.65-1.09-4.2-4.03-4.2-2.25 0-4.18 1.91-4.94 2.84-0.58 0.73 -2.06 2.48-2.29 2.72-0.25 0.3 -0.68 0.84 -1.11 0.84 -0.45 0-0.72-0.83-0.36-1.92 0.35 -1.09 1.4-2.86 1.85-3.52 0.78 -1.14 1.3-1.92 1.3-3.28C8.95 3.69 7.31 3 6.44 3 5.12 3 3.97 4 3.72 4.25c-0.36 0.36 -0.66 0.66 -0.88 0.93 l1.75 1.71zm9.29 11.66c-0.31 0-0.74-0.26-0.74-0.72 0-0.6 0.73 -2.2 2.87-2.76-0.3 2.69-1.43 3.48-2.13 3.48z" />
 </vector>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5609006..98892e4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7330,6 +7330,9 @@
     <!-- Battery Saver: Search terms for battery saver schedule preference. Feel free to add additional terms when translating if appropriate [CHAR_LIMIT=NONE] -->
     <string name="keywords_battery_saver_schedule">routine, schedule, battery saver, power saver, battery, automatic, percent</string>
 
+    <!-- List of synonyms for the Add an account setting [CHAR_LIMIT=NONE] -->
+    <string name="keywords_add_an_account">work profile</string>
+
     <!-- Option title for the default sound, context based on screen -->
     <string name="default_sound">Default sound</string>
 
diff --git a/res/xml/add_account_settings.xml b/res/xml/add_account_settings.xml
index 6b36f8d..01e7674 100644
--- a/res/xml/add_account_settings.xml
+++ b/res/xml/add_account_settings.xml
@@ -19,4 +19,5 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="add_account_screen"
     android:title="@string/header_add_an_account"
-    settings:controller="com.android.settings.accounts.ChooseAccountPreferenceController" />
+    settings:controller="com.android.settings.accounts.ChooseAccountPreferenceController"
+    settings:keywords="@string/keywords_add_an_account"/>
diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml
index cc377bd..1ff8860 100644
--- a/res/xml/mobile_network_settings_v2.xml
+++ b/res/xml/mobile_network_settings_v2.xml
@@ -191,4 +191,10 @@
 
     </PreferenceCategory>
 
+    <Preference
+        android:key="erase_sim"
+        android:persistent="false"
+        android:title="@string/mobile_network_erase_sim"
+        settings:controller="com.android.settings.network.telephony.DeleteSimProfilePreferenceController" />
+
 </PreferenceScreen>
diff --git a/src/com/android/settings/backup/SettingsBackupHelper.java b/src/com/android/settings/backup/SettingsBackupHelper.java
new file mode 100644
index 0000000..92612b0
--- /dev/null
+++ b/src/com/android/settings/backup/SettingsBackupHelper.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.backup;
+
+import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupDataInputStream;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupHelper;
+import android.os.ParcelFileDescriptor;
+
+import com.android.settings.shortcut.CreateShortcutPreferenceController;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Backup agent for Settings APK
+ */
+public class SettingsBackupHelper extends BackupAgentHelper {
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        addHelper("no-op", new NoOpHelper());
+    }
+
+    @Override
+    public void onRestoreFinished() {
+        super.onRestoreFinished();
+        CreateShortcutPreferenceController.updateRestoredShortcuts(this);
+    }
+
+    /**
+     * Backup helper which does not do anything. Having at least one helper ensures that the
+     * transport is not empty and onRestoreFinished is called eventually.
+     */
+    private static class NoOpHelper implements BackupHelper {
+
+        private final int VERSION_CODE = 1;
+
+        @Override
+        public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+                ParcelFileDescriptor newState) {
+
+            try (FileOutputStream out = new FileOutputStream(newState.getFileDescriptor())) {
+                if (getVersionCode(oldState) != VERSION_CODE) {
+                    data.writeEntityHeader("dummy", 1);
+                    data.writeEntityData(new byte[1], 1);
+                }
+
+                // Write new version code
+                out.write(VERSION_CODE);
+                out.flush();
+            } catch (IOException e) { }
+        }
+
+        @Override
+        public void restoreEntity(BackupDataInputStream data) { }
+
+        @Override
+        public void writeNewStateDescription(ParcelFileDescriptor newState) { }
+
+        private int getVersionCode(ParcelFileDescriptor state) {
+            if (state == null) {
+                return 0;
+            }
+            try (FileInputStream in = new FileInputStream(state.getFileDescriptor())) {
+                return in.read();
+            } catch (IOException e) {
+                return 0;
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
index 1c75669..d42a1be 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
@@ -66,7 +66,7 @@
         if (TextUtils.equals(getPreferenceKey(), preference.getKey()) && mFragment != null) {
             mMetricsFeatureProvider.action(mContext,
                     SettingsEnums.ACTION_BLUETOOTH_RENAME);
-            LocalDeviceNameDialogFragment.newInstance()
+            new LocalDeviceNameDialogFragment()
                     .show(mFragment.getFragmentManager(), LocalDeviceNameDialogFragment.TAG);
             return true;
         }
diff --git a/src/com/android/settings/bluetooth/LocalDeviceNameDialogFragment.java b/src/com/android/settings/bluetooth/LocalDeviceNameDialogFragment.java
index 5cf2ccc..c15dd04 100644
--- a/src/com/android/settings/bluetooth/LocalDeviceNameDialogFragment.java
+++ b/src/com/android/settings/bluetooth/LocalDeviceNameDialogFragment.java
@@ -31,10 +31,6 @@
     public static final String TAG = "LocalAdapterName";
     private BluetoothAdapter mBluetoothAdapter;
 
-    public static LocalDeviceNameDialogFragment newInstance() {
-        return new LocalDeviceNameDialogFragment();
-    }
-
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
index 761755c..d1051fe 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
@@ -30,6 +30,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.util.ArrayMap;
+import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
@@ -112,9 +113,12 @@
                 continue;
             }
             final Drawable drawable = mContext.getDrawable(batteryTip.getIconId());
-            drawable.setColorFilter(new PorterDuffColorFilter(
-                    mContext.getResources().getColor(batteryTip.getIconTintColorId()),
-                    PorterDuff.Mode.SRC_IN));
+            final int iconTintColorId = batteryTip.getIconTintColorId();
+            if (iconTintColorId != View.NO_ID) {
+                drawable.setColorFilter(new PorterDuffColorFilter(
+                        mContext.getResources().getColor(iconTintColorId),
+                        PorterDuff.Mode.SRC_IN));
+            }
 
             final IconCompat icon = Utils.createIconWithDrawable(drawable);
             final SliceAction primaryAction = SliceAction.createDeeplink(getPrimaryAction(),
diff --git a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
index c8b5b6d..c37d2b5 100644
--- a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
@@ -16,20 +16,11 @@
 
 package com.android.settings.inputmethod;
 
-import android.annotation.DrawableRes;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.provider.SearchIndexableResource;
 import android.view.inputmethod.InputMethodInfo;
@@ -93,59 +84,12 @@
         return SettingsEnums.ENABLE_VIRTUAL_KEYBOARDS;
     }
 
-    @Nullable
-    private static Drawable loadDrawable(@NonNull final PackageManager packageManager,
-            @NonNull final String packageName, @DrawableRes final int resId,
-            @NonNull final ApplicationInfo applicationInfo) {
-        if (resId == 0) {
-            return null;
-        }
-        try {
-            return packageManager.getDrawable(packageName, resId, applicationInfo);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    @NonNull
-    private static Drawable getInputMethodIcon(@NonNull final PackageManager packageManager,
-            @NonNull final InputMethodInfo imi) {
-        final ServiceInfo si = imi.getServiceInfo();
-        final ApplicationInfo ai = si != null ? si.applicationInfo : null;
-        final String packageName = imi.getPackageName();
-        if (si == null || ai == null || packageName == null) {
-            return new ColorDrawable(Color.TRANSPARENT);
-        }
-        // We do not use ServiceInfo#loadLogo() and ServiceInfo#loadIcon here since those methods
-        // internally have some fallback rules, which we want to do manually.
-        Drawable drawable = loadDrawable(packageManager, packageName, si.logo, ai);
-        if (drawable != null) {
-            return drawable;
-        }
-        drawable = loadDrawable(packageManager, packageName, si.icon, ai);
-        if (drawable != null) {
-            return drawable;
-        }
-        // We do not use ApplicationInfo#loadLogo() and ApplicationInfo#loadIcon here since those
-        // methods internally have some fallback rules, which we want to do manually.
-        drawable = loadDrawable(packageManager, packageName, ai.logo, ai);
-        if (drawable != null) {
-            return drawable;
-        }
-        drawable = loadDrawable(packageManager, packageName, ai.icon, ai);
-        if (drawable != null) {
-            return drawable;
-        }
-        return new ColorDrawable(Color.TRANSPARENT);
-    }
-
     private void updateInputMethodPreferenceViews() {
         mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
         // Clear existing "InputMethodPreference"s
         mInputMethodPreferenceList.clear();
         List<String> permittedList = mDpm.getPermittedInputMethodsForCurrentUser();
         final Context context = getPrefContext();
-        final PackageManager packageManager = getActivity().getPackageManager();
         final List<InputMethodInfo> imis = mInputMethodSettingValues.getInputMethodList();
         final int numImis = (imis == null ? 0 : imis.size());
         for (int i = 0; i < numImis; ++i) {
@@ -154,7 +98,7 @@
                     || permittedList.contains(imi.getPackageName());
             final InputMethodPreference pref = new InputMethodPreference(
                     context, imi, true, isAllowedByOrganization, this);
-            pref.setIcon(getInputMethodIcon(packageManager, imi));
+            pref.setIcon(imi.loadIcon(context.getPackageManager()));
             mInputMethodPreferenceList.add(pref);
         }
         final Collator collator = Collator.getInstance();
diff --git a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
index cb7831e..ef07d11 100644
--- a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
@@ -20,8 +20,6 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.provider.SearchIndexableResource;
@@ -48,7 +46,6 @@
 public final class VirtualKeyboardFragment extends SettingsPreferenceFragment implements Indexable {
 
     private static final String ADD_VIRTUAL_KEYBOARD_SCREEN = "add_virtual_keyboard_screen";
-    private static final Drawable NO_ICON = new ColorDrawable(Color.TRANSPARENT);
 
     private final ArrayList<InputMethodPreference> mInputMethodPreferenceList = new ArrayList<>();
     private InputMethodManager mImm;
@@ -89,14 +86,7 @@
             final InputMethodInfo imi = imis.get(i);
             final boolean isAllowedByOrganization = permittedList == null
                     || permittedList.contains(imi.getPackageName());
-            Drawable icon;
-            try {
-                // TODO: Consider other ways to retrieve an icon to show here.
-                icon = getActivity().getPackageManager().getApplicationIcon(imi.getPackageName());
-            } catch (Exception e) {
-                // TODO: Consider handling the error differently perhaps by showing default icons.
-                icon = NO_ICON;
-            }
+            final Drawable icon = imi.loadIcon(context.getPackageManager());
             final InputMethodPreference pref = new InputMethodPreference(
                     context,
                     imi,
diff --git a/src/com/android/settings/network/telephony/DeleteSimProfileConfirmationDialog.java b/src/com/android/settings/network/telephony/DeleteSimProfileConfirmationDialog.java
new file mode 100644
index 0000000..52c5cc1
--- /dev/null
+++ b/src/com/android/settings/network/telephony/DeleteSimProfileConfirmationDialog.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.network.telephony;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.telephony.SubscriptionInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class DeleteSimProfileConfirmationDialog extends InstrumentedDialogFragment implements
+        DialogInterface.OnClickListener {
+    public static final String TAG = "confirm_delete_sim";
+    public static final String KEY_SUBSCRIPTION_INFO = "subscription_info";
+    private SubscriptionInfo mInfo;
+
+    public static DeleteSimProfileConfirmationDialog newInstance(SubscriptionInfo info) {
+        final DeleteSimProfileConfirmationDialog dialog =
+                new DeleteSimProfileConfirmationDialog();
+        final Bundle args = new Bundle();
+        args.putParcelable(KEY_SUBSCRIPTION_INFO, info);
+        dialog.setArguments(args);
+        return dialog;
+    }
+
+    @NonNull
+    @Override
+    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+        mInfo = getArguments().getParcelable(KEY_SUBSCRIPTION_INFO);
+        Context context = getContext();
+        final String message = context.getString(R.string.mobile_network_erase_sim_dialog_body,
+                mInfo.getCarrierName(), mInfo.getCarrierName());
+        return new AlertDialog.Builder(context)
+                .setTitle(R.string.mobile_network_erase_sim_dialog_title)
+                .setMessage(message)
+                .setNegativeButton(R.string.cancel, null)
+                .setPositiveButton(R.string.mobile_network_erase_sim_dialog_ok, this)
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == DialogInterface.BUTTON_POSITIVE) {
+            beginDeletionWithProgress();
+        }
+    }
+
+    @VisibleForTesting
+    void beginDeletionWithProgress() {
+        final DeleteSimProfileProgressDialog progress =
+                DeleteSimProfileProgressDialog.newInstance(mInfo.getSubscriptionId());
+        progress.setTargetFragment(getTargetFragment(), 0);
+        progress.show(getFragmentManager(), DeleteSimProfileProgressDialog.TAG);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        // TODO(b/131519375) - use a real id here once it's been created in the metrics proto
+        return 0;
+    }
+}
diff --git a/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceController.java b/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceController.java
new file mode 100644
index 0000000..22ff2b6
--- /dev/null
+++ b/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.network.SubscriptionUtil;
+
+/** This controls a preference allowing the user to delete the profile for an eSIM. */
+public class DeleteSimProfilePreferenceController extends BasePreferenceController {
+
+    private SubscriptionInfo mSubscriptionInfo;
+    private Fragment mParentFragment;
+
+    public DeleteSimProfilePreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    public void init(int subscriptionId, Fragment parentFragment) {
+        mParentFragment = parentFragment;
+
+        for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(
+                mContext)) {
+            if (info.getSubscriptionId() == subscriptionId && info.isEmbedded()) {
+                mSubscriptionInfo = info;
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        final Preference pref = screen.findPreference(getPreferenceKey());
+        pref.setOnPreferenceClickListener(p -> {
+            final DeleteSimProfileConfirmationDialog dialogFragment =
+                    DeleteSimProfileConfirmationDialog.newInstance(mSubscriptionInfo);
+            dialogFragment.setTargetFragment(mParentFragment, 0);
+            dialogFragment.show(mParentFragment.getFragmentManager(),
+                    DeleteSimProfileConfirmationDialog.TAG);
+            return true;
+        });
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mSubscriptionInfo != null) {
+            return AVAILABLE;
+        } else {
+            return CONDITIONALLY_UNAVAILABLE;
+        }
+    }
+
+}
diff --git a/src/com/android/settings/network/telephony/DeleteSimProfileProgressDialog.java b/src/com/android/settings/network/telephony/DeleteSimProfileProgressDialog.java
new file mode 100644
index 0000000..15f4b22
--- /dev/null
+++ b/src/com/android/settings/network/telephony/DeleteSimProfileProgressDialog.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.network.telephony;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.PendingIntent;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.telephony.euicc.EuiccManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class DeleteSimProfileProgressDialog extends InstrumentedDialogFragment {
+    public static final String TAG = "delete_sim_progress";
+
+    // Note that this must be listed in AndroidManfiest.xml in a <protected-broadcast> tag
+    @VisibleForTesting
+    static final String PENDING_INTENT =
+            "com.android.settings.DELETE_SIM_PROFILE_RESULT";
+    private static final int PENDING_INTENT_REQUEST_CODE = 1;
+    private static final String KEY_SUBSCRIPTION_ID = "subscription_id";
+    @VisibleForTesting
+    static final String KEY_DELETE_STARTED = "delete_started";
+
+    private boolean mDeleteStarted;
+    private BroadcastReceiver mReceiver;
+
+    public static DeleteSimProfileProgressDialog newInstance(int subscriptionId) {
+        final DeleteSimProfileProgressDialog dialog = new DeleteSimProfileProgressDialog();
+        final Bundle args = new Bundle();
+        args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId);
+        dialog.setArguments(args);
+        return dialog;
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(KEY_DELETE_STARTED, mDeleteStarted);
+    }
+
+    @NonNull
+    @Override
+    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+        if (savedInstanceState != null) {
+            mDeleteStarted = savedInstanceState.getBoolean(KEY_DELETE_STARTED, false);
+        }
+        final Context context = getContext();
+        final ProgressDialog progressDialog = new ProgressDialog(context);
+        progressDialog.setMessage(
+                context.getString(R.string.mobile_network_erase_sim_dialog_progress));
+
+        mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                dismiss();
+                final Activity activity = getActivity();
+                if (activity != null && !activity.isFinishing()) {
+                    activity.finish();
+                }
+            }
+        };
+        context.registerReceiver(mReceiver, new IntentFilter(PENDING_INTENT));
+
+        if (!mDeleteStarted) {
+            final PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
+                    PENDING_INTENT_REQUEST_CODE, new Intent(PENDING_INTENT),
+                    PendingIntent.FLAG_ONE_SHOT);
+
+            final EuiccManager euiccManager = context.getSystemService(EuiccManager.class);
+            final int subId = getArguments().getInt(KEY_SUBSCRIPTION_ID);
+            euiccManager.deleteSubscription(subId, pendingIntent);
+            mDeleteStarted = true;
+        }
+
+        return progressDialog;
+    }
+
+    @Override
+    public void onDismiss(@NonNull DialogInterface dialog) {
+        if (mReceiver != null) {
+            final Context context = getContext();
+            if (context != null) {
+                context.unregisterReceiver(mReceiver);
+            }
+            mReceiver = null;
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        // TODO(b/131519375) - use a real id here once it's been created in the metrics proto
+        return 0;
+    }
+}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index eb00b9f..e18971d 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -138,6 +138,7 @@
             use(BillingCyclePreferenceController.class).init(mSubId);
             use(MmsMessagePreferenceController.class).init(mSubId);
             use(DisabledSubscriptionController.class).init(getLifecycle(), mSubId);
+            use(DeleteSimProfilePreferenceController.class).init(mSubId, this);
         }
         use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
         use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
diff --git a/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
index 9b9de5f..6b95b92 100644
--- a/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
+++ b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
@@ -38,11 +38,6 @@
 import android.view.View;
 import android.widget.ImageView;
 
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceGroup;
-
 import com.android.settings.R;
 import com.android.settings.Settings.TetherSettingsActivity;
 import com.android.settings.core.BasePreferenceController;
@@ -54,6 +49,11 @@
 import java.util.Comparator;
 import java.util.List;
 
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceGroup;
+
 /**
  * {@link BasePreferenceController} that populates a list of widgets that Settings app support.
  */
@@ -143,24 +143,7 @@
     @VisibleForTesting
     Intent createResultIntent(Intent shortcutIntent, ResolveInfo resolveInfo,
             CharSequence label) {
-        final ActivityInfo activityInfo = resolveInfo.activityInfo;
-
-        final Icon maskableIcon;
-        if (activityInfo.icon != 0 && activityInfo.applicationInfo != null) {
-            maskableIcon = Icon.createWithAdaptiveBitmap(createIcon(
-                    activityInfo.applicationInfo, activityInfo.icon,
-                    R.layout.shortcut_badge_maskable,
-                    mContext.getResources().getDimensionPixelSize(R.dimen.shortcut_size_maskable)));
-        } else {
-            maskableIcon = Icon.createWithResource(mContext, R.drawable.ic_launcher_settings);
-        }
-        final String shortcutId = SHORTCUT_ID_PREFIX +
-                shortcutIntent.getComponent().flattenToShortString();
-        ShortcutInfo info = new ShortcutInfo.Builder(mContext, shortcutId)
-                .setShortLabel(label)
-                .setIntent(shortcutIntent)
-                .setIcon(maskableIcon)
-                .build();
+        ShortcutInfo info = createShortcutInfo(mContext, shortcutIntent, resolveInfo, label);
         Intent intent = mShortcutManager.createShortcutResultIntent(info);
         if (intent == null) {
             intent = new Intent();
@@ -170,8 +153,10 @@
                 .putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent)
                 .putExtra(Intent.EXTRA_SHORTCUT_NAME, label);
 
+        final ActivityInfo activityInfo = resolveInfo.activityInfo;
         if (activityInfo.icon != 0) {
             intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(
+                    mContext,
                     activityInfo.applicationInfo,
                     activityInfo.icon,
                     R.layout.shortcut_badge,
@@ -217,15 +202,40 @@
                 info.activityInfo.name);
     }
 
-    private Intent buildShortcutIntent(ResolveInfo info) {
+    private static Intent buildShortcutIntent(ResolveInfo info) {
         return new Intent(SHORTCUT_PROBE)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
                 .setClassName(info.activityInfo.packageName, info.activityInfo.name);
     }
 
-    private Bitmap createIcon(ApplicationInfo app, int resource, int layoutRes, int size) {
-        final Context context = new ContextThemeWrapper(mContext, android.R.style.Theme_Material);
-        final View view = LayoutInflater.from(context).inflate(layoutRes, null);
+    private static ShortcutInfo createShortcutInfo(Context context, Intent shortcutIntent,
+            ResolveInfo resolveInfo, CharSequence label) {
+        final ActivityInfo activityInfo = resolveInfo.activityInfo;
+
+        final Icon maskableIcon;
+        if (activityInfo.icon != 0 && activityInfo.applicationInfo != null) {
+            maskableIcon = Icon.createWithAdaptiveBitmap(createIcon(
+                    context,
+                    activityInfo.applicationInfo, activityInfo.icon,
+                    R.layout.shortcut_badge_maskable,
+                    context.getResources().getDimensionPixelSize(R.dimen.shortcut_size_maskable)));
+        } else {
+            maskableIcon = Icon.createWithResource(context, R.drawable.ic_launcher_settings);
+        }
+        final String shortcutId = SHORTCUT_ID_PREFIX +
+                shortcutIntent.getComponent().flattenToShortString();
+        return new ShortcutInfo.Builder(context, shortcutId)
+                .setShortLabel(label)
+                .setIntent(shortcutIntent)
+                .setIcon(maskableIcon)
+                .build();
+    }
+
+    private static Bitmap createIcon(Context context, ApplicationInfo app, int resource,
+            int layoutRes, int size) {
+        final Context themedContext = new ContextThemeWrapper(context,
+                android.R.style.Theme_Material);
+        final View view = LayoutInflater.from(themedContext).inflate(layoutRes, null);
         final int spec = View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.EXACTLY);
         view.measure(spec, spec);
         final Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
@@ -234,14 +244,15 @@
 
         Drawable iconDrawable;
         try {
-            iconDrawable = mPackageManager.getResourcesForApplication(app).getDrawable(resource);
+            iconDrawable = context.getPackageManager().getResourcesForApplication(app)
+                    .getDrawable(resource);
             if (iconDrawable instanceof LayerDrawable) {
                 iconDrawable = ((LayerDrawable) iconDrawable).getDrawable(1);
             }
             ((ImageView) view.findViewById(android.R.id.icon)).setImageDrawable(iconDrawable);
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "Cannot load icon from app " + app + ", returning a default icon");
-            Icon icon = Icon.createWithResource(mContext, R.drawable.ic_launcher_settings);
+            Icon icon = Icon.createWithResource(context, R.drawable.ic_launcher_settings);
             ((ImageView) view.findViewById(android.R.id.icon)).setImageIcon(icon);
         }
 
@@ -250,12 +261,24 @@
         return bitmap;
     }
 
-    private static final Comparator<ResolveInfo> SHORTCUT_COMPARATOR =
-            new Comparator<ResolveInfo>() {
+    public static void updateRestoredShortcuts(Context context) {
+        ShortcutManager sm = context.getSystemService(ShortcutManager.class);
+        List<ShortcutInfo> updatedShortcuts = new ArrayList<>();
+        for (ShortcutInfo si : sm.getPinnedShortcuts()) {
+            if (si.getId().startsWith(SHORTCUT_ID_PREFIX)) {
+                ResolveInfo ri = context.getPackageManager().resolveActivity(si.getIntent(), 0);
 
-                @Override
-                public int compare(ResolveInfo i1, ResolveInfo i2) {
-                    return i1.priority - i2.priority;
+                if (ri != null) {
+                    updatedShortcuts.add(createShortcutInfo(context, buildShortcutIntent(ri), ri,
+                            si.getShortLabel()));
                 }
-            };
+            }
+        }
+        if (!updatedShortcuts.isEmpty()) {
+            sm.updateShortcuts(updatedShortcuts);
+        }
+    }
+
+    private static final Comparator<ResolveInfo> SHORTCUT_COMPARATOR =
+            (i1, i2) -> i1.priority - i2.priority;
 }
diff --git a/src/com/android/settings/sim/SimSelectNotification.java b/src/com/android/settings/sim/SimSelectNotification.java
index 3179e6a..911d0e8 100644
--- a/src/com/android/settings/sim/SimSelectNotification.java
+++ b/src/com/android/settings/sim/SimSelectNotification.java
@@ -16,12 +16,18 @@
 
 package com.android.settings.sim;
 
+import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS;
+import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS;
+import static android.provider.Settings.EXTRA_ENABLE_MMS_DATA_REQUEST_REASON;
+import static android.provider.Settings.EXTRA_SUB_ID;
 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE;
 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL;
 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA;
 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE;
 import static android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID;
+import static android.telephony.data.ApnSetting.TYPE_MMS;
 
+import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -32,28 +38,97 @@
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
-import com.android.settings.Settings.SimSettingsActivity;
-
-import androidx.core.app.NotificationCompat;
+import com.android.settings.network.telephony.MobileNetworkActivity;
 
 public class SimSelectNotification extends BroadcastReceiver {
     private static final String TAG = "SimSelectNotification";
-    private static final int NOTIFICATION_ID = 1;
+    @VisibleForTesting
+    public static final int SIM_SELECT_NOTIFICATION_ID = 1;
+    @VisibleForTesting
+    public static final int ENABLE_MMS_NOTIFICATION_ID = 2;
 
-    private static final String SIM_SELECT_NOTIFICATION_CHANNEL =
+    @VisibleForTesting
+    public static final String SIM_SELECT_NOTIFICATION_CHANNEL =
             "sim_select_notification_channel";
 
+    @VisibleForTesting
+    public static final String ENABLE_MMS_NOTIFICATION_CHANNEL =
+            "enable_mms_notification_channel";
+
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (!TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED.equals(intent.getAction())) {
+        String action = intent.getAction();
+
+        if (action == null) {
+            Log.w(TAG, "Received unexpected intent with null action.");
             return;
         }
+
+        switch (action) {
+            case TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED:
+                onPrimarySubscriptionListChanged(context, intent);
+                break;
+            case Settings.ACTION_ENABLE_MMS_DATA_REQUEST:
+                onEnableMmsDataRequest(context, intent);
+                break;
+            default:
+                Log.w(TAG, "Received unexpected intent " + intent.getAction());
+        }
+    }
+
+    private void onEnableMmsDataRequest(Context context, Intent intent) {
+        // Getting subId from extra.
+        int subId = intent.getIntExtra(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+            subId = SubscriptionManager.getDefaultSmsSubscriptionId();
+        }
+
+        SubscriptionManager subscriptionManager = ((SubscriptionManager) context.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE));
+        if (!subscriptionManager.isActiveSubId(subId)) {
+            Log.w(TAG, "onEnableMmsDataRequest invalid sub ID " + subId);
+            return;
+        }
+
+        // Getting request reason from extra, which will determine the notification title.
+        CharSequence notificationTitle = null;
+        int requestReason = intent.getIntExtra(EXTRA_ENABLE_MMS_DATA_REQUEST_REASON, -1);
+        if (requestReason == ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS) {
+            notificationTitle = context.getResources().getText(
+                    R.string.enable_receiving_mms_notification_title);
+        } else if (requestReason == ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS) {
+            notificationTitle = context.getResources().getText(
+                    R.string.enable_sending_mms_notification_title);
+        } else {
+            Log.w(TAG, "onEnableMmsDataRequest invalid request reason " + requestReason);
+            return;
+        }
+
+        TelephonyManager tm = ((TelephonyManager) context.getSystemService(
+                Context.TELEPHONY_SERVICE)).createForSubscriptionId(subId);
+
+        if (tm.isDataEnabledForApn(TYPE_MMS)) {
+            Log.w(TAG, "onEnableMmsDataRequest MMS data already enabled on sub ID " + subId);
+            return;
+        }
+
+        CharSequence notificationSummary = context.getResources().getString(
+                R.string.enable_mms_notification_summary, tm.getSimOperatorName());
+
+        cancelEnableMmsNotification(context);
+
+        createEnableMmsNotification(context, notificationTitle, notificationSummary, subId);
+    }
+
+    private void onPrimarySubscriptionListChanged(Context context, Intent intent) {
         // Cancel any previous notifications
-        cancelNotification(context);
+        cancelSimSelectNotification(context);
         // Create a notification to tell the user that some defaults are missing
-        createNotification(context);
+        createSimSelectNotification(context);
 
         int dialogType = intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE,
                 EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE);
@@ -76,20 +151,20 @@
         }
     }
 
-    private void createNotification(Context context){
+    private void createSimSelectNotification(Context context){
         final Resources resources = context.getResources();
 
         NotificationChannel notificationChannel = new NotificationChannel(
                 SIM_SELECT_NOTIFICATION_CHANNEL,
-                resources.getString(R.string.sim_selection_channel_title),
+                resources.getText(R.string.sim_selection_channel_title),
                 NotificationManager.IMPORTANCE_LOW);
 
-        NotificationCompat.Builder builder =
-                new NotificationCompat.Builder(context, SIM_SELECT_NOTIFICATION_CHANNEL)
+        Notification.Builder builder =
+                new Notification.Builder(context, SIM_SELECT_NOTIFICATION_CHANNEL)
                 .setSmallIcon(R.drawable.ic_sim_card_alert_white_48dp)
                 .setColor(context.getColor(R.color.sim_noitification))
-                .setContentTitle(resources.getString(R.string.sim_notification_title))
-                .setContentText(resources.getString(R.string.sim_notification_summary));
+                .setContentTitle(resources.getText(R.string.sim_notification_title))
+                .setContentText(resources.getText(R.string.sim_notification_summary));
         Intent resultIntent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
         resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent,
@@ -98,12 +173,51 @@
         NotificationManager notificationManager =
                 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         notificationManager.createNotificationChannel(notificationChannel);
-        notificationManager.notify(NOTIFICATION_ID, builder.build());
+        notificationManager.notify(SIM_SELECT_NOTIFICATION_ID, builder.build());
     }
 
-    public static void cancelNotification(Context context) {
+    public static void cancelSimSelectNotification(Context context) {
         NotificationManager notificationManager =
                 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        notificationManager.cancel(NOTIFICATION_ID);
+        notificationManager.cancel(SIM_SELECT_NOTIFICATION_ID);
+    }
+
+    private void createEnableMmsNotification(Context context, CharSequence titleString,
+            CharSequence notificationSummary, int subId) {
+        final Resources resources = context.getResources();
+
+        NotificationChannel notificationChannel = new NotificationChannel(
+                ENABLE_MMS_NOTIFICATION_CHANNEL,
+                resources.getText(R.string.enable_mms_notification_channel_title),
+                NotificationManager.IMPORTANCE_HIGH);
+
+        Notification.Builder builder =
+                new Notification.Builder(context, ENABLE_MMS_NOTIFICATION_CHANNEL)
+                        .setSmallIcon(R.drawable.ic_settings_24dp)
+                        .setColor(context.getColor(R.color.sim_noitification))
+                        .setContentTitle(titleString)
+                        .setContentText(notificationSummary)
+                        .setStyle(new Notification.BigTextStyle().bigText(notificationSummary));
+
+        // Create the pending intent that will lead to the subscription setting page.
+        Intent resultIntent = new Intent(Settings.ACTION_MMS_MESSAGE_SETTING);
+        resultIntent.setClass(context, MobileNetworkActivity.class);
+        resultIntent.putExtra(Settings.EXTRA_SUB_ID, subId);
+        resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+        builder.setContentIntent(resultPendingIntent);
+
+        // Notify the notification.
+        NotificationManager notificationManager =
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager.createNotificationChannel(notificationChannel);
+        notificationManager.notify(ENABLE_MMS_NOTIFICATION_ID, builder.build());
+    }
+
+    private void cancelEnableMmsNotification(Context context) {
+        NotificationManager notificationManager =
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager.cancel(ENABLE_MMS_NOTIFICATION_ID);
     }
 }
diff --git a/src/com/android/settings/sim/SimSettings.java b/src/com/android/settings/sim/SimSettings.java
index e43c6a5..1222913 100644
--- a/src/com/android/settings/sim/SimSettings.java
+++ b/src/com/android/settings/sim/SimSettings.java
@@ -101,7 +101,7 @@
         mSimCards = (PreferenceScreen)findPreference(SIM_CARD_CATEGORY);
         mAvailableSubInfos = new ArrayList<SubscriptionInfo>(mNumSlots);
         mSelectableSubInfos = new ArrayList<SubscriptionInfo>();
-        SimSelectNotification.cancelNotification(getActivity());
+        SimSelectNotification.cancelSimSelectNotification(getActivity());
     }
 
     private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
index 0da0f21..5b70d16 100644
--- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java
+++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
@@ -17,7 +17,6 @@
 package com.android.settings.sound;
 
 import static android.media.AudioManager.STREAM_DEVICES_CHANGED_ACTION;
-import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
 
 import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
@@ -29,7 +28,6 @@
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.MediaRouter;
-import android.media.MediaRouter.Callback;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.FeatureFlagUtils;
@@ -76,7 +74,6 @@
     protected AudioSwitchCallback mAudioSwitchPreferenceCallback;
 
     private final AudioManagerAudioDeviceCallback mAudioManagerAudioDeviceCallback;
-    private final MediaRouterCallback mMediaRouterCallback;
     private final WiredHeadsetBroadcastReceiver mReceiver;
     private final Handler mHandler;
     private LocalBluetoothManager mLocalBluetoothManager;
@@ -92,7 +89,6 @@
         mHandler = new Handler(Looper.getMainLooper());
         mAudioManagerAudioDeviceCallback = new AudioManagerAudioDeviceCallback();
         mReceiver = new WiredHeadsetBroadcastReceiver();
-        mMediaRouterCallback = new MediaRouterCallback();
         mConnectedDevices = new ArrayList<>();
         final FutureTask<LocalBluetoothManager> localBtManagerFutureTask = new FutureTask<>(
                 // Avoid StrictMode ThreadPolicy violation
@@ -210,12 +206,12 @@
      * get A2dp devices on all states
      * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
      */
-    protected List<BluetoothDevice> getConnectableA2dpDevices() {
+    protected List<BluetoothDevice> getConnectedA2dpDevices() {
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
         if (a2dpProfile == null) {
             return new ArrayList<>();
         }
-        return a2dpProfile.getConnectableDevices();
+        return a2dpProfile.getConnectedDevices();
     }
 
     /**
@@ -242,31 +238,6 @@
     }
 
     /**
-     * get hearing aid profile devices on all states
-     * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
-     * exclude other devices with same hiSyncId.
-     */
-    protected List<BluetoothDevice> getConnectableHearingAidDevices() {
-        final List<BluetoothDevice> connectedDevices = new ArrayList<>();
-        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
-        if (hapProfile == null) {
-            return connectedDevices;
-        }
-        final List<Long> devicesHiSyncIds = new ArrayList<>();
-        final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
-        for (BluetoothDevice device : devices) {
-            final long hiSyncId = hapProfile.getHiSyncId(device);
-            // device with same hiSyncId should not be shown in the UI.
-            // So do not add it into connectedDevices.
-            if (!devicesHiSyncIds.contains(hiSyncId)) {
-                devicesHiSyncIds.add(hiSyncId);
-                connectedDevices.add(device);
-            }
-        }
-        return connectedDevices;
-    }
-
-    /**
      * Find active hearing aid device
      */
     protected BluetoothDevice findActiveHearingAidDevice() {
@@ -299,7 +270,6 @@
     private void register() {
         mLocalBluetoothManager.getEventManager().registerCallback(this);
         mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler);
-        mMediaRouter.addCallback(ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback);
 
         // Register for misc other intent broadcasts.
         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
@@ -310,7 +280,6 @@
     private void unregister() {
         mLocalBluetoothManager.getEventManager().unregisterCallback(this);
         mAudioManager.unregisterAudioDeviceCallback(mAudioManagerAudioDeviceCallback);
-        mMediaRouter.removeCallback(mMediaRouterCallback);
         mContext.unregisterReceiver(mReceiver);
     }
 
@@ -338,49 +307,4 @@
             }
         }
     }
-
-    /** Callback for cast device events. */
-    private class MediaRouterCallback extends Callback {
-        @Override
-        public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
-        }
-
-        @Override
-        public void onRouteUnselected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
-        }
-
-        @Override
-        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
-            if (info != null && !info.isDefault()) {
-                // cast mode
-                updateState(mPreference);
-            }
-        }
-
-        @Override
-        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
-        }
-
-        @Override
-        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
-            if (info != null && !info.isDefault()) {
-                // cast mode
-                updateState(mPreference);
-            }
-        }
-
-        @Override
-        public void onRouteGrouped(MediaRouter router, MediaRouter.RouteInfo info,
-                MediaRouter.RouteGroup group, int index) {
-        }
-
-        @Override
-        public void onRouteUngrouped(MediaRouter router, MediaRouter.RouteInfo info,
-                MediaRouter.RouteGroup group) {
-        }
-
-        @Override
-        public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo info) {
-        }
-    }
 }
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index 47810f7..1831ad6 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -16,9 +16,6 @@
 
 package com.android.settings.sound;
 
-import static android.media.AudioManager.STREAM_MUSIC;
-import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
-
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.content.Intent;
@@ -56,13 +53,6 @@
             return;
         }
 
-        if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_REMOTE_SUBMIX)) {
-            // In cast mode, disable switch entry.
-            mPreference.setVisible(false);
-            preference.setSummary(mContext.getText(R.string.media_output_summary_unavailable));
-            return;
-        }
-
         if (Utils.isAudioModeOngoingCall(mContext)) {
             // Ongoing call status, switch entry for media will be disabled.
             mPreference.setVisible(false);
@@ -71,19 +61,19 @@
             return;
         }
 
-        boolean deviceConnectable = false;
+        boolean deviceConnected = false;
         BluetoothDevice activeDevice = null;
         // Show preference if there is connected or previously connected device
         // Find active device and set its name as the preference's summary
-        List<BluetoothDevice> connectableA2dpDevices = getConnectableA2dpDevices();
-        List<BluetoothDevice> connectableHADevices = getConnectableHearingAidDevices();
+        List<BluetoothDevice> connectedA2dpDevices = getConnectedA2dpDevices();
+        List<BluetoothDevice> connectedHADevices = getConnectedHearingAidDevices();
         if (mAudioManager.getMode() == AudioManager.MODE_NORMAL
-                && ((connectableA2dpDevices != null && !connectableA2dpDevices.isEmpty())
-                || (connectableHADevices != null && !connectableHADevices.isEmpty()))) {
-            deviceConnectable = true;
+                && ((connectedA2dpDevices != null && !connectedA2dpDevices.isEmpty())
+                || (connectedHADevices != null && !connectedHADevices.isEmpty()))) {
+            deviceConnected = true;
             activeDevice = findActiveDevice();
         }
-        mPreference.setVisible(deviceConnectable);
+        mPreference.setVisible(deviceConnected);
         mPreference.setSummary((activeDevice == null) ?
                 mContext.getText(R.string.media_output_default_summary) :
                 activeDevice.getAliasName());
diff --git a/tests/robotests/src/com/android/settings/bluetooth/LocalDeviceNameDialogFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/LocalDeviceNameDialogFragmentTest.java
deleted file mode 100644
index 9a6ad91..0000000
--- a/tests/robotests/src/com/android/settings/bluetooth/LocalDeviceNameDialogFragmentTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.FragmentActivity;
-
-import com.android.settings.R;
-import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.androidx.fragment.FragmentController;
-import org.robolectric.util.ReflectionHelpers;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowAlertDialogCompat.class)
-public class LocalDeviceNameDialogFragmentTest {
-
-    @Mock
-    private InputMethodManager mInputMethodManager;
-
-    private Context mContext;
-    private LocalDeviceNameDialogFragment mFragment;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(RuntimeEnvironment.application);
-        doReturn(mInputMethodManager).when(mContext).getSystemService(Context.INPUT_METHOD_SERVICE);
-
-        mFragment = spy(LocalDeviceNameDialogFragment.newInstance());
-        when(mFragment.getContext()).thenReturn(mContext);
-    }
-
-    @After
-    public void tearDown() {
-        ReflectionHelpers.setStaticField(LocalBluetoothManager.class, "sInstance", null);
-    }
-
-    @Test
-    @Ignore("b/120505691")
-    public void dialogTriggersShowSoftInput() {
-        FragmentController.setupFragment(mFragment, FragmentActivity.class, 0 /* containerViewId */,
-                null /* bundle */);
-        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-        assertThat(dialog).isNotNull();
-        View view = dialog.findViewById(R.id.edittext);
-        verify(mInputMethodManager).showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfileConfirmationDialogTest.java b/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfileConfirmationDialogTest.java
new file mode 100644
index 0000000..9b6f551
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfileConfirmationDialogTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.network.telephony;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.telephony.SubscriptionInfo;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowAlertDialogCompat.class)
+public class DeleteSimProfileConfirmationDialogTest {
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo;
+
+    private DeleteSimProfileConfirmationDialog mDialogFragment;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mDialogFragment = spy(DeleteSimProfileConfirmationDialog.newInstance(mSubscriptionInfo));
+        doNothing().when(mDialogFragment).beginDeletionWithProgress();
+    }
+
+    @Test
+    public void showDialog_dialogCancelled_deleteNotCalled() {
+        FragmentController.setupFragment(mDialogFragment, FragmentActivity.class,
+                0 /* containerViewId */,
+                null /* bundle */);
+        final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        dialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
+        verify(mDialogFragment, never()).beginDeletionWithProgress();
+    }
+
+    @Test
+    public void showDialog_dialogOk_deleteWasCalled() {
+        FragmentController.setupFragment(mDialogFragment, FragmentActivity.class,
+                0 /* containerViewId */,
+                null /* bundle */);
+        final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        verify(mDialogFragment).beginDeletionWithProgress();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceControllerTest.java
new file mode 100644
index 0000000..21fd19b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceControllerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.euicc.EuiccManager;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.network.SubscriptionUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(RobolectricTestRunner.class)
+public class DeleteSimProfilePreferenceControllerTest {
+    private static final String PREF_KEY = "delete_profile_key";
+    private static final int SUB_ID = 1234;
+    private static final int OTHER_ID = 5678;
+
+    @Mock
+    private Fragment mFragment;
+
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private Preference mPreference;
+    private DeleteSimProfilePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscriptionInfo));
+        when(mSubscriptionInfo.getSubscriptionId()).thenReturn(SUB_ID);
+        when(mSubscriptionInfo.isEmbedded()).thenReturn(true);
+
+        mPreference = new Preference(mContext);
+        mPreference.setKey(PREF_KEY);
+        when(mScreen.findPreference(PREF_KEY)).thenReturn(mPreference);
+
+        mController = new DeleteSimProfilePreferenceController(mContext, PREF_KEY);
+    }
+
+    @After
+    public void tearDown() {
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
+    }
+
+    @Test
+    public void getAvailabilityStatus_noSubs_notAvailable() {
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(new ArrayList<>());
+        mController.init(SUB_ID, mFragment);
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void getAvailabilityStatus_physicalSim_notAvailable() {
+        when(mSubscriptionInfo.isEmbedded()).thenReturn(false);
+        mController.init(SUB_ID, mFragment);
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void getAvailabilityStatus_unknownSim_notAvailable() {
+        when(mSubscriptionInfo.getSubscriptionId()).thenReturn(OTHER_ID);
+        mController.init(SUB_ID, mFragment);
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void getAvailabilityStatus_knownEsim_isAvailable() {
+        mController.init(SUB_ID, mFragment);
+        assertThat(mController.isAvailable()).isTrue();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfileProgressDialogTest.java b/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfileProgressDialogTest.java
new file mode 100644
index 0000000..aebcc46
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/telephony/DeleteSimProfileProgressDialogTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.network.telephony;
+
+import static com.android.settings.network.telephony.DeleteSimProfileProgressDialog.KEY_DELETE_STARTED;
+import static com.android.settings.network.telephony.DeleteSimProfileProgressDialog.PENDING_INTENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Dialog;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.telephony.euicc.EuiccManager;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowAlertDialogCompat.class)
+public class DeleteSimProfileProgressDialogTest {
+    private static final int SUB_ID = 111;
+
+    @Mock
+    private FragmentActivity mActivity;
+    @Mock
+    private Fragment mTargetFragment;
+    @Mock
+    private EuiccManager mEuiccManager;
+
+    private Context mContext;
+    private DeleteSimProfileProgressDialog mDialogFragment;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+
+        when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
+        mDialogFragment = spy(DeleteSimProfileProgressDialog.newInstance(SUB_ID));
+        when(mDialogFragment.getContext()).thenReturn(mContext);
+        when(mDialogFragment.getTargetFragment()).thenReturn(mTargetFragment);
+        when(mDialogFragment.getActivity()).thenReturn(mActivity);
+    }
+
+    @Test
+    public void onCreateDialog_firstShowing_deleteStartedAndRecordedInOutState() {
+        mDialogFragment.onCreateDialog(null);
+        verify(mEuiccManager).deleteSubscription(eq(SUB_ID), notNull());
+
+        final Bundle outState = new Bundle();
+        mDialogFragment.onSaveInstanceState(outState);
+        assertThat(outState.containsKey(KEY_DELETE_STARTED)).isTrue();
+        assertThat(outState.getBoolean(KEY_DELETE_STARTED)).isTrue();
+    }
+
+    @Test
+    public void showDialog_secondShowing_deleteNotStarted() {
+        final Bundle inState = new Bundle();
+        inState.putBoolean(KEY_DELETE_STARTED, true);
+        mDialogFragment.onCreateDialog(inState);
+
+        verify(mEuiccManager, never()).deleteSubscription(anyInt(), any());
+
+        final Bundle outState = new Bundle();
+        mDialogFragment.onSaveInstanceState(outState);
+        assertThat(outState.containsKey(KEY_DELETE_STARTED)).isTrue();
+        assertThat(outState.getBoolean(KEY_DELETE_STARTED)).isTrue();
+    }
+
+    @Test
+    public void showDialog_pendingIntentReceiverFired_activityFinished() {
+        mDialogFragment.onCreateDialog(null);
+
+        final ArgumentCaptor<PendingIntent> intentCaptor = ArgumentCaptor.forClass(
+                PendingIntent.class);
+        verify(mEuiccManager).deleteSubscription(eq(SUB_ID), intentCaptor.capture());
+        assertThat(intentCaptor.getValue()).isNotNull();
+
+        final ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(
+                BroadcastReceiver.class);
+        verify(mContext).registerReceiver(receiverCaptor.capture(), any(IntentFilter.class));
+
+        doNothing().when(mDialogFragment).dismiss();
+        receiverCaptor.getValue().onReceive(mContext, new Intent(PENDING_INTENT));
+        verify(mDialogFragment).dismiss();
+        verify(mActivity).finish();
+    }
+
+    @Test
+    public void onDismiss_receiverUnregistered() {
+        Dialog dialog = mDialogFragment.onCreateDialog(null);
+        final ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(
+                BroadcastReceiver.class);
+        verify(mContext).registerReceiver(receiverCaptor.capture(), any(IntentFilter.class));
+
+        mDialogFragment.onDismiss(dialog);
+        verify(mContext).unregisterReceiver(eq(receiverCaptor.getValue()));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
new file mode 100644
index 0000000..69c0919
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.settings.sim;
+
+
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS;
+import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS;
+import static android.provider.Settings.EXTRA_ENABLE_MMS_DATA_REQUEST_REASON;
+import static android.provider.Settings.EXTRA_SUB_ID;
+import static android.telephony.data.ApnSetting.TYPE_MMS;
+
+import static com.android.settings.sim.SimSelectNotification.ENABLE_MMS_NOTIFICATION_CHANNEL;
+import static com.android.settings.sim.SimSelectNotification.ENABLE_MMS_NOTIFICATION_ID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.settings.R;
+
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowAlertDialogCompat.class)
+public class SimSelectNotificationTest {
+    @Mock
+    private Context mContext;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private Resources mResources;
+
+    private String mFakeOperatorName = "fake_operator_name";
+    private CharSequence mFakeNotificationChannelTitle = "fake_notification_channel_title";
+    private CharSequence mFakeNotificationTitle = "fake_notification_title";
+    private String mFakeNotificationSummary = "fake_notification_Summary";
+
+    private int mSubId = 1;
+
+    SimSelectNotification mSimSelectNotification = new SimSelectNotification();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+                .thenReturn(mNotificationManager);
+        when(mContext.getSystemService(Context.TELEPHONY_SERVICE))
+                .thenReturn(mTelephonyManager);
+        when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE))
+                .thenReturn(mSubscriptionManager);
+        when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.checkPermission(any(), any()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+        when(mTelephonyManager.getSimOperatorName()).thenReturn(mFakeOperatorName);
+        when(mTelephonyManager.isDataEnabledForApn(TYPE_MMS)).thenReturn(false);
+        when(mSubscriptionManager.isActiveSubId(mSubId)).thenReturn(true);
+        when(mContext.getResources()).thenReturn(mResources);
+
+        when(mResources.getText(R.string.enable_sending_mms_notification_title))
+                .thenReturn(mFakeNotificationTitle);
+        when(mResources.getText(R.string.enable_mms_notification_channel_title))
+                .thenReturn(mFakeNotificationChannelTitle);
+        when(mResources.getString(R.string.enable_mms_notification_summary,
+                mFakeOperatorName)).thenReturn(mFakeNotificationSummary);
+    }
+
+    @Test
+    public void onReceiveEnableMms_notificationShouldSend() {
+        Intent intent = new Intent(Settings.ACTION_ENABLE_MMS_DATA_REQUEST);
+        intent.putExtra(EXTRA_SUB_ID, mSubId);
+        intent.putExtra(EXTRA_ENABLE_MMS_DATA_REQUEST_REASON,
+                ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS);
+
+        mSimSelectNotification.onReceive(mContext, intent);
+
+        // Capture the notification channel created and verify its fields.
+        ArgumentCaptor<NotificationChannel> nc = ArgumentCaptor.forClass(NotificationChannel.class);
+        verify(mNotificationManager).createNotificationChannel(nc.capture());
+
+        assertThat(nc.getValue().getId()).isEqualTo(ENABLE_MMS_NOTIFICATION_CHANNEL);
+        assertThat(nc.getValue().getName()).isEqualTo(mFakeNotificationChannelTitle);
+        assertThat(nc.getValue().getImportance()).isEqualTo(IMPORTANCE_HIGH);
+
+        // Capture the notification it notifies and verify its fields.
+        ArgumentCaptor<Notification> notification = ArgumentCaptor.forClass(Notification.class);
+        verify(mNotificationManager).notify(
+                eq(ENABLE_MMS_NOTIFICATION_ID), notification.capture());
+        assertThat(notification.getValue().extras.getCharSequence(Notification.EXTRA_TITLE))
+                .isEqualTo(mFakeNotificationTitle);
+        assertThat(notification.getValue().extras.getCharSequence(Notification.EXTRA_BIG_TEXT))
+                .isEqualTo(mFakeNotificationSummary);
+        assertThat(notification.getValue().contentIntent).isNotNull();
+    }
+
+    @Test
+    public void onReceiveEnableMms_NoExtra_notificationShouldNotSend() {
+        Intent intent = new Intent(Settings.ACTION_ENABLE_MMS_DATA_REQUEST);
+
+        // EXTRA_SUB_ID and EXTRA_ENABLE_MMS_DATA_REQUEST_REASON are required.
+        mSimSelectNotification.onReceive(mContext, intent);
+        verify(mNotificationManager, never()).createNotificationChannel(any());
+    }
+
+    @Test
+    public void onReceiveEnableMms_MmsDataAlreadyEnabled_notificationShouldNotSend() {
+        when(mTelephonyManager.isDataEnabledForApn(TYPE_MMS)).thenReturn(true);
+        Intent intent = new Intent(Settings.ACTION_ENABLE_MMS_DATA_REQUEST);
+        intent.putExtra(EXTRA_SUB_ID, mSubId);
+        intent.putExtra(EXTRA_ENABLE_MMS_DATA_REQUEST_REASON,
+                ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS);
+
+        // If MMS data is already enabled, there's no need to trigger the notification.
+        mSimSelectNotification.onReceive(mContext, intent);
+        verify(mNotificationManager, never()).createNotificationChannel(any());
+    }
+}
+
diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
index 7fcd3d2..51264c1 100644
--- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
@@ -109,7 +109,7 @@
     private BluetoothDevice mRightBluetoothHapDevice;
     private LocalBluetoothManager mLocalBluetoothManager;
     private MediaOutputPreferenceController mController;
-    private List<BluetoothDevice> mProfileConnectableDevices;
+    private List<BluetoothDevice> mProfileConnectedDevices;
     private List<BluetoothDevice> mHearingAidActiveDevices;
 
     @Before
@@ -150,7 +150,7 @@
         mController = new MediaOutputPreferenceController(mContext, TEST_KEY);
         mScreen = spy(new PreferenceScreen(mContext, null));
         mPreference = new Preference(mContext);
-        mProfileConnectableDevices = new ArrayList<>();
+        mProfileConnectedDevices = new ArrayList<>();
         mHearingAidActiveDevices = new ArrayList<>(2);
 
         when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
@@ -172,11 +172,11 @@
      * Preference should be invisible
      */
     @Test
-    public void updateState_withoutConnectableBtDevice_preferenceInvisible() {
+    public void updateState_withoutConnectedBtDevice_preferenceInvisible() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectableDevices.clear();
-        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        mProfileConnectedDevices.clear();
+        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
         mPreference.setVisible(true);
 
         assertThat(mPreference.isVisible()).isTrue();
@@ -185,16 +185,16 @@
     }
 
     /**
-     * A2DP Bluetooth device(s) are connectable, no matter active or inactive
+     * A2DP Bluetooth device(s) are connected, no matter active or inactive
      * Preference should be visible
      */
     @Test
-    public void updateState_withConnectableBtDevice_preferenceVisible() {
+    public void updateState_withConnectedBtDevice_preferenceVisible() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectableDevices.clear();
-        mProfileConnectableDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        mProfileConnectedDevices.clear();
+        mProfileConnectedDevices.add(mBluetoothDevice);
+        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
         assertThat(mPreference.isVisible()).isFalse();
 
         // Without Active Bluetooth Device
@@ -208,17 +208,17 @@
     }
 
     /**
-     * A2DP Bluetooth device(s) are connectable, but no device is set as activated
+     * A2DP Bluetooth device(s) are connected, but no device is set as activated
      * Preference summary should be "This device"
      */
     @Test
-    public void updateState_withConnectableBtDevice_withoutActiveBtDevice_setDefaultSummary() {
+    public void updateState_withConnectedBtDevice_withoutActiveBtDevice_setDefaultSummary() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectableDevices.clear();
-        mProfileConnectableDevices.add(mBluetoothDevice);
-        mProfileConnectableDevices.add(mSecondBluetoothDevice);
-        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        mProfileConnectedDevices.clear();
+        mProfileConnectedDevices.add(mBluetoothDevice);
+        mProfileConnectedDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
         when(mA2dpProfile.getActiveDevice()).thenReturn(null);
 
         assertThat(mPreference.getSummary()).isNull();
@@ -235,10 +235,10 @@
     public void updateState_withActiveBtDevice_setActivatedDeviceName() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectableDevices.clear();
-        mProfileConnectableDevices.add(mBluetoothDevice);
-        mProfileConnectableDevices.add(mSecondBluetoothDevice);
-        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        mProfileConnectedDevices.clear();
+        mProfileConnectedDevices.add(mBluetoothDevice);
+        mProfileConnectedDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
         when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
 
         assertThat(mPreference.getSummary()).isNull();
@@ -248,16 +248,16 @@
 
 
     /**
-     * Hearing Aid device(s) are connectable, no matter active or inactive
+     * Hearing Aid device(s) are connected, no matter active or inactive
      * Preference should be visible
      */
     @Test
-    public void updateState_withConnectableHADevice_preferenceVisible() {
+    public void updateState_withConnectedHADevice_preferenceVisible() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
         mHearingAidActiveDevices.clear();
         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
+        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mHearingAidActiveDevices);
         assertThat(mPreference.isVisible()).isFalse();
 
         // Without Active Hearing Aid Device
@@ -280,7 +280,7 @@
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
         mHearingAidActiveDevices.clear();
         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
+        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mHearingAidActiveDevices);
         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
 
         assertThat(mPreference.getSummary()).isNull();
@@ -332,22 +332,6 @@
                 mContext.getText(R.string.media_out_summary_ongoing_call_state));
     }
 
-    /**
-     * Media stream is captured by something else (cast device):
-     * Preference should be invisible
-     * Preference summary should be "unavailable"
-     */
-    @Test
-    public void updateState_mediaStreamIsCapturedByCast_shouldDisableAndSetDefaultSummary() {
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_REMOTE_SUBMIX);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isFalse();
-        String defaultString = mContext.getString(R.string.media_output_summary_unavailable);
-        assertThat(mPreference.getSummary()).isEqualTo(defaultString);
-    }
-
     @Test
     public void findActiveDevice_onlyA2dpDeviceActive_returnA2dpDevice() {
         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);