Merge "Fix deep link issue of Slice cards in home page"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c5e512e..7807f0e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -69,6 +69,7 @@
     <uses-permission android:name="android.permission.READ_PROFILE" />
     <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
     <uses-permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE" />
+    <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
     <uses-permission android:name="android.permission.SET_TIME" />
     <uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
     <uses-permission android:name="android.permission.REBOOT" />
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index 8d81e82..75d449f 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -21,24 +21,17 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <com.google.android.material.appbar.AppBarLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:background="@android:color/transparent"
-        app:elevation="0dp">
-        <include layout="@layout/search_bar"/>
-    </com.google.android.material.appbar.AppBarLayout>
-
     <androidx.core.widget.NestedScrollView
         android:id="@+id/main_content_scrollable_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        app:layout_behavior="@string/appbar_scrolling_view_behavior">
+        app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="vertical"
+            android:paddingTop="@dimen/app_bar_height"
             android:descendantFocusability="blocksDescendants">
 
             <FrameLayout
@@ -55,4 +48,10 @@
 
         </LinearLayout>
     </androidx.core.widget.NestedScrollView>
+
+    <com.google.android.material.appbar.AppBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <include layout="@layout/search_bar"/>
+    </com.google.android.material.appbar.AppBarLayout>
 </androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 83848af..a6c6c37 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -105,6 +105,8 @@
     <dimen name="search_bar_avatar_size">32dp</dimen>
     <dimen name="search_bar_avatar_start_margin">4dp</dimen>
     <dimen name="search_bar_avatar_end_margin">16dp</dimen>
+    <!-- appbar height is equal search bar height (48dp) plus search bar top and bottom margin  -->
+    <dimen name="app_bar_height">80dp</dimen>
 
     <!-- Dimensions for Wifi Assistant Card -->
     <dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>
diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java
index 7b0be94..5ab543f 100644
--- a/src/com/android/settings/CredentialStorage.java
+++ b/src/com/android/settings/CredentialStorage.java
@@ -172,8 +172,9 @@
                     dialog.show(getSupportFragmentManager(), ConfigureKeyGuardDialog.TAG);
                     return;
                 }
-                installIfAvailable();
-                finish();
+                if (installIfAvailable()) {
+                    finish();
+                }
                 return;
             }
         }
@@ -217,10 +218,13 @@
 
     /**
      * Install credentials if available, otherwise do nothing.
+     *
+     * @return true if the installation is done and the activity should be finished, false if
+     * an asynchronous task is pending and will finish the activity when it's done.
      */
-    private void installIfAvailable() {
+    private boolean installIfAvailable() {
         if (mInstallBundle == null || mInstallBundle.isEmpty()) {
-            return;
+            return true;
         }
 
         final Bundle bundle = mInstallBundle;
@@ -235,16 +239,17 @@
             if (uid != Process.WIFI_UID) {
                 Log.e(TAG, "Failed to install credentials as uid " + uid + ": cross-user installs"
                         + " may only target wifi uids");
-                return;
+                return true;
             }
 
             final Intent installIntent = new Intent(ACTION_INSTALL)
                     .setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
                     .putExtras(bundle);
             startActivityAsUser(installIntent, new UserHandle(dstUserId));
-            return;
+            return true;
         }
 
+        boolean shouldFinish = true;
         if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) {
             final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
             final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
@@ -259,7 +264,7 @@
 
             if (!mKeyStore.importKey(key, value, uid, flags)) {
                 Log.e(TAG, "Failed to install " + key + " as uid " + uid);
-                return;
+                return true;
             }
             // The key was prepended USER_PRIVATE_KEY by the CredentialHelper. However,
             // KeyChain internally uses the raw alias name and only prepends USER_PRIVATE_KEY
@@ -270,6 +275,7 @@
             if (uid == Process.SYSTEM_UID || uid == KeyStore.UID_SELF) {
                 new MarkKeyAsUserSelectable(
                         key.replaceFirst("^" + Credentials.USER_PRIVATE_KEY, "")).execute();
+                shouldFinish = false;
             }
         }
 
@@ -281,7 +287,7 @@
 
             if (!mKeyStore.put(certName, certData, uid, flags)) {
                 Log.e(TAG, "Failed to install " + certName + " as uid " + uid);
-                return;
+                return shouldFinish;
             }
         }
 
@@ -291,7 +297,7 @@
 
             if (!mKeyStore.put(caListName, caListData, uid, flags)) {
                 Log.e(TAG, "Failed to install " + caListName + " as uid " + uid);
-                return;
+                return shouldFinish;
             }
         }
 
@@ -300,6 +306,7 @@
         sendBroadcast(broadcast);
 
         setResult(RESULT_OK);
+        return shouldFinish;
     }
 
     /**
@@ -411,6 +418,13 @@
                 return false;
             }
         }
+
+        @Override
+        protected void onPostExecute(Boolean result) {
+            Log.i(TAG, String.format("Marked alias %s as selectable, success? %s",
+                        mAlias, result));
+            CredentialStorage.this.finish();
+        }
     }
 
     /**
diff --git a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
index 408db09..33e7771 100644
--- a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
+++ b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
@@ -36,8 +36,9 @@
 public class EmergencyInfoPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin {
 
+    public static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
+
     private static final String KEY_EMERGENCY_INFO = "emergency_info";
-    private static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
     private static final String PACKAGE_NAME_EMERGENCY = "com.android.emergency";
 
     public EmergencyInfoPreferenceController(Context context) {
@@ -57,7 +58,7 @@
 
     public void updateState(Preference preference) {
         UserInfo info = mContext.getSystemService(UserManager.class).getUserInfo(
-            UserHandle.myUserId());
+                UserHandle.myUserId());
         preference.setSummary(mContext.getString(R.string.emergency_info_summary, info.name));
     }
 
diff --git a/src/com/android/settings/display/ColorModePreferenceController.java b/src/com/android/settings/display/ColorModePreferenceController.java
index 4679436..5d6a412 100644
--- a/src/com/android/settings/display/ColorModePreferenceController.java
+++ b/src/com/android/settings/display/ColorModePreferenceController.java
@@ -14,11 +14,7 @@
 package com.android.settings.display;
 
 import android.content.Context;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
+import android.hardware.display.ColorDisplayManager;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -29,19 +25,16 @@
 public class ColorModePreferenceController extends BasePreferenceController {
     private static final String TAG = "ColorModePreference";
 
-    private static final int SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGEMENT = 1030;
-
-    private final ConfigurationWrapper mConfigWrapper;
     private ColorDisplayController mColorDisplayController;
 
     public ColorModePreferenceController(Context context, String key) {
         super(context, key);
-        mConfigWrapper = new ConfigurationWrapper();
     }
 
     @Override
     public int getAvailabilityStatus() {
-        return mConfigWrapper.isDeviceColorManaged()
+        return mContext.getSystemService(ColorDisplayManager.class)
+                .isDeviceColorManaged()
                 && !getColorDisplayController().getAccessibilityTransformActivated() ?
                 AVAILABLE_UNSEARCHABLE : DISABLED_FOR_USER;
     }
@@ -68,32 +61,4 @@
         }
         return mColorDisplayController;
     }
-
-    @VisibleForTesting
-    static class ConfigurationWrapper {
-        private final IBinder mSurfaceFlinger;
-
-        ConfigurationWrapper() {
-            mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
-        }
-
-        boolean isDeviceColorManaged() {
-            if (mSurfaceFlinger != null) {
-                final Parcel data = Parcel.obtain();
-                final Parcel reply = Parcel.obtain();
-                data.writeInterfaceToken("android.ui.ISurfaceComposer");
-                try {
-                    mSurfaceFlinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGEMENT,
-                            data, reply, 0);
-                    return reply.readBoolean();
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Failed to query color management support", ex);
-                } finally {
-                    data.recycle();
-                    reply.recycle();
-                }
-            }
-            return false;
-        }
-    }
 }
diff --git a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
index 8ad5e63..1710f51 100644
--- a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
@@ -17,7 +17,6 @@
 package com.android.settings.display;
 
 import android.content.Context;
-
 import android.hardware.display.ColorDisplayManager;
 
 import androidx.preference.DropDownPreference;
diff --git a/src/com/android/settings/flashlight/FlashlightSliceBuilder.java b/src/com/android/settings/flashlight/FlashlightSlice.java
similarity index 66%
rename from src/com/android/settings/flashlight/FlashlightSliceBuilder.java
rename to src/com/android/settings/flashlight/FlashlightSlice.java
index 5833229..a2c4561 100644
--- a/src/com/android/settings/flashlight/FlashlightSliceBuilder.java
+++ b/src/com/android/settings/flashlight/FlashlightSlice.java
@@ -28,6 +28,7 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraManager;
+import android.net.Uri;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.util.Log;
@@ -41,69 +42,78 @@
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.slices.CustomSliceRegistry;
-import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.CustomSliceable;
 
 
 /**
  * Utility class to build a Flashlight Slice, and handle all associated actions.
  */
-public class FlashlightSliceBuilder {
+public class FlashlightSlice implements CustomSliceable {
 
-    private static final String TAG = "FlashlightSliceBuilder";
-
-    /**
-     * Action notifying a change on the Flashlight Slice.
-     */
-    public static final String ACTION_FLASHLIGHT_SLICE_CHANGED =
-            "com.android.settings.flashlight.action.FLASHLIGHT_SLICE_CHANGED";
+    private static final String TAG = "FlashlightSlice";
 
     /**
      * Action broadcasting a change on whether flashlight is on or off.
      */
-    public static final String ACTION_FLASHLIGHT_CHANGED =
+    private static final String ACTION_FLASHLIGHT_CHANGED =
             "com.android.settings.flashlight.action.FLASHLIGHT_CHANGED";
 
-    public static final IntentFilter INTENT_FILTER = new IntentFilter(ACTION_FLASHLIGHT_CHANGED);
+    private final Context mContext;
 
-    private FlashlightSliceBuilder() {
+    public FlashlightSlice(Context context) {
+        mContext = context;
     }
 
-    public static Slice getSlice(Context context) {
-        if (!isFlashlightAvailable(context)) {
+    @Override
+    public Slice getSlice() {
+        if (!isFlashlightAvailable(mContext)) {
             return null;
         }
-        final PendingIntent toggleAction = getBroadcastIntent(context);
-        @ColorInt final int color = Utils.getColorAccentDefaultColor(context);
+        final PendingIntent toggleAction = getBroadcastIntent(mContext);
+        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
         final IconCompat icon =
-                IconCompat.createWithResource(context, R.drawable.ic_signal_flashlight);
-        return new ListBuilder(context, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
+                IconCompat.createWithResource(mContext, R.drawable.ic_signal_flashlight);
+        return new ListBuilder(mContext, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
                 ListBuilder.INFINITY)
                 .setAccentColor(color)
                 .addRow(new RowBuilder()
-                        .setTitle(context.getText(R.string.power_flashlight))
+                        .setTitle(mContext.getText(R.string.power_flashlight))
                         .setTitleItem(icon, ICON_IMAGE)
                         .setPrimaryAction(
-                                SliceAction.createToggle(toggleAction, null, isFlashlightEnabled(context))))
+                                SliceAction.createToggle(toggleAction, null,
+                                        isFlashlightEnabled(mContext))))
                 .build();
     }
 
-    /**
-     * Update the current flashlight status to the boolean value keyed by
-     * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
-     */
-    public static void handleUriChange(Context context, Intent intent) {
+    @Override
+    public Uri getUri() {
+        return CustomSliceRegistry.FLASHLIGHT_SLICE_URI;
+    }
+
+    @Override
+    public IntentFilter getIntentFilter() {
+        return new IntentFilter(ACTION_FLASHLIGHT_CHANGED);
+    }
+
+    @Override
+    public void onNotifyChange(Intent intent) {
         try {
-            final String cameraId = getCameraId(context);
+            final String cameraId = getCameraId(mContext);
             if (cameraId != null) {
                 final boolean state = intent.getBooleanExtra(
-                        EXTRA_TOGGLE_STATE, isFlashlightEnabled(context));
-                final CameraManager cameraManager = context.getSystemService(CameraManager.class);
+                        EXTRA_TOGGLE_STATE, isFlashlightEnabled(mContext));
+                final CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
                 cameraManager.setTorchMode(cameraId, state);
             }
         } catch (CameraAccessException e) {
             Log.e(TAG, "Camera couldn't set torch mode.", e);
         }
-        context.getContentResolver().notifyChange(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, null);
+        mContext.getContentResolver().notifyChange(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, null);
+    }
+
+    @Override
+    public Intent getIntent() {
+        return null;
     }
 
     private static String getCameraId(Context context) throws CameraAccessException {
@@ -121,12 +131,6 @@
         return null;
     }
 
-    private static PendingIntent getBroadcastIntent(Context context) {
-        final Intent intent = new Intent(ACTION_FLASHLIGHT_SLICE_CHANGED);
-        intent.setClass(context, SliceBroadcastReceiver.class);
-        return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-    }
 
     private static boolean isFlashlightAvailable(Context context) {
         return Settings.Secure.getInt(
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
index 2484e53..f8be2d6 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
@@ -16,9 +16,12 @@
 
 package com.android.settings.homepage.contextualcards.deviceinfo;
 
+import static com.android.settings.accounts.EmergencyInfoPreferenceController.ACTION_EDIT_EMERGENCY_INFO;
+
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
@@ -27,37 +30,57 @@
 
 import com.android.settings.R;
 import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.CustomSliceable;
 
 // This is a slice helper class for EmergencyInfo
-public class EmergencyInfoSlice {
+public class EmergencyInfoSlice implements CustomSliceable {
 
-    private static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
+    private final Context mContext;
 
-    public static Slice getSlice(Context context) {
-        final ListBuilder listBuilder = new ListBuilder(context,
+    public EmergencyInfoSlice(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public Slice getSlice() {
+        final ListBuilder listBuilder = new ListBuilder(mContext,
                 CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI,
                 ListBuilder.INFINITY);
         listBuilder.addRow(
                 new ListBuilder.RowBuilder()
-                        .setTitle(context.getText(R.string.emergency_info_title))
+                        .setTitle(mContext.getText(R.string.emergency_info_title))
                         .setSubtitle(
-                                context.getText(R.string.emergency_info_contextual_card_summary))
-                        .setPrimaryAction(createPrimaryAction(context)));
+                                mContext.getText(R.string.emergency_info_contextual_card_summary))
+                        .setPrimaryAction(createPrimaryAction()));
         return listBuilder.build();
     }
 
-    private static SliceAction createPrimaryAction(Context context) {
-        PendingIntent pendingIntent =
+    @Override
+    public Uri getUri() {
+        return CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI;
+    }
+
+    @Override
+    public Intent getIntent() {
+        return new Intent(ACTION_EDIT_EMERGENCY_INFO);
+    }
+
+    @Override
+    public void onNotifyChange(Intent intent) {
+    }
+
+    private SliceAction createPrimaryAction() {
+        final PendingIntent pendingIntent =
                 PendingIntent.getActivity(
-                        context,
+                        mContext,
                         0 /* requestCode */,
-                        new Intent(ACTION_EDIT_EMERGENCY_INFO),
+                        getIntent(),
                         PendingIntent.FLAG_UPDATE_CURRENT);
 
         return SliceAction.createDeeplink(
                 pendingIntent,
-                IconCompat.createWithResource(context, R.drawable.empty_icon),
+                IconCompat.createWithResource(mContext, R.drawable.empty_icon),
                 ListBuilder.ICON_IMAGE,
-                context.getText(R.string.emergency_info_title));
+                mContext.getText(R.string.emergency_info_title));
     }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
index 4378be3..8720a3c 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
@@ -69,9 +69,9 @@
             dbHelper.markContextualCardAsDismissed(mContext, card.getName());
         });
         showFeedbackDialog(card);
-        final ContextualCardFeatureProvider contexualCardFeatureProvider =
+        final ContextualCardFeatureProvider contextualCardFeatureProvider =
                 FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
-        contexualCardFeatureProvider.logContextualCardDismiss(mContext, card);
+        contextualCardFeatureProvider.logContextualCardDismiss(mContext, card);
     }
 
     @Override
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index a2d6e2b..267fe4d 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -28,8 +28,11 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LiveData;
+import androidx.lifecycle.OnLifecycleEvent;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
@@ -51,13 +54,15 @@
  * Card renderer for {@link ContextualCard} built as slices.
  */
 public class SliceContextualCardRenderer implements ContextualCardRenderer,
-        SliceView.OnSliceActionListener {
+        SliceView.OnSliceActionListener, LifecycleObserver {
     public static final int VIEW_TYPE = R.layout.homepage_slice_tile;
 
     private static final String TAG = "SliceCardRenderer";
 
     @VisibleForTesting
-    final Map<String, LiveData<Slice>> mSliceLiveDataMap;
+    final Map<Uri, LiveData<Slice>> mSliceLiveDataMap;
+    @VisibleForTesting
+    final Set<SliceViewHolder> mFlippedCardSet;
 
     private final Context mContext;
     private final LifecycleOwner mLifecycleOwner;
@@ -71,6 +76,8 @@
         mSliceLiveDataMap = new ArrayMap<>();
         mControllerRendererPool = controllerRendererPool;
         mCardSet = new ArraySet<>();
+        mFlippedCardSet = new ArraySet<>();
+        mLifecycleOwner.getLifecycle().addObserver(this);
     }
 
     @Override
@@ -88,8 +95,6 @@
         final SliceViewHolder cardHolder = (SliceViewHolder) holder;
         final Uri uri = card.getSliceUri();
 
-        //TODO(b/116063073): The URI check should be done earlier when we are performing final
-        // filtering after having the full list.
         if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
             Log.w(TAG, "Invalid uri, skipping slice: " + uri);
             return;
@@ -99,11 +104,11 @@
         cardHolder.sliceView.setTag(uri);
         //TODO(b/114009676): We will soon have a field to decide what slice mode we should set.
         cardHolder.sliceView.setMode(SliceView.MODE_LARGE);
-        LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri.toString());
+        LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri);
 
         if (sliceLiveData == null) {
             sliceLiveData = SliceLiveData.fromUri(mContext, uri);
-            mSliceLiveDataMap.put(uri.toString(), sliceLiveData);
+            mSliceLiveDataMap.put(uri, sliceLiveData);
         }
         mCardSet.add(card);
 
@@ -122,20 +127,24 @@
     }
 
     private void initDismissalActions(SliceViewHolder cardHolder, ContextualCard card) {
-        final ViewFlipper viewFlipper = cardHolder.itemView.findViewById(R.id.viewFlipper);
         cardHolder.sliceView.setOnLongClickListener(v -> {
-            viewFlipper.showNext();
+            cardHolder.viewFlipper.showNext();
+            mFlippedCardSet.add(cardHolder);
             return true;
         });
 
         final Button btnKeep = cardHolder.itemView.findViewById(R.id.keep);
         btnKeep.setOnClickListener(v -> {
-            viewFlipper.showPrevious();
+            cardHolder.resetCard();
+            mFlippedCardSet.remove(cardHolder);
         });
 
         final Button btnRemove = cardHolder.itemView.findViewById(R.id.remove);
         btnRemove.setOnClickListener(v -> {
             mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card);
+            cardHolder.resetCard();
+            mFlippedCardSet.remove(cardHolder);
+            mSliceLiveDataMap.get(card.getSliceUri()).removeObservers(mLifecycleOwner);
         });
     }
 
@@ -158,12 +167,24 @@
         }
     }
 
+    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+    public void onStop() {
+        mFlippedCardSet.stream().forEach(holder -> holder.resetCard());
+        mFlippedCardSet.clear();
+    }
+
     public static class SliceViewHolder extends RecyclerView.ViewHolder {
         public final SliceView sliceView;
+        public final ViewFlipper viewFlipper;
 
         public SliceViewHolder(View view) {
             super(view);
             sliceView = view.findViewById(R.id.slice_view);
+            viewFlipper = view.findViewById(R.id.viewFlipper);
+        }
+
+        public void resetCard() {
+            viewFlipper.setDisplayedChild(0);
         }
     }
 }
diff --git a/src/com/android/settings/location/LocationSliceBuilder.java b/src/com/android/settings/location/LocationSlice.java
similarity index 66%
rename from src/com/android/settings/location/LocationSliceBuilder.java
rename to src/com/android/settings/location/LocationSlice.java
index f70d09b..6dc4241 100644
--- a/src/com/android/settings/location/LocationSliceBuilder.java
+++ b/src/com/android/settings/location/LocationSlice.java
@@ -38,29 +38,31 @@
 import com.android.settings.SubSettings;
 import com.android.settings.Utils;
 import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.CustomSliceable;
 import com.android.settings.slices.SliceBuilderUtils;
 
 /**
  * Utility class to build an intent-based Location Slice.
  */
-public class LocationSliceBuilder {
+public class LocationSlice implements CustomSliceable {
 
-    private LocationSliceBuilder() {
+    private final Context mContext;
+
+    public LocationSlice(Context context) {
+        mContext = context;
     }
 
-    /**
-     * Return a Location Slice bound to {@link CustomSliceRegistry#LOCATION_SLICE_URI}.
-     */
-    public static Slice getSlice(Context context) {
-        final IconCompat icon = IconCompat.createWithResource(context,
+    @Override
+    public Slice getSlice() {
+        final IconCompat icon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_signal_location);
-        final String title = context.getString(R.string.location_settings_title);
-        @ColorInt final int color = Utils.getColorAccentDefaultColor(context);
-        final PendingIntent primaryAction = getPrimaryAction(context);
+        final CharSequence title = mContext.getText(R.string.location_settings_title);
+        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
+        final PendingIntent primaryAction = getPrimaryAction();
         final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
                 ListBuilder.ICON_IMAGE, title);
 
-        return new ListBuilder(context, CustomSliceRegistry.LOCATION_SLICE_URI,
+        return new ListBuilder(mContext, CustomSliceRegistry.LOCATION_SLICE_URI,
                 ListBuilder.INFINITY)
                 .setAccentColor(color)
                 .addRow(new RowBuilder()
@@ -70,19 +72,30 @@
                 .build();
     }
 
-    public static Intent getIntent(Context context) {
-        final String screenTitle = context.getText(R.string.location_settings_title).toString();
+    @Override
+    public Uri getUri() {
+        return CustomSliceRegistry.LOCATION_SLICE_URI;
+    }
+
+    @Override
+    public void onNotifyChange(Intent intent) {
+
+    }
+
+    @Override
+    public Intent getIntent() {
+        final String screenTitle = mContext.getText(R.string.location_settings_title).toString();
         final Uri contentUri = new Uri.Builder().appendPath(KEY_LOCATION).build();
-        return SliceBuilderUtils.buildSearchResultPageIntent(context,
+        return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
                 LocationSettings.class.getName(), KEY_LOCATION, screenTitle,
                 MetricsEvent.LOCATION)
-                .setClassName(context.getPackageName(), SubSettings.class.getName())
+                .setClassName(mContext.getPackageName(), SubSettings.class.getName())
                 .setData(contentUri);
     }
 
-    private static PendingIntent getPrimaryAction(Context context) {
-        final Intent intent = getIntent(context);
-        return PendingIntent.getActivity(context, 0 /* requestCode */,
+    private PendingIntent getPrimaryAction() {
+        final Intent intent = getIntent();
+        return PendingIntent.getActivity(mContext, 0 /* requestCode */,
                 intent, 0 /* flags */);
     }
 }
diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
index b1124f8..9ebeda0 100644
--- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
+++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
@@ -22,7 +22,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -131,16 +130,12 @@
     @VisibleForTesting
     boolean isDialogNeeded() {
         final boolean enableData = !mTelephonyManager.isDataEnabled();
-        final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(
-                mSubId);
-        final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
         final boolean isMultiSim = (mTelephonyManager.getSimCount() > 1);
-        final boolean isMultipleDataOnCapable =
-                (mTelephonyManager.getNumberOfModemsWithSimultaneousDataConnections() > 1);
-        final boolean isDefaultDataSubscription = (nextSir != null && currentSir != null
-                && currentSir.getSubscriptionId() == nextSir.getSubscriptionId());
+        final int defaultSubId = mSubscriptionManager.getDefaultDataSubscriptionId();
+        final boolean needToDisableOthers = mSubscriptionManager
+                .isActiveSubscriptionId(defaultSubId) && defaultSubId != mSubId;
         if (enableData) {
-            if (isMultiSim && !isMultipleDataOnCapable && !isDefaultDataSubscription) {
+            if (isMultiSim && needToDisableOthers) {
                 mDialogType = MobileDataDialogFragment.TYPE_MULTI_SIM_DIALOG;
                 return true;
             }
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index dc184d3..27cc367 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -230,7 +230,8 @@
                     subscriptionManager.getActiveSubscriptionInfoList();
             if (subInfoList != null) {
                 for (SubscriptionInfo subInfo : subInfoList) {
-                    if (subInfo.getSubscriptionId() != subId) {
+                    // We never disable mobile data for opportunistic subscriptions.
+                    if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) {
                         context.getSystemService(TelephonyManager.class).createForSubscriptionId(
                                 subInfo.getSubscriptionId()).setDataEnabled(false);
                     }
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index bef72b7..8f8ee96 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -22,13 +22,16 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.settings.flashlight.FlashlightSlice;
 import com.android.settings.homepage.contextualcards.deviceinfo.BatterySlice;
 import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
 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.BatteryFixSlice;
 import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
 import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
+import com.android.settings.location.LocationSlice;
 import com.android.settings.wifi.WifiSlice;
 
 import java.util.Map;
@@ -106,6 +109,9 @@
         mUriMap.put(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI, ConnectedDeviceSlice.class);
         mUriMap.put(CustomSliceRegistry.DATA_USAGE_SLICE_URI, DataUsageSlice.class);
         mUriMap.put(CustomSliceRegistry.DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class);
+        mUriMap.put(CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class);
+        mUriMap.put(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
+        mUriMap.put(CustomSliceRegistry.LOCATION_SLICE_URI, LocationSlice.class);
         mUriMap.put(CustomSliceRegistry.LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
         mUriMap.put(CustomSliceRegistry.STORAGE_SLICE_URI, StorageSlice.class);
         mUriMap.put(CustomSliceRegistry.WIFI_SLICE_URI, WifiSlice.class);
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 109f02e..80b7133 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -41,9 +41,6 @@
 import com.android.settings.R;
 import com.android.settings.bluetooth.BluetoothSliceBuilder;
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.flashlight.FlashlightSliceBuilder;
-import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
-import com.android.settings.location.LocationSliceBuilder;
 import com.android.settings.notification.ZenModeSliceBuilder;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.SliceBroadcastRelay;
@@ -182,12 +179,6 @@
         } else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
             registerIntentToUri(BluetoothSliceBuilder.INTENT_FILTER, sliceUri);
             return;
-        } else if (CustomSliceRegistry.FLASHLIGHT_SLICE_URI.equals(sliceUri)) {
-            registerIntentToUri(FlashlightSliceBuilder.INTENT_FILTER, sliceUri);
-            mRegisteredUris.add(sliceUri);
-            return;
-        } else if (CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI.equals(sliceUri)) {
-            return;
         }
 
         // Start warming the slice, we expect someone will want it soon.
@@ -240,8 +231,6 @@
                 return ZenModeSliceBuilder.getSlice(getContext());
             } else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
                 return BluetoothSliceBuilder.getSlice(getContext());
-            } else if (CustomSliceRegistry.LOCATION_SLICE_URI.equals(sliceUri)) {
-                return LocationSliceBuilder.getSlice(getContext());
             } else if (CustomSliceRegistry.ENHANCED_4G_SLICE_URI.equals(sliceUri)) {
                 return FeatureFactory.getFactory(getContext())
                         .getSlicesFeatureProvider()
@@ -252,10 +241,6 @@
                         .getSlicesFeatureProvider()
                         .getNewWifiCallingSliceHelper(getContext())
                         .createWifiCallingPreferenceSlice(sliceUri);
-            } else if (CustomSliceRegistry.FLASHLIGHT_SLICE_URI.equals(sliceUri)) {
-                return FlashlightSliceBuilder.getSlice(getContext());
-            } else if (CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI.equals(sliceUri)) {
-                return EmergencyInfoSlice.getSlice(getContext());
             }
 
             SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 2860e9a..823c729 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -17,7 +17,6 @@
 package com.android.settings.slices;
 
 import static com.android.settings.bluetooth.BluetoothSliceBuilder.ACTION_BLUETOOTH_SLICE_CHANGED;
-import static com.android.settings.flashlight.FlashlightSliceBuilder.ACTION_FLASHLIGHT_SLICE_CHANGED;
 import static com.android.settings.network.telephony.Enhanced4gLteSliceHelper.ACTION_ENHANCED_4G_LTE_CHANGED;
 import static com.android.settings.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED;
 import static com.android.settings.slices.SettingsSliceProvider.ACTION_COPY;
@@ -46,7 +45,6 @@
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.SliderPreferenceController;
 import com.android.settings.core.TogglePreferenceController;
-import com.android.settings.flashlight.FlashlightSliceBuilder;
 import com.android.settings.notification.ZenModeSliceBuilder;
 import com.android.settings.overlay.FeatureFactory;
 
@@ -108,9 +106,6 @@
                         .getNewWifiCallingSliceHelper(context)
                         .handleWifiCallingPreferenceChanged(intent);
                 break;
-            case ACTION_FLASHLIGHT_SLICE_CHANGED:
-                FlashlightSliceBuilder.handleUriChange(context, intent);
-                break;
             case ACTION_COPY:
                 handleCopyAction(context, key, isPlatformSlice);
                 break;
diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
index 01708af..d633b7a 100644
--- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
+++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
@@ -24,7 +24,6 @@
 import androidx.annotation.Keep;
 
 import com.android.settings.bluetooth.BluetoothSliceBuilder;
-import com.android.settings.location.LocationSliceBuilder;
 import com.android.settings.notification.ZenModeSliceBuilder;
 import com.android.settings.overlay.FeatureFactory;
 
@@ -66,8 +65,6 @@
                     launchIntent = ZenModeSliceBuilder.getIntent(this /* context */);
                 } else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
                     launchIntent = BluetoothSliceBuilder.getIntent(this /* context */);
-                } else if (CustomSliceRegistry.LOCATION_SLICE_URI.equals(sliceUri)) {
-                    launchIntent = LocationSliceBuilder.getIntent(this /* context */);
                 } else {
                     final SlicesDatabaseAccessor slicesDatabaseAccessor =
                             new SlicesDatabaseAccessor(this /* context */);
diff --git a/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java b/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java
new file mode 100644
index 0000000..23f6ccd
--- /dev/null
+++ b/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java
@@ -0,0 +1,61 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+/**
+ * This scrolling view behavior will set the background of the {@link AppBarLayout} as
+ * transparent and without the elevation. Also make header overlapped the scrolling child view.
+ */
+public class FloatingAppBarScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {
+    private boolean initialized;
+
+    public FloatingAppBarScrollingViewBehavior(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
+        boolean changed = super.onDependentViewChanged(parent, child, dependency);
+        if (!initialized && dependency instanceof AppBarLayout) {
+            initialized = true;
+            AppBarLayout appBarLayout = (AppBarLayout) dependency;
+            setAppBarLayoutTransparent(appBarLayout);
+        }
+        return changed;
+    }
+
+    @VisibleForTesting
+    void setAppBarLayoutTransparent(AppBarLayout appBarLayout) {
+        appBarLayout.setBackgroundColor(Color.TRANSPARENT);
+        appBarLayout.setTargetElevation(0);
+    }
+
+    @Override
+    protected boolean shouldHeaderOverlapScrollingChild() {
+        return true;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
similarity index 94%
rename from tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java
rename to tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
index 56a84bb..4af5754 100644
--- a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
@@ -42,7 +42,7 @@
 
 
 @RunWith(SettingsRobolectricTestRunner.class)
-public class FlashlightSliceBuilderTest {
+public class FlashlightSliceTest {
 
     private Context mContext;
 
@@ -58,7 +58,7 @@
     public void getFlashlightSlice_correctData() {
         Settings.Secure.putInt(
                 mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
-        final Slice slice = FlashlightSliceBuilder.getSlice(mContext);
+        final Slice slice = new FlashlightSlice(mContext).getSlice();
         final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
 
         final List<SliceAction> toggles = metadata.getToggles();
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
index 13a2bc5..7d71302 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
@@ -51,10 +52,14 @@
 @RunWith(SettingsRobolectricTestRunner.class)
 public class SliceContextualCardRendererTest {
 
+    private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
+
     @Mock
     private LiveData<Slice> mSliceLiveData;
     @Mock
     private ControllerRendererPool mControllerRendererPool;
+    @Mock
+    private SliceContextualCardController mController;
 
     private Activity mActivity;
     private SliceContextualCardRenderer mRenderer;
@@ -75,10 +80,9 @@
 
     @Test
     public void bindView_shouldSetScrollableToFalse() {
-        final String sliceUri = "content://com.android.settings.slices/action/flashlight";
         RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
 
-        mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+        mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
 
         assertThat(
                 ((SliceContextualCardRenderer.SliceViewHolder) viewHolder).sliceView.isScrollable
@@ -87,7 +91,7 @@
 
     @Test
     public void bindView_invalidScheme_sliceShouldBeNull() {
-        final String sliceUri = "contet://com.android.settings.slices/action/flashlight";
+        final Uri sliceUri = Uri.parse("contet://com.android.settings.slices/action/flashlight");
         RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
 
         mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
@@ -99,64 +103,124 @@
 
     @Test
     public void bindView_newSliceLiveData_shouldAddDataToMap() {
-        final String sliceUri = "content://com.android.settings.slices/action/flashlight";
-
-        mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
+        mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
 
         assertThat(mRenderer.mSliceLiveDataMap.size()).isEqualTo(1);
     }
 
     @Test
     public void bindView_sliceLiveDataShouldObserveSliceView() {
-        final String sliceUri = "content://com.android.settings.slices/action/flashlight";
+        mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
 
-        mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
-
-        assertThat(mRenderer.mSliceLiveDataMap.get(sliceUri).hasObservers()).isTrue();
+        assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isTrue();
     }
 
     @Test
     public void bindView_sliceLiveDataShouldRemoveObservers() {
-        final String sliceUri = "content://com.android.settings.slices/action/flashlight";
-        mRenderer.mSliceLiveDataMap.put(sliceUri, mSliceLiveData);
+        mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData);
 
-        mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
+        mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
 
         verify(mSliceLiveData).removeObservers(mLifecycleOwner);
     }
 
     @Test
     public void longClick_shouldFlipCard() {
-        final String sliceUri = "content://com.android.settings.slices/action/flashlight";
         final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
         final View card = viewHolder.itemView.findViewById(R.id.slice_view);
         final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
         final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view);
-        mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+        mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
 
-        assertThat(card).isNotNull();
         card.performLongClick();
 
         assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView);
     }
 
     @Test
+    public void longClick_shouldAddViewHolderToSet() {
+        final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+        final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+        mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+        card.performLongClick();
+
+        assertThat(mRenderer.mFlippedCardSet).contains(viewHolder);
+    }
+
+    @Test
     public void viewClick_keepCard_shouldFlipBackToSlice() {
-        final String sliceUri = "content://com.android.settings.slices/action/flashlight";
         final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
         final View card = viewHolder.itemView.findViewById(R.id.slice_view);
         final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
         final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
-        mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+        mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
 
-        assertThat(card).isNotNull();
         card.performLongClick();
-        assertThat(btnKeep).isNotNull();
         btnKeep.performClick();
 
         assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
     }
 
+    @Test
+    public void viewClick_keepCard_shouldRemoveViewHolderFromSet() {
+        final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+        final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+        final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
+        mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+        card.performLongClick();
+        btnKeep.performClick();
+
+        assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
+    }
+
+    @Test
+    public void viewClick_removeCard_shouldRemoveViewHolderFromSet() {
+        final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+        final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+        final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
+        final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI);
+        mRenderer.bindView(viewHolder, contextualCard);
+        doReturn(mController).when(mControllerRendererPool).getController(mActivity,
+                ContextualCard.CardType.SLICE);
+
+        card.performLongClick();
+        btnRemove.performClick();
+
+        assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
+    }
+
+    @Test
+    public void viewClick_removeCard_sliceLiveDataShouldRemoveObservers() {
+        final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+        final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+        final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
+        final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI);
+        mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData);
+        mRenderer.bindView(viewHolder, contextualCard);
+        doReturn(mController).when(mControllerRendererPool).getController(mActivity,
+                ContextualCard.CardType.SLICE);
+
+        card.performLongClick();
+        btnRemove.performClick();
+
+        assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isFalse();
+    }
+
+    @Test
+    public void onStop_cardIsFlipped_shouldFlipBack() {
+        final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+        final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+        final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
+        mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+        card.performLongClick();
+        mRenderer.onStop();
+
+        assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
+    }
+
     private RecyclerView.ViewHolder getSliceViewHolder() {
         final int viewType = mRenderer.getViewType(false /* isHalfWidth */);
         final RecyclerView recyclerView = new RecyclerView(mActivity);
@@ -166,10 +230,11 @@
         return mRenderer.createViewHolder(view);
     }
 
-    private ContextualCard buildContextualCard(String sliceUri) {
+    private ContextualCard buildContextualCard(Uri sliceUri) {
         return new ContextualCard.Builder()
                 .setName("test_name")
-                .setSliceUri(Uri.parse(sliceUri))
+                .setCardType(ContextualCard.CardType.SLICE)
+                .setSliceUri(sliceUri)
                 .build();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
similarity index 93%
rename from tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java
rename to tests/robotests/src/com/android/settings/location/LocationSliceTest.java
index ecbf858..8f1045a 100644
--- a/tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
@@ -24,7 +24,7 @@
 import java.util.List;
 
 @RunWith(SettingsRobolectricTestRunner.class)
-public class LocationSliceBuilderTest {
+public class LocationSliceTest {
 
     private Context mContext;
 
@@ -38,7 +38,7 @@
 
     @Test
     public void getLocationSlice_correctSliceContent() {
-        final Slice LocationSlice = LocationSliceBuilder.getSlice(mContext);
+        final Slice LocationSlice = new LocationSlice(mContext).getSlice();
         final SliceMetadata metadata = SliceMetadata.from(mContext, LocationSlice);
 
         final List<SliceAction> toggles = metadata.getToggles();
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
index 2fc3d98..e1ad93b 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
@@ -20,6 +20,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -104,9 +105,8 @@
     public void isDialogNeeded_enableNonDefaultSimInMultiSimMode_returnTrue() {
         doReturn(false).when(mTelephonyManager).isDataEnabled();
         doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID);
-        doReturn(null).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+        doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(anyInt());
         doReturn(2).when(mTelephonyManager).getSimCount();
-        doReturn(1).when(mTelephonyManager).getNumberOfModemsWithSimultaneousDataConnections();
 
         assertThat(mController.isDialogNeeded()).isTrue();
         assertThat(mController.mDialogType).isEqualTo(
diff --git a/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java b/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java
new file mode 100644
index 0000000..6acc4d9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class FloatingAppBarScrollingViewBehaviorTest {
+
+    private FloatingAppBarScrollingViewBehavior mScrollingViewBehavior;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mScrollingViewBehavior = new FloatingAppBarScrollingViewBehavior(mContext,
+                Robolectric.buildAttributeSet().build());
+    }
+
+    @Test
+    public void shouldHeaderOverlapScrollingChild_returnTrue() {
+        assertThat(mScrollingViewBehavior.shouldHeaderOverlapScrollingChild()).isTrue();
+    }
+
+    @Test
+    public void setAppBarLayoutTransparent_backgroundDefaultAsWhite_shouldBeTransparent() {
+        mContext.setTheme(R.style.Theme_Settings_Home);
+        final AppBarLayout appBarLayout = new AppBarLayout(mContext);
+        appBarLayout.setBackgroundColor(Color.WHITE);
+        mScrollingViewBehavior.setAppBarLayoutTransparent(appBarLayout);
+        assertThat(((ColorDrawable) appBarLayout.getBackground()).getColor()).isEqualTo(
+                Color.TRANSPARENT);
+    }
+}