Merge "Fix Settings crash on changing device orientation"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bc832ef..1ffdba1 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -111,13 +111,9 @@
         <uses-library android:name="org.apache.http.legacy" />
         <!-- Settings -->
 
-        <activity android:name="Settings"
+        <activity android:name="SettingsActivity"
                 android:label="@string/settings_label_launcher"
                 android:launchMode="singleTask">
-            <intent-filter android:priority="1">
-                <action android:name="android.settings.SETTINGS" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
             <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
                 android:value="true" />
         </activity>
@@ -126,6 +122,12 @@
                   android:label="@string/settings_label_launcher"
                   android:theme="@style/Theme.Settings.Home"
                   android:launchMode="singleTask">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                       android:value="true" />
         </activity>
 
         <activity android:name=".network.telephony.MobileSettingsActivity"
@@ -2974,15 +2976,12 @@
 
         <receiver
             android:name=".slices.SliceBroadcastReceiver"
-            android:exported="false">
-        </receiver>
+            android:exported="false" />
 
         <receiver
             android:name=".slices.SliceRelayReceiver"
             android:permission="android.permission.MANAGE_SLICE_PERMISSIONS"
-            android:exported="true">
-
-        </receiver>
+            android:exported="true" />
 
         <!-- Couldn't be triggered from outside of settings. Statsd can trigger it because we send
              PendingIntent to it-->
diff --git a/res/layout/fingerprint_rename_dialog.xml b/res/layout/fingerprint_rename_dialog.xml
index 99cfa71..2da84ca 100644
--- a/res/layout/fingerprint_rename_dialog.xml
+++ b/res/layout/fingerprint_rename_dialog.xml
@@ -35,7 +35,7 @@
         android:clipChildren="false"
         android:clipToPadding="false" />
 
-    <EditText
+    <com.android.settings.widget.ImeAwareEditText
         android:id="@+id/fingerprint_rename_field"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f18ec41..f2661bd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10264,4 +10264,12 @@
     <string name="see_more">See more</string>
     <!-- See less items in contextual homepage [CHAR LIMIT=30]-->
     <string name="see_less">See less</string>
+
+    <!-- Summary for connected devices count in connected device slice. [CHAR LIMIT=NONE] -->
+    <plurals name="show_connected_devices">
+        <item quantity="one"><xliff:g id="number_device_count">%1$d</xliff:g> device connected</item>
+        <item quantity="other"><xliff:g id="number_device_count">%1$d</xliff:g> devices connected</item>
+    </plurals>
+    <!-- Title for no connected devices in connected device slice. [CHAR LIMIT=NONE] -->
+    <string name="no_connected_devices">No connected devices</string>
 </resources>
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index 4a24154..e76cdb7 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -20,21 +20,17 @@
     android:key="tts_settings_screen"
     android:title="@string/tts_settings_title">
 
-    <PreferenceCategory android:key="tts_engine_section">
+   <com.android.settings.widget.GearPreference
+       android:key="tts_engine_preference"
+       android:title="@string/tts_engine_preference_title"
+       android:fragment="com.android.settings.tts.TtsEnginePreferenceFragment"
+       settings:searchable="false"/>
 
-        <com.android.settings.widget.GearPreference
-            android:key="tts_engine_preference"
-            android:title="@string/tts_engine_preference_title"
-            android:fragment="com.android.settings.tts.TtsEnginePreferenceFragment"
-            settings:searchable="false"/>
-
-        <ListPreference
-            android:key="tts_default_lang"
-            android:title="@string/tts_default_lang_title"
-            android:summary="@string/tts_default_lang_summary"
-            android:persistent="false" />
-
-    </PreferenceCategory>
+   <ListPreference
+       android:key="tts_default_lang"
+       android:title="@string/tts_default_lang_title"
+       android:summary="@string/tts_default_lang_summary"
+       android:persistent="false" />
 
     <PreferenceCategory android:key="tts_general_section">
 
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 8881fc2..8ed368c 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -16,8 +16,6 @@
 
 package com.android.settings;
 
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
-
 import android.app.ActionBar;
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
@@ -248,10 +246,8 @@
         // Getting Intent properties can only be done after the super.onCreate(...)
         final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
 
-        final ComponentName cn = intent.getComponent();
-        final String className = cn.getClassName();
-
-        mIsShowingDashboard = className.equals(Settings.class.getName());
+        mIsShowingDashboard = TextUtils.equals(
+                SettingsActivity.class.getName(), intent.getComponent().getClassName());
 
         // This is a "Sub Settings" when:
         // - this is a real SubSettings
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index c3bd043..2e67ec3 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -55,6 +55,7 @@
 import com.android.settings.password.ChooseLockGeneric;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.utils.AnnotationSpan;
+import com.android.settings.widget.ImeAwareEditText;
 import com.android.settingslib.HelpUtils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -708,11 +709,7 @@
         public static class RenameDialog extends InstrumentedDialogFragment {
 
             private Fingerprint mFp;
-            private EditText mDialogTextField;
-            private String mFingerName;
-            private Boolean mTextHadFocus;
-            private int mTextSelectionStart;
-            private int mTextSelectionEnd;
+            private ImeAwareEditText mDialogTextField;
             private AlertDialog mAlertDialog;
             private boolean mDeleteInProgress;
 
@@ -723,11 +720,17 @@
             @Override
             public Dialog onCreateDialog(Bundle savedInstanceState) {
                 mFp = getArguments().getParcelable("fingerprint");
+                final String fingerName;
+                final int textSelectionStart;
+                final int textSelectionEnd;
                 if (savedInstanceState != null) {
-                    mFingerName = savedInstanceState.getString("fingerName");
-                    mTextHadFocus = savedInstanceState.getBoolean("textHadFocus");
-                    mTextSelectionStart = savedInstanceState.getInt("startSelection");
-                    mTextSelectionEnd = savedInstanceState.getInt("endSelection");
+                    fingerName = savedInstanceState.getString("fingerName");
+                    textSelectionStart = savedInstanceState.getInt("startSelection", -1);
+                    textSelectionEnd = savedInstanceState.getInt("endSelection", -1);
+                } else {
+                    fingerName = null;
+                    textSelectionStart = -1;
+                    textSelectionEnd = -1;
                 }
                 mAlertDialog = new AlertDialog.Builder(getActivity())
                         .setView(R.layout.fingerprint_rename_dialog)
@@ -756,26 +759,21 @@
                 mAlertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
                     @Override
                     public void onShow(DialogInterface dialog) {
-                        mDialogTextField = (EditText) mAlertDialog.findViewById(
-                                R.id.fingerprint_rename_field);
-                        CharSequence name = mFingerName == null ? mFp.getName() : mFingerName;
+                        mDialogTextField = mAlertDialog.findViewById(R.id.fingerprint_rename_field);
+                        CharSequence name = fingerName == null ? mFp.getName() : fingerName;
                         mDialogTextField.setText(name);
-                        if (mTextHadFocus == null) {
-                            mDialogTextField.selectAll();
+                        if (textSelectionStart != -1 && textSelectionEnd != -1) {
+                            mDialogTextField.setSelection(textSelectionStart, textSelectionEnd);
                         } else {
-                            mDialogTextField.setSelection(mTextSelectionStart, mTextSelectionEnd);
+                            mDialogTextField.selectAll();
                         }
                         if (mDeleteInProgress) {
                             mAlertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false);
                         }
                         mDialogTextField.requestFocus();
+                        mDialogTextField.scheduleShowSoftInput();
                     }
                 });
-                if (mTextHadFocus == null || mTextHadFocus) {
-                    // Request the IME
-                    mAlertDialog.getWindow().setSoftInputMode(
-                            WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
-                }
                 return mAlertDialog;
             }
 
@@ -791,7 +789,6 @@
                 super.onSaveInstanceState(outState);
                 if (mDialogTextField != null) {
                     outState.putString("fingerName", mDialogTextField.getText().toString());
-                    outState.putBoolean("textHadFocus", mDialogTextField.hasFocus());
                     outState.putInt("startSelection", mDialogTextField.getSelectionStart());
                     outState.putInt("endSelection", mDialogTextField.getSelectionEnd());
                 }
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index be59ca1..0cda9ee 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -321,6 +321,12 @@
         displayResourceTiles();
 
         refreshDashboardTiles(TAG);
+
+        final Activity activity = getActivity();
+        if (activity != null) {
+            Log.d(TAG, "All preferences added, reporting fully drawn");
+            activity.reportFullyDrawn();
+        }
     }
 
     /**
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index b3d1aa4..c10543d 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.homepage;
 
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.FeatureFlagUtils;
@@ -27,6 +26,7 @@
 import androidx.fragment.app.FragmentTransaction;
 
 import com.android.settings.R;
+import com.android.settings.SettingsActivity;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.core.SettingsBaseActivity;
 import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
@@ -38,9 +38,8 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        if (!isDynamicHomepageEnabled(this)) {
-            final Intent settings = new Intent();
-            settings.setAction("android.settings.SETTINGS");
+        if (!FeatureFlagUtils.isEnabled(this, FeatureFlags.DYNAMIC_HOMEPAGE)) {
+            final Intent settings = new Intent(this, SettingsActivity.class);
             startActivity(settings);
             finish();
             return;
@@ -56,10 +55,6 @@
         showFragment(new TopLevelSettings(), R.id.main_content);
     }
 
-    public static boolean isDynamicHomepageEnabled(Context context) {
-        return FeatureFlagUtils.isEnabled(context, FeatureFlags.DYNAMIC_HOMEPAGE);
-    }
-
     private void showFragment(Fragment fragment, int id) {
         final FragmentManager fragmentManager = getSupportFragmentManager();
         final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index 572c36d..36c0a11 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -25,6 +25,7 @@
 import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
 import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
 import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
+import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
 import com.android.settings.intelligence.ContextualCardProto.ContextualCard;
 import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
 import com.android.settings.wifi.WifiSlice;
@@ -69,6 +70,11 @@
                         .setSliceUri(BatterySlice.BATTERY_CARD_URI.toSafeString())
                         .setCardName(BatterySlice.PATH_BATTERY_INFO)
                         .build();
+        final ContextualCard connectedDeviceCard =
+                ContextualCard.newBuilder()
+                        .setSliceUri(ConnectedDeviceSlice.CONNECTED_DEVICE_URI.toString())
+                        .setCardName(ConnectedDeviceSlice.PATH_CONNECTED_DEVICE)
+                        .build();
         final ContextualCardList cards = ContextualCardList.newBuilder()
                 .addCard(wifiCard)
                 .addCard(dataUsageCard)
@@ -76,6 +82,7 @@
                 .addCard(storageInfoCard)
                 .addCard(emergencyInfoCard)
                 .addCard(batteryInfoCard)
+                .addCard(connectedDeviceCard)
                 .build();
 
         return cards;
diff --git a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java b/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
new file mode 100644
index 0000000..83a6af5
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
@@ -0,0 +1,286 @@
+/*
+ * 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.homepage.contextualcards.slices;
+
+import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.SubSettings;
+import com.android.settings.Utils;
+import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.slices.CustomSliceable;
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.slices.SliceBuilderUtils;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * TODO(b/114807655): Contextual Home Page - Connected Device
+ *
+ * Show connected device info if one is currently connected. UI for connected device should
+ * match Connected Devices > Currently Connected Devices
+ *
+ * This Slice will show multiple currently connected devices, which includes:
+ * 1) Bluetooth.
+ * 2) Docks.
+ * ...
+ * TODO Other device types are under checking to support, will update later.
+ */
+public class ConnectedDeviceSlice implements CustomSliceable {
+
+    /**
+     * The path denotes the unique name of Connected device Slice.
+     */
+    public static final String PATH_CONNECTED_DEVICE = "connected_device";
+
+    /**
+     * Backing Uri for Connected device Slice.
+     */
+    public static final Uri CONNECTED_DEVICE_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+            .appendPath(PATH_CONNECTED_DEVICE)
+            .build();
+
+    /**
+     * To sort the Bluetooth devices by {@link CachedBluetoothDevice}.
+     * Refer compareTo method from {@link com.android.settings.bluetooth.BluetoothDevicePreference}.
+     */
+    private static final Comparator<CachedBluetoothDevice> COMPARATOR
+            = Comparator.naturalOrder();
+
+    private static final int DEFAULT_EXPANDED_ROW_COUNT = 4;
+
+    private static final String TAG = "ConnectedDeviceSlice";
+
+    private final Context mContext;
+
+    public ConnectedDeviceSlice(Context context) {
+        mContext = context;
+    }
+
+    private static Bitmap getBitmapFromVectorDrawable(Drawable VectorDrawable) {
+        final Bitmap bitmap = Bitmap.createBitmap(VectorDrawable.getIntrinsicWidth(),
+                VectorDrawable.getIntrinsicHeight(), Config.ARGB_8888);
+        final Canvas canvas = new Canvas(bitmap);
+
+        VectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        VectorDrawable.draw(canvas);
+
+        return bitmap;
+    }
+
+    @Override
+    public Uri getUri() {
+        return CONNECTED_DEVICE_URI;
+    }
+
+    /**
+     * Return a Connected Device Slice bound to {@link #CONNECTED_DEVICE_URI}.
+     */
+    @Override
+    public Slice getSlice() {
+        final IconCompat icon = IconCompat.createWithResource(mContext,
+                R.drawable.ic_homepage_connected_device);
+        final CharSequence title = mContext.getText(R.string.connected_devices_dashboard_title);
+        final CharSequence titleNoConnectedDevices = mContext.getText(
+                R.string.no_connected_devices);
+        final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext, 0,
+                getIntent(), 0);
+        final SliceAction primarySliceAction = new SliceAction(primaryActionIntent, icon,
+                title);
+        final ListBuilder listBuilder =
+                new ListBuilder(mContext, CONNECTED_DEVICE_URI, ListBuilder.INFINITY)
+                        .setAccentColor(Utils.getColorAccentDefaultColor(mContext));
+
+        // Get row builders by connected devices, e.g. Bluetooth.
+        // TODO Add other type connected devices, e.g. Docks.
+        final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction);
+
+        // Return a header with IsError flag, if no connected devices.
+        if (rows.isEmpty()) {
+            return listBuilder.setHeader(new ListBuilder.HeaderBuilder()
+                    .setTitle(titleNoConnectedDevices)
+                    .setPrimaryAction(primarySliceAction))
+                    .setIsError(true)
+                    .build();
+        }
+
+        // According the number of connected devices to set sub title of header.
+        listBuilder.setHeader(new ListBuilder.HeaderBuilder()
+                .setTitle(title)
+                .setSubtitle(getSubTitle(rows.size()))
+                .setPrimaryAction(primarySliceAction));
+
+        // Add rows.
+        for (ListBuilder.RowBuilder rowBuilder : rows) {
+            listBuilder.addRow(rowBuilder);
+        }
+
+        // Only show "see more" button when the number of data row is more than or equal to 4.
+        // TODO(b/118465996): SHOW MORE button won't work properly when having two data rows
+        if (rows.size() >= DEFAULT_EXPANDED_ROW_COUNT) {
+            listBuilder.setSeeMoreAction(primaryActionIntent);
+        }
+
+        return listBuilder.build();
+    }
+
+    @Override
+    public Intent getIntent() {
+        final String screenTitle = mContext.getText(R.string.connected_devices_dashboard_title)
+                .toString();
+        final Uri contentUri = new Uri.Builder().appendPath(PATH_CONNECTED_DEVICE).build();
+
+        return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
+                ConnectedDeviceDashboardFragment.class.getName(), PATH_CONNECTED_DEVICE,
+                screenTitle,
+                MetricsProto.MetricsEvent.SLICE)
+                .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+                .setData(contentUri);
+    }
+
+    @Override
+    public void onNotifyChange(Intent intent) {
+    }
+
+    @VisibleForTesting
+    List<CachedBluetoothDevice> getBluetoothConnectedDevices() {
+        final List<CachedBluetoothDevice> connectedBluetoothList = new ArrayList<>();
+
+        // If Bluetooth is disable, skip to get the bluetooth devices.
+        if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
+            Log.d(TAG, "Cannot get Bluetooth connected devices, Bluetooth is disabled.");
+            return connectedBluetoothList;
+        }
+
+        // Get the Bluetooth devices from LocalBluetoothManager.
+        final LocalBluetoothManager bluetoothManager =
+                com.android.settings.bluetooth.Utils.getLocalBtManager(mContext);
+        if (bluetoothManager == null) {
+            Log.d(TAG, "Cannot get Bluetooth connected devices, Bluetooth is not supported.");
+            return connectedBluetoothList;
+        }
+        final Collection<CachedBluetoothDevice> cachedDevices =
+                bluetoothManager.getCachedDeviceManager().getCachedDevicesCopy();
+
+        // Get all connected Bluetooth devices and use Map to filter duplicated Bluetooth.
+        final Map<BluetoothDevice, CachedBluetoothDevice> connectedBluetoothMap = new ArrayMap<>();
+        for (CachedBluetoothDevice device : cachedDevices) {
+            if (device.isConnected() && !connectedBluetoothMap.containsKey(device.getDevice())) {
+                connectedBluetoothMap.put(device.getDevice(), device);
+            }
+        }
+
+        // Sort connected Bluetooth devices.
+        connectedBluetoothList.addAll(connectedBluetoothMap.values());
+        Collections.sort(connectedBluetoothList, COMPARATOR);
+
+        return connectedBluetoothList;
+    }
+
+    @VisibleForTesting
+    PendingIntent getBluetoothDetailIntent(CachedBluetoothDevice device) {
+        final Bundle args = new Bundle();
+        args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS,
+                device.getDevice().getAddress());
+        final SubSettingLauncher subSettingLauncher = new SubSettingLauncher(mContext);
+        subSettingLauncher.setDestination(BluetoothDeviceDetailsFragment.class.getName())
+                .setArguments(args)
+                .setTitleRes(R.string.device_details_title)
+                .setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN);
+
+        // The requestCode should be unique, use the hashcode of device as request code.
+        return PendingIntent
+                .getActivity(mContext, device.hashCode()  /* requestCode */,
+                        subSettingLauncher.toIntent(),
+                        0  /* flags */);
+    }
+
+    @VisibleForTesting
+    IconCompat getConnectedDeviceIcon(CachedBluetoothDevice device) {
+        final Pair<Drawable, String> pair = BluetoothUtils
+                .getBtClassDrawableWithDescription(mContext, device);
+
+        if (pair.first != null) {
+            return IconCompat.createWithBitmap(getBitmapFromVectorDrawable(pair.first));
+        } else {
+            return IconCompat.createWithResource(mContext, R.drawable.ic_homepage_connected_device);
+        }
+    }
+
+    private List<ListBuilder.RowBuilder> getBluetoothRowBuilder(SliceAction primarySliceAction) {
+        final List<ListBuilder.RowBuilder> bluetoothRows = new ArrayList<>();
+
+        // According Bluetooth connected device to create row builders.
+        final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothConnectedDevices();
+        for (CachedBluetoothDevice bluetoothDevice : bluetoothDevices) {
+            bluetoothRows.add(new ListBuilder.RowBuilder()
+                    .setTitleItem(getConnectedDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
+                    .setTitle(bluetoothDevice.getName())
+                    .setSubtitle(bluetoothDevice.getConnectionSummary())
+                    .setPrimaryAction(primarySliceAction)
+                    .addEndItem(buildBluetoothDetailDeepLinkAction(bluetoothDevice)));
+        }
+
+        return bluetoothRows;
+    }
+
+    private SliceAction buildBluetoothDetailDeepLinkAction(CachedBluetoothDevice bluetoothDevice) {
+        return new SliceAction(
+                getBluetoothDetailIntent(bluetoothDevice),
+                IconCompat.createWithResource(mContext, R.drawable.ic_settings),
+                bluetoothDevice.getName());
+    }
+
+    private CharSequence getSubTitle(int deviceCount) {
+        return mContext.getResources().getQuantityString(R.plurals.show_connected_devices,
+                deviceCount, deviceCount);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index b43cd3a..f397382 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -30,7 +30,6 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
-import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -213,11 +212,6 @@
                 || (!esimIgnoredDevice && enabledEsimUiByDefault && inEsimSupportedCountries));
     }
 
-    public static PersistableBundle getCarrierConfigBySubId(int mSubId) {
-        //TODO(b/114749736): get carrier config from subId
-        return new PersistableBundle();
-    }
-
     /**
      * Set whether to enable data for {@code subId}, also whether to disable data for other
      * subscription
@@ -253,9 +247,17 @@
         }
         final TelephonyManager telephonyManager = TelephonyManager.from(context)
                 .createForSubscriptionId(subId);
+        final PersistableBundle carrierConfig = context.getSystemService(
+                CarrierConfigManager.class).getConfigForSubId(subId);
+
 
         if (telephonyManager.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
             return true;
+        } else if (carrierConfig != null
+                && !carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
+                && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {
+            return true;
         }
 
         if (isWorldMode(context, subId)) {
@@ -312,7 +314,10 @@
 
         if (telephonyManager.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
             return true;
-        } else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {
+        } else if (carrierConfig != null
+                && !carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
+                && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {
             return true;
         }
 
diff --git a/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java b/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java
index 4119c64..5f259f8 100644
--- a/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java
+++ b/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java
@@ -23,6 +23,8 @@
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 
+import com.android.internal.telephony.Phone;
+
 /**
  * Preference controller for "System Select"
  */
@@ -47,6 +49,12 @@
                 resetCdmaRoamingModeToDefault();
             }
         }
+        final int settingsNetworkMode = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.PREFERRED_NETWORK_MODE + mSubId,
+                Phone.PREFERRED_NT_MODE);
+        listPreference.setEnabled(
+                settingsNetworkMode != TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);
     }
 
     @Override
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index 4658d2a..556c698 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -24,6 +24,7 @@
 import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
 import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
 import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
+import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
 import com.android.settings.wifi.WifiSlice;
 
 import java.util.Map;
@@ -103,5 +104,6 @@
         mUriMap.put(DeviceInfoSlice.DEVICE_INFO_CARD_URI, DeviceInfoSlice.class);
         mUriMap.put(StorageSlice.STORAGE_CARD_URI, StorageSlice.class);
         mUriMap.put(BatterySlice.BATTERY_CARD_URI, BatterySlice.class);
+        mUriMap.put(ConnectedDeviceSlice.CONNECTED_DEVICE_URI, ConnectedDeviceSlice.class);
     }
 }
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index 0f10d28..866e5a8 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -147,12 +147,7 @@
      * screen for the first time (as opposed to when a user changes his choice
      * of engine).
      */
-    private final TextToSpeech.OnInitListener mInitListener = new TextToSpeech.OnInitListener() {
-        @Override
-        public void onInit(int status) {
-            onInitEngine(status);
-        }
-    };
+    private final TextToSpeech.OnInitListener mInitListener = this::onInitEngine;
 
     @Override
     public int getMetricsCategory() {
@@ -215,6 +210,11 @@
     @Override
     public void onResume() {
         super.onResume();
+        // We tend to change the summary contents of our widgets, which at higher text sizes causes
+        // them to resize, which results in the recyclerview smoothly animating them at inopportune
+        // times. Disable the animation so widgets snap to their positions rather than sliding
+        // around while the user is interacting with it.
+        getListView().getItemAnimator().setMoveDuration(0);
 
         if (mTts == null || mCurrentDefaultLocale == null) {
             return;
@@ -323,7 +323,6 @@
         if (mCurrentEngine != null) {
             EngineInfo info = mEnginesHelper.getEngineInfo(mCurrentEngine);
 
-
             Preference mEnginePreference = findPreference(KEY_TTS_ENGINE_PREFERENCE);
             ((GearPreference) mEnginePreference).setOnGearClickListener(this);
             mEnginePreference.setSummary(info.label);
@@ -365,14 +364,7 @@
         if (status == TextToSpeech.SUCCESS) {
             if (DBG) Log.d(TAG, "TTS engine for settings screen initialized.");
             checkDefaultLocale();
-            getActivity()
-                    .runOnUiThread(
-                            new Runnable() {
-                                @Override
-                                public void run() {
-                                    mLocalePreference.setEnabled(true);
-                                }
-                            });
+            getActivity().runOnUiThread(() -> mLocalePreference.setEnabled(true));
         } else {
             if (DBG) {
                 Log.d(TAG,
@@ -516,14 +508,7 @@
         }
 
         // Sort it
-        Collections.sort(
-                entryPairs,
-                new Comparator<Pair<String, Locale>>() {
-                    @Override
-                    public int compare(Pair<String, Locale> lhs, Pair<String, Locale> rhs) {
-                        return lhs.first.compareToIgnoreCase(rhs.first);
-                    }
-                });
+        Collections.sort(entryPairs, (lhs, rhs) -> lhs.first.compareToIgnoreCase(rhs.first));
 
         // Get two arrays out of one of pairs
         mSelectedLocaleIndex = 0; // Will point to the R.string.tts_lang_use_system value
diff --git a/tests/robotests/src/com/android/settings/SettingsActivityTest.java b/tests/robotests/src/com/android/settings/SettingsActivityTest.java
index 409512e..af25f48 100644
--- a/tests/robotests/src/com/android/settings/SettingsActivityTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsActivityTest.java
@@ -71,10 +71,9 @@
     @Test
     public void onCreate_deviceNotProvisioned_shouldDisableSearch() {
         Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 0);
-        final Intent intent = new Intent(mContext, Settings.class);
-        final SettingsActivity activity =
-                Robolectric.buildActivity(SettingsActivity.class, intent).create(
-                        Bundle.EMPTY).get();
+        final SettingsActivity activity = Robolectric.buildActivity(SettingsActivity.class)
+                .create(Bundle.EMPTY)
+                .get();
 
         assertThat(activity.findViewById(R.id.search_bar).getVisibility())
                 .isEqualTo(View.INVISIBLE);
@@ -83,10 +82,9 @@
     @Test
     public void onCreate_deviceProvisioned_shouldEnableSearch() {
         Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
-        final Intent intent = new Intent(mContext, Settings.class);
-        final SettingsActivity activity =
-                Robolectric.buildActivity(SettingsActivity.class, intent).create(
-                        Bundle.EMPTY).get();
+        final SettingsActivity activity = Robolectric.buildActivity(SettingsActivity.class)
+                .create(Bundle.EMPTY)
+                .get();
 
         assertThat(activity.findViewById(R.id.search_bar).getVisibility()).isEqualTo(View.VISIBLE);
     }
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
new file mode 100644
index 0000000..f122819
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.homepage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.FeatureFlags;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.shadows.ShadowActivity;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class SettingsHomepageActivityTest {
+
+    @Test
+    public void launch_featureFlagOff_shouldRedirectToSettingsActivity() {
+        FeatureFlagUtils.setEnabled(RuntimeEnvironment.application, FeatureFlags.DYNAMIC_HOMEPAGE,
+                false);
+
+        final ShadowActivity shadowActivity = Shadows.shadowOf(
+                Robolectric.setupActivity(SettingsHomepageActivity.class));
+        assertThat(shadowActivity.getNextStartedActivity().getComponent().getClassName())
+                .isEqualTo(SettingsActivity.class.getName());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java
new file mode 100644
index 0000000..23da127
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.homepage.contextualcards.slices;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceProvider;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.SliceTester;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ConnectedDeviceSliceTest {
+
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+
+    private List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
+    private Context mContext;
+    private ConnectedDeviceSlice mConnectedDeviceSlice;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        // Set-up specs for SliceMetadata.
+        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+
+        mConnectedDeviceSlice = spy(new ConnectedDeviceSlice(mContext));
+    }
+
+    @Test
+    public void getSlice_hasConnectedDevices_shouldBeCorrectSliceContent() {
+        final String title = "BluetoothTitle";
+        final String summary = "BluetoothSummary";
+        final IconCompat icon = IconCompat.createWithResource(mContext,
+                R.drawable.ic_homepage_connected_device);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
+                new Intent("test action"), 0);
+        doReturn(title).when(mCachedBluetoothDevice).getName();
+        doReturn(summary).when(mCachedBluetoothDevice).getConnectionSummary();
+        mCachedDevices.add(mCachedBluetoothDevice);
+        doReturn(mCachedDevices).when(mConnectedDeviceSlice).getBluetoothConnectedDevices();
+        doReturn(icon).when(mConnectedDeviceSlice).getConnectedDeviceIcon(any());
+        doReturn(pendingIntent).when(mConnectedDeviceSlice).getBluetoothDetailIntent(any());
+        final Slice slice = mConnectedDeviceSlice.getSlice();
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertTitle(sliceItems, title);
+    }
+
+    @Test
+    public void getSlice_hasNoConnectedDevices_shouldReturnCorrectHeader() {
+        final List<CachedBluetoothDevice> connectedBluetoothList = new ArrayList<>();
+        doReturn(connectedBluetoothList).when(mConnectedDeviceSlice).getBluetoothConnectedDevices();
+        final Slice slice = mConnectedDeviceSlice.getSlice();
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_connected_devices));
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
index c03fb71..676c9f4 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
@@ -21,18 +21,20 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.doReturn;
 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.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -75,27 +77,35 @@
     private ComponentName mComponentName;
     @Mock
     private ResolveInfo mResolveInfo;
+    @Mock
+    private CarrierConfigManager mCarrierConfigManager;
 
     private Context mContext;
+    private PersistableBundle mCarrierConfig;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
         mContext = spy(RuntimeEnvironment.application);
-        doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class);
-        doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
-        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID_1);
-        doReturn(mTelephonyManager2).when(mTelephonyManager).createForSubscriptionId(SUB_ID_2);
-        doReturn(mPackageManager).when(mContext).getPackageManager();
-        doReturn(mComponentName).when(mPhoneAccountHandle).getComponentName();
-        doReturn(PACKAGE_NAME).when(mComponentName).getPackageName();
+        when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+        when(mTelephonyManager.createForSubscriptionId(SUB_ID_1)).thenReturn(mTelephonyManager);
+        when(mTelephonyManager.createForSubscriptionId(SUB_ID_2)).thenReturn(mTelephonyManager2);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPhoneAccountHandle.getComponentName()).thenReturn(mComponentName);
+        when(mComponentName.getPackageName()).thenReturn(PACKAGE_NAME);
+        when(mContext.getSystemService(CarrierConfigManager.class)).thenReturn(
+                mCarrierConfigManager);
 
-        doReturn(SUB_ID_1).when(mSubscriptionInfo1).getSubscriptionId();
-        doReturn(SUB_ID_2).when(mSubscriptionInfo2).getSubscriptionId();
+        mCarrierConfig = new PersistableBundle();
+        when(mCarrierConfigManager.getConfigForSubId(SUB_ID_1)).thenReturn(mCarrierConfig);
 
-        doReturn(Arrays.asList(mSubscriptionInfo1, mSubscriptionInfo2)).when(
-                mSubscriptionManager).getActiveSubscriptionInfoList();
+        when(mSubscriptionInfo1.getSubscriptionId()).thenReturn(SUB_ID_1);
+        when(mSubscriptionInfo2.getSubscriptionId()).thenReturn(SUB_ID_2);
+
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo1, mSubscriptionInfo2));
     }
 
     @Test
@@ -129,8 +139,8 @@
 
     @Test
     public void buildConfigureIntent_noActivityHandleIntent_returnNull() {
-        doReturn(new ArrayList<ResolveInfo>()).when(mPackageManager).queryIntentActivities(
-                nullable(Intent.class), anyInt());
+        when(mPackageManager.queryIntentActivities(nullable(Intent.class), anyInt()))
+                .thenReturn(new ArrayList<>());
 
         assertThat(MobileNetworkUtils.buildPhoneAccountConfigureIntent(mContext,
                 mPhoneAccountHandle)).isNull();
@@ -138,8 +148,8 @@
 
     @Test
     public void buildConfigureIntent_hasActivityHandleIntent_returnIntent() {
-        doReturn(Arrays.asList(mResolveInfo)).when(mPackageManager).queryIntentActivities(
-                nullable(Intent.class), anyInt());
+        when(mPackageManager.queryIntentActivities(nullable(Intent.class), anyInt()))
+                .thenReturn(Arrays.asList(mResolveInfo));
 
         assertThat(MobileNetworkUtils.buildPhoneAccountConfigureIntent(mContext,
                 mPhoneAccountHandle)).isNotNull();
@@ -147,19 +157,29 @@
 
     @Test
     public void isCdmaOptions_phoneTypeCdma_returnTrue() {
-        doReturn(PhoneConstants.PHONE_TYPE_CDMA).when(mTelephonyManager).getPhoneType();
+        when(mTelephonyManager.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_CDMA);
 
         assertThat(MobileNetworkUtils.isCdmaOptions(mContext, SUB_ID_1)).isTrue();
     }
 
     @Test
     public void isCdmaOptions_worldModeWithGsmWcdma_returnTrue() {
-        doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mTelephonyManager).getPhoneType();
-        doReturn("true").when(mContext).getString(R.string.config_world_mode);
+        when(mTelephonyManager.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
+        when(mContext.getString(R.string.config_world_mode)).thenReturn("true");
         Settings.Global.putInt(mContext.getContentResolver(),
                 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID_1,
                 TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);
 
         assertThat(MobileNetworkUtils.isCdmaOptions(mContext, SUB_ID_1)).isTrue();
     }
+
+    @Test
+    public void isCdmaOptions_carrierWorldModeWithoutHideCarrier_returnTrue() {
+        when(mTelephonyManager.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
+        mCarrierConfig.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
+                false);
+        mCarrierConfig.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+
+        assertThat(MobileNetworkUtils.isCdmaOptions(mContext, SUB_ID_1)).isTrue();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSubscriptionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSubscriptionPreferenceControllerTest.java
index c938948..4044b6c 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSubscriptionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSubscriptionPreferenceControllerTest.java
@@ -21,10 +21,13 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.PersistableBundle;
 import android.os.SystemProperties;
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
@@ -53,9 +56,12 @@
     private TelephonyManager mInvalidTelephonyManager;
     @Mock
     private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private CarrierConfigManager mCarrierConfigManager;
 
     private CdmaSubscriptionPreferenceController mController;
     private ListPreference mPreference;
+    private PersistableBundle mCarrierConfig;
     private Context mContext;
 
     @Before
@@ -68,6 +74,10 @@
         doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
         doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        doReturn(mCarrierConfigManager).when(mContext).getSystemService(CarrierConfigManager.class);
+
+        mCarrierConfig = new PersistableBundle();
+        when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(mCarrierConfig);
 
         mPreference = new ListPreference(mContext);
         mController = new CdmaSubscriptionPreferenceController(mContext, "mobile_data");
diff --git a/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java
index 2046237..f00afc9 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java
@@ -21,9 +21,12 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.PersistableBundle;
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
@@ -51,9 +54,12 @@
     private TelephonyManager mInvalidTelephonyManager;
     @Mock
     private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private CarrierConfigManager mCarrierConfigManager;
 
     private CdmaSystemSelectPreferenceController mController;
     private ListPreference mPreference;
+    private PersistableBundle mCarrierConfig;
     private Context mContext;
 
     @Before
@@ -67,6 +73,12 @@
         doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
 
+        doReturn(mCarrierConfigManager).when(mContext).getSystemService(CarrierConfigManager.class);
+
+        mCarrierConfig = new PersistableBundle();
+        when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(mCarrierConfig);
+
+
         mPreference = new ListPreference(mContext);
         mController = new CdmaSystemSelectPreferenceController(mContext, "mobile_data");
         mController.init(mPreferenceManager, SUB_ID);
@@ -102,6 +114,20 @@
     }
 
     @Test
+    public void updateState_LteGSMWcdma_disabled() {
+        doReturn(TelephonyManager.CDMA_ROAMING_MODE_HOME).when(
+                mTelephonyManager).getCdmaRoamingMode();
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID,
+                TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+
+    @Test
     public void updateState_stateOther_resetToDefault() {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.CDMA_ROAMING_MODE,