Merge "Fix .equals call in ImageDecoder" into rvc-dev
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 5c43f8f..08d9905 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -486,15 +486,8 @@
     /**
      * @hide
      */
-    public String getShortcutId(Context context) {
-        String conversationId = getNotification().getShortcutId();
-        if (TextUtils.isEmpty(conversationId)
-                && (Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0)
-                && getNotification().getNotificationStyle() == Notification.MessagingStyle.class) {
-            conversationId = getId() + getTag() + PLACEHOLDER_CONVERSATION_ID;
-        }
-        return conversationId;
+    public String getShortcutId() {
+        return getNotification().getShortcutId();
     }
 
     /**
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index bcb32fb..a47ad73 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -301,7 +301,7 @@
 
     private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
         if (shouldShowNoCrossProfileIntentsEmptyState(activeListAdapter)) {
-            activeListAdapter.postListReadyRunnable(doPostProcessing);
+            activeListAdapter.postListReadyRunnable(doPostProcessing, /* rebuildCompleted */ true);
             return false;
         }
         return activeListAdapter.rebuildList(doPostProcessing);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b671fa7..a84d964 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2404,10 +2404,9 @@
     public ChooserGridAdapter createChooserGridAdapter(Context context,
             List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
             boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) {
-        ChooserListAdapter chooserListAdapter = new ChooserListAdapter(context, payloadIntents,
-                initialIntents, rList,
-                filterLastUsed, createListController(userHandle), useLayoutForBrowsables,
-                this, this);
+        ChooserListAdapter chooserListAdapter = createChooserListAdapter(context, payloadIntents,
+                initialIntents, rList, filterLastUsed,
+                useLayoutForBrowsables, createListController(userHandle));
         AppPredictor.Callback appPredictorCallback = createAppPredictorCallback(chooserListAdapter);
         AppPredictor appPredictor = setupAppPredictorForUser(userHandle, appPredictorCallback);
         chooserListAdapter.setAppPredictor(appPredictor);
@@ -2416,6 +2415,16 @@
     }
 
     @VisibleForTesting
+    public ChooserListAdapter createChooserListAdapter(Context context,
+            List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
+            boolean filterLastUsed, boolean useLayoutForBrowsables,
+            ResolverListController resolverListController) {
+        return new ChooserListAdapter(context, payloadIntents, initialIntents, rList,
+                filterLastUsed, resolverListController, useLayoutForBrowsables,
+                this, this, context.getPackageManager());
+    }
+
+    @VisibleForTesting
     protected ResolverListController createListController(UserHandle userHandle) {
         AppPredictor appPredictor = getAppPredictorForShareActivitiesIfEnabled(userHandle);
         AbstractResolverComparator resolverComparator;
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 69a4927..73ee295 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -88,7 +88,7 @@
     private final int mMaxShortcutTargetsPerApp;
     private final ChooserListCommunicator mChooserListCommunicator;
     private final SelectableTargetInfo.SelectableTargetInfoCommunicator
-            mSelectableTargetInfoComunicator;
+            mSelectableTargetInfoCommunicator;
 
     private int mNumShortcutResults = 0;
 
@@ -117,7 +117,8 @@
             boolean filterLastUsed, ResolverListController resolverListController,
             boolean useLayoutForBrowsables,
             ChooserListCommunicator chooserListCommunicator,
-            SelectableTargetInfo.SelectableTargetInfoCommunicator selectableTargetInfoComunicator) {
+            SelectableTargetInfo.SelectableTargetInfoCommunicator selectableTargetInfoCommunicator,
+            PackageManager packageManager) {
         // Don't send the initial intents through the shared ResolverActivity path,
         // we want to separate them into a different section.
         super(context, payloadIntents, null, rList, filterLastUsed,
@@ -128,10 +129,9 @@
         mMaxShortcutTargetsPerApp =
                 context.getResources().getInteger(R.integer.config_maxShortcutTargetsPerApp);
         mChooserListCommunicator = chooserListCommunicator;
-        mSelectableTargetInfoComunicator = selectableTargetInfoComunicator;
+        mSelectableTargetInfoCommunicator = selectableTargetInfoCommunicator;
 
         if (initialIntents != null) {
-            final PackageManager pm = context.getPackageManager();
             for (int i = 0; i < initialIntents.length; i++) {
                 final Intent ii = initialIntents[i];
                 if (ii == null) {
@@ -147,7 +147,7 @@
                 final ComponentName cn = ii.getComponent();
                 if (cn != null) {
                     try {
-                        ai = pm.getActivityInfo(ii.getComponent(), 0);
+                        ai = packageManager.getActivityInfo(ii.getComponent(), 0);
                         ri = new ResolveInfo();
                         ri.activityInfo = ai;
                     } catch (PackageManager.NameNotFoundException ignored) {
@@ -155,7 +155,7 @@
                     }
                 }
                 if (ai == null) {
-                    ri = pm.resolveActivity(ii, PackageManager.MATCH_DEFAULT_ONLY);
+                    ri = packageManager.resolveActivity(ii, PackageManager.MATCH_DEFAULT_ONLY);
                     ai = ri != null ? ri.activityInfo : null;
                 }
                 if (ai == null) {
@@ -455,7 +455,7 @@
             UserHandle userHandle = getUserHandle();
             Context contextAsUser = mContext.createContextAsUser(userHandle, 0 /* flags */);
             boolean isInserted = insertServiceTarget(new SelectableTargetInfo(contextAsUser,
-                    origTarget, target, targetScore, mSelectableTargetInfoComunicator,
+                    origTarget, target, targetScore, mSelectableTargetInfoCommunicator,
                     (isShortcutResult ? directShareToShortcutInfos.get(target) : null)));
 
             if (isInserted && isShortcutResult) {
@@ -507,7 +507,7 @@
                     .map(target ->
                             new SelectableTargetInfo(
                                     contextAsUser, origTarget, target, target.getScore(),
-                                    mSelectableTargetInfoComunicator,
+                                    mSelectableTargetInfoCommunicator,
                                     (isShortcutResult ? directShareToShortcutInfos.get(target)
                                             : null))
                     )
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 4ba6ce4..cf9b955 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1026,7 +1026,8 @@
     }
 
     @Override // ResolverListCommunicator
-    public final void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing) {
+    public final void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing,
+            boolean rebuildCompleted) {
         if (isAutolaunching()) {
             return;
         }
@@ -1041,7 +1042,7 @@
         }
         // showEmptyResolverListEmptyState can mark the tab as loaded,
         // which is a precondition for auto launching
-        if (maybeAutolaunchActivity()) {
+        if (rebuildCompleted && maybeAutolaunchActivity()) {
             return;
         }
         if (doPostProcessing) {
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 62bddb1..2fd938f 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -282,7 +282,7 @@
                 }
                 setPlaceholderCount(placeholderCount);
                 createSortingTask(doPostProcessing).execute(currentResolveList);
-                postListReadyRunnable(doPostProcessing);
+                postListReadyRunnable(doPostProcessing, /* rebuildCompleted */ false);
                 return false;
             } else {
                 processSortedList(currentResolveList, doPostProcessing);
@@ -370,7 +370,7 @@
         }
 
         mResolverListCommunicator.sendVoiceChoicesIfNeeded();
-        postListReadyRunnable(doPostProcessing);
+        postListReadyRunnable(doPostProcessing, /* rebuildCompleted */ true);
         mIsTabLoaded = true;
     }
 
@@ -380,14 +380,15 @@
      * handler thread to update after the current task is finished.
      * @param doPostProcessing Whether to update the UI and load additional direct share targets
      *                         after the list has been rebuilt
+     * @param rebuildCompleted Whether the list has been completely rebuilt
      */
-    void postListReadyRunnable(boolean doPostProcessing) {
+    void postListReadyRunnable(boolean doPostProcessing, boolean rebuildCompleted) {
         if (mPostListReadyRunnable == null) {
             mPostListReadyRunnable = new Runnable() {
                 @Override
                 public void run() {
                     mResolverListCommunicator.onPostListReady(ResolverListAdapter.this,
-                            doPostProcessing);
+                            doPostProcessing, rebuildCompleted);
                     mPostListReadyRunnable = null;
                 }
             };
@@ -649,7 +650,8 @@
 
         Intent getReplacementIntent(ActivityInfo activityInfo, Intent defIntent);
 
-        void onPostListReady(ResolverListAdapter listAdapter, boolean updateUi);
+        void onPostListReady(ResolverListAdapter listAdapter, boolean updateUi,
+                boolean rebuildCompleted);
 
         void sendVoiceChoicesIfNeeded();
 
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index c52555b..edad5c4 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -34,6 +34,7 @@
 import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
 import static com.android.internal.app.MatcherUtils.first;
 
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.hamcrest.CoreMatchers.is;
@@ -41,6 +42,8 @@
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
@@ -55,6 +58,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
@@ -302,7 +307,7 @@
         waitForIdle();
         UsageStatsManager usm = activity.getUsageStatsManager();
         verify(sOverrides.resolverListController, times(1))
-                .topK(Mockito.any(List.class), Mockito.anyInt());
+                .topK(any(List.class), anyInt());
         assertThat(activity.getIsSelected(), is(false));
         sOverrides.onSafelyStartCallback = targetInfo -> {
             return true;
@@ -312,7 +317,7 @@
                 .perform(click());
         waitForIdle();
         verify(sOverrides.resolverListController, times(1))
-                .updateChooserCounts(Mockito.anyString(), Mockito.anyInt(), Mockito.anyString());
+                .updateChooserCounts(Mockito.anyString(), anyInt(), Mockito.anyString());
         verify(sOverrides.resolverListController, times(1))
                 .updateModel(toChoose.activityInfo.getComponentName());
         assertThat(activity.getIsSelected(), is(true));
@@ -1750,6 +1755,54 @@
         assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0)));
     }
 
+    @Test
+    public void testOneInitialIntent_noAutolaunch() {
+        List<ResolvedComponentInfo> personalResolvedComponentInfos =
+                createResolvedComponentsForTest(1);
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class)))
+                .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+        Intent chooserIntent = createChooserIntent(new Intent[] {new Intent("action.fake")});
+        ResolveInfo[] chosen = new ResolveInfo[1];
+        sOverrides.onSafelyStartCallback = targetInfo -> {
+            chosen[0] = targetInfo.getResolveInfo();
+            return true;
+        };
+        sOverrides.packageManager = mock(PackageManager.class);
+        ResolveInfo ri = createFakeResolveInfo();
+        when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(ri);
+        waitForIdle();
+
+        mActivityRule.launchActivity(chooserIntent);
+        waitForIdle();
+
+        assertNull(chosen[0]);
+    }
+
+    private Intent createChooserIntent(Intent[] initialIntents) {
+        Intent chooserIntent = new Intent();
+        chooserIntent.setAction(Intent.ACTION_CHOOSER);
+        chooserIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
+        chooserIntent.putExtra(Intent.EXTRA_TITLE, "some title");
+        chooserIntent.putExtra(Intent.EXTRA_INTENT, createSendTextIntent());
+        chooserIntent.setType("text/plain");
+        if (initialIntents != null) {
+            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, initialIntents);
+        }
+        return chooserIntent;
+    }
+
+    private ResolveInfo createFakeResolveInfo() {
+        ResolveInfo ri = new ResolveInfo();
+        ri.activityInfo = new ActivityInfo();
+        ri.activityInfo.name = "FakeActivityName";
+        ri.activityInfo.packageName = "fake.package.name";
+        ri.activityInfo.applicationInfo = new ApplicationInfo();
+        ri.activityInfo.applicationInfo.packageName = "fake.package.name";
+        return ri;
+    }
+
     private Intent createSendTextIntent() {
         Intent sendIntent = new Intent();
         sendIntent.setAction(Intent.ACTION_SEND);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 5b83f95..071b225 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -58,6 +58,18 @@
         return multiProfilePagerAdapter;
     }
 
+    @Override
+    public ChooserListAdapter createChooserListAdapter(Context context, List<Intent> payloadIntents,
+            Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed,
+            boolean useLayoutForBrowsables, ResolverListController resolverListController) {
+        PackageManager packageManager =
+                sOverrides.packageManager == null ? context.getPackageManager()
+                        : sOverrides.packageManager;
+        return new ChooserListAdapter(context, payloadIntents, initialIntents, rList,
+                filterLastUsed, resolverListController, useLayoutForBrowsables,
+                this, this, packageManager);
+    }
+
     ChooserListAdapter getAdapter() {
         return mChooserMultiProfilePagerAdapter.getActiveListAdapter();
     }
@@ -217,6 +229,7 @@
         public boolean hasCrossProfileIntents;
         public boolean isQuietModeEnabled;
         public AbstractMultiProfilePagerAdapter.Injector multiPagerAdapterInjector;
+        public PackageManager packageManager;
 
         public void reset() {
             onSafelyStartCallback = null;
@@ -235,6 +248,7 @@
             workProfileUserHandle = null;
             hasCrossProfileIntents = true;
             isQuietModeEnabled = false;
+            packageManager = null;
             multiPagerAdapterInjector = new AbstractMultiProfilePagerAdapter.Injector() {
                 @Override
                 public boolean hasCrossProfileIntents(List<Intent> intents, int sourceUserId,
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index db109fe..94a6bc5 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -38,6 +38,7 @@
         android:elevation="1dp"
         android:fillViewport="true"
         android:layout_marginHorizontal="@dimen/screenshot_action_container_margin_horizontal"
+        android:layout_marginBottom="@dimen/screenshot_action_container_offset_y"
         android:gravity="center"
         android:paddingLeft="@dimen/screenshot_action_container_padding_left"
         android:paddingRight="@dimen/screenshot_action_container_padding_right"
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
index 6b94bef..bd91ddb 100644
--- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
@@ -16,14 +16,15 @@
   -->
 <com.android.systemui.screenshot.ScreenshotActionChip
     xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/global_screenshot_action_chip"
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:layout_marginRight="@dimen/screenshot_action_chip_margin_right"
-              android:layout_gravity="center"
-              android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
-              android:background="@drawable/action_chip_background"
-              android:gravity="center">
+    android:id="@+id/global_screenshot_action_chip"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginRight="@dimen/screenshot_action_chip_margin_right"
+    android:layout_gravity="center"
+    android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
+    android:background="@drawable/action_chip_background"
+    android:alpha="0"
+    android:gravity="center">
     <ImageView
         android:id="@+id/screenshot_action_chip_icon"
         android:layout_width="@dimen/screenshot_action_chip_icon_size"
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
new file mode 100644
index 0000000..2401dfb
--- /dev/null
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2020, 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.
+-->
+
+<com.android.systemui.statusbar.notification.row.PartialConversationInfo
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/notification_guts"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:focusable="true"
+    android:clipChildren="false"
+    android:clipToPadding="true"
+    android:orientation="vertical"
+    android:paddingStart="@*android:dimen/notification_content_margin_start">
+
+    <!-- Package Info -->
+    <LinearLayout
+        android:id="@+id/header"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/notification_guts_conversation_header_height"
+        android:gravity="center_vertical"
+        android:clipChildren="false"
+        android:clipToPadding="false">
+        <ImageView
+            android:id="@+id/conversation_icon"
+            android:layout_width="@dimen/notification_guts_conversation_icon_size"
+            android:layout_height="@dimen/notification_guts_conversation_icon_size"
+            android:layout_centerVertical="true"
+            android:layout_alignParentStart="true"
+            android:layout_marginEnd="15dp" />
+        <LinearLayout
+            android:id="@+id/names"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:orientation="vertical"
+
+            android:layout_height="wrap_content"
+            android:minHeight="@dimen/notification_guts_conversation_icon_size"
+            android:layout_centerVertical="true"
+            android:gravity="center_vertical"
+            android:layout_alignEnd="@id/conversation_icon"
+            android:layout_toEndOf="@id/conversation_icon">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="start"
+                android:orientation="horizontal">
+                <TextView
+                    android:id="@+id/name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/TextAppearance.NotificationImportanceChannel"/>
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    style="@style/TextAppearance.NotificationImportanceHeader"
+                    android:layout_marginStart="2dp"
+                    android:layout_marginEnd="2dp"
+                    android:text="@*android:string/notification_header_divider_symbol" />
+                <TextView
+                    android:id="@+id/parent_channel_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/TextAppearance.NotificationImportanceChannel"/>
+
+            </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="start"
+                android:orientation="horizontal">
+                <TextView
+                    android:id="@+id/pkg_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/TextAppearance.NotificationImportanceChannelGroup"
+                    android:ellipsize="end"
+                    android:maxLines="1"/>
+                <TextView
+                    android:id="@+id/group_divider"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    style="@style/TextAppearance.NotificationImportanceHeader"
+                    android:layout_marginStart="2dp"
+                    android:layout_marginEnd="2dp"
+                    android:text="@*android:string/notification_header_divider_symbol" />
+                <TextView
+                    android:id="@+id/group_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
+            </LinearLayout>
+            <TextView
+                android:id="@+id/delegate_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                style="@style/TextAppearance.NotificationImportanceHeader"
+                android:layout_marginStart="2dp"
+                android:layout_marginEnd="2dp"
+                android:ellipsize="end"
+                android:text="@string/notification_delegate_header"
+                android:maxLines="1" />
+
+        </LinearLayout>
+
+        <!-- end aligned fields -->
+        <ImageButton
+            android:id="@+id/info"
+            android:layout_width="@dimen/notification_importance_toggle_size"
+            android:layout_height="@dimen/notification_importance_toggle_size"
+            android:layout_centerVertical="true"
+            android:background="@drawable/ripple_drawable"
+            android:contentDescription="@string/notification_more_settings"
+            android:src="@drawable/ic_settings"
+            android:layout_alignParentEnd="true"
+            android:tint="@color/notification_guts_link_icon_tint"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/inline_controls"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingEnd="@*android:dimen/notification_content_margin_end"
+        android:layout_marginTop="@dimen/notification_guts_option_vertical_padding"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:orientation="horizontal">
+            <ImageView
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:contentDescription="@null"
+                android:src="@drawable/ic_info"
+                android:tint="?android:attr/textColorPrimary"
+                android:layout_marginEnd="8dp"/>
+            <TextView
+                android:id="@+id/non_configurable_text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.NotificationImportanceChannelGroup" />
+        </LinearLayout>
+
+        <RelativeLayout
+            android:id="@+id/bottom_buttons"
+            android:layout_width="match_parent"
+            android:layout_height="60dp"
+            android:gravity="center_vertical"
+            android:paddingStart="4dp"
+            android:paddingEnd="4dp"
+            >
+            <TextView
+                android:id="@+id/turn_off_notifications"
+                android:text="@string/inline_turn_off_notifications"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentStart="true"
+                android:gravity="start|center_vertical"
+                android:minWidth="@dimen/notification_importance_toggle_size"
+                android:minHeight="@dimen/notification_importance_toggle_size"
+                android:maxWidth="200dp"
+                style="@style/TextAppearance.NotificationInfo.Button"/>
+            <TextView
+                android:id="@+id/done"
+                android:text="@string/inline_done_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:gravity="end|center_vertical"
+                android:minWidth="@dimen/notification_importance_toggle_size"
+                android:minHeight="@dimen/notification_importance_toggle_size"
+                android:maxWidth="125dp"
+                style="@style/TextAppearance.NotificationInfo.Button"/>
+        </RelativeLayout>
+
+    </LinearLayout>
+</com.android.systemui.statusbar.notification.row.PartialConversationInfo>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9f0f482..43ebb40 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1847,6 +1847,9 @@
     <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level -->
     <string name="notification_priority_title">Priority</string>
 
+    <!-- Text shown in notification guts for conversation notifications that don't implement the full feature -->
+    <string name="no_shortcut"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> does not support conversation specific settings</string>
+
     <!-- [CHAR LIMIT=NONE] Empty overflow title -->
     <string name="bubble_overflow_empty_title">No recent bubbles</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 290816b..fdf2c34 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -82,6 +82,7 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
@@ -162,6 +163,9 @@
     private static final long SCREENSHOT_TO_CORNER_X_DURATION_MS = 234;
     private static final long SCREENSHOT_TO_CORNER_Y_DURATION_MS = 500;
     private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
+    private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
+    private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100;
+    private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
     private static final float ROUNDED_CORNER_RADIUS = .05f;
     private static final long SCREENSHOT_CORNER_TIMEOUT_MILLIS = 6000;
     private static final int MESSAGE_CORNER_TIMEOUT = 2;
@@ -263,6 +267,7 @@
         mScreenshotSelectorView.setFocusableInTouchMode(true);
         mScreenshotView.setPivotX(0);
         mScreenshotView.setPivotY(0);
+        mActionsContainer.setPivotX(0);
 
         // Setup the window that we are going to use
         mWindowLayoutParams = new WindowManager.LayoutParams(
@@ -661,6 +666,8 @@
         } catch (RemoteException e) {
         }
 
+        ArrayList<ScreenshotActionChip> chips = new ArrayList<>();
+
         for (Notification.Action smartAction : imageData.smartActions) {
             ScreenshotActionChip actionChip = (ScreenshotActionChip) inflater.inflate(
                     R.layout.global_screenshot_action_chip, mActionsView, false);
@@ -673,6 +680,7 @@
                         mOnCompleteRunnable.run();
                     });
             mActionsView.addView(actionChip);
+            chips.add(actionChip);
         }
 
         ScreenshotActionChip shareChip = (ScreenshotActionChip) inflater.inflate(
@@ -685,6 +693,7 @@
             mOnCompleteRunnable.run();
         });
         mActionsView.addView(shareChip);
+        chips.add(shareChip);
 
         ScreenshotActionChip editChip = (ScreenshotActionChip) inflater.inflate(
                 R.layout.global_screenshot_action_chip, mActionsView, false);
@@ -696,6 +705,7 @@
             mOnCompleteRunnable.run();
         });
         mActionsView.addView(editChip);
+        chips.add(editChip);
 
         mScreenshotView.setOnClickListener(v -> {
             try {
@@ -709,7 +719,6 @@
         });
         mScreenshotView.setContentDescription(imageData.editAction.title);
 
-
         if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_SCROLLING_ENABLED, false)) {
             ScreenshotActionChip scrollChip = (ScreenshotActionChip) inflater.inflate(
                     R.layout.global_screenshot_action_chip, mActionsView, false);
@@ -723,18 +732,27 @@
                 scrollNotImplemented.show();
             });
             mActionsView.addView(scrollChip);
+            chips.add(scrollChip);
         }
 
         ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
-        mActionsContainer.setY(mDisplayMetrics.heightPixels);
+        animator.setDuration(SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS);
+        float alphaFraction = (float) SCREENSHOT_ACTIONS_ALPHA_DURATION_MS
+                / SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS;
         mActionsContainer.setVisibility(VISIBLE);
-        mActionsContainer.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-        float actionsViewHeight = mActionsContainer.getMeasuredHeight() + mScreenshotHeightPx;
+        mActionsContainer.setAlpha(0);
 
         animator.addUpdateListener(animation -> {
             float t = animation.getAnimatedFraction();
             mBackgroundProtection.setAlpha(t);
-            mActionsContainer.setY(mDisplayMetrics.heightPixels - actionsViewHeight * t);
+            mActionsContainer.setAlpha(t < alphaFraction ? t / alphaFraction : 1);
+            float containerScale = SCREENSHOT_ACTIONS_START_SCALE_X
+                    + (t * (1 - SCREENSHOT_ACTIONS_START_SCALE_X));
+            mActionsContainer.setScaleX(containerScale);
+            for (ScreenshotActionChip chip : chips) {
+                chip.setAlpha(t);
+                chip.setScaleX(1 / containerScale); // invert to keep size of children constant
+            }
         });
         return animator;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationChannelHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationChannelHelper.java
index ff945d1..1c2a00e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationChannelHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationChannelHelper.java
@@ -26,7 +26,6 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
@@ -44,32 +43,18 @@
         if (!TextUtils.isEmpty(channel.getConversationId())) {
             return channel;
         }
-        final String conversationId = entry.getSbn().getShortcutId(context);
+        final String conversationId = entry.getSbn().getShortcutId();
         final String pkg = entry.getSbn().getPackageName();
         final int appUid = entry.getSbn().getUid();
-        if (TextUtils.isEmpty(conversationId) || TextUtils.isEmpty(pkg)) {
+        if (TextUtils.isEmpty(conversationId) || TextUtils.isEmpty(pkg)
+            || entry.getRanking().getShortcutInfo() == null) {
             return channel;
         }
 
-        String name;
-        if (entry.getRanking().getShortcutInfo() != null) {
-            name = entry.getRanking().getShortcutInfo().getShortLabel().toString();
-        } else {
-            Bundle extras = entry.getSbn().getNotification().extras;
-            String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
-            if (TextUtils.isEmpty(nameString)) {
-                nameString = extras.getString(Notification.EXTRA_TITLE);
-            }
-            name = nameString;
-        }
-
         // If this channel is not already a customized conversation channel, create
         // a custom channel
         try {
-            // TODO: When shortcuts are enforced remove this and use the shortcut label for naming
-            channel.setName(context.getString(
-                    R.string.notification_summary_message_format,
-                    name, channel.getName()));
+            channel.setName(getName(entry));
             notificationManager.createConversationNotificationChannelForPackage(
                     pkg, appUid, entry.getSbn().getKey(), channel,
                     conversationId);
@@ -81,4 +66,19 @@
         }
         return channel;
     }
+
+    private static String getName(NotificationEntry entry) {
+        if (entry.getRanking().getShortcutInfo().getShortLabel() != null) {
+            return entry.getRanking().getShortcutInfo().getShortLabel().toString();
+        }
+        Bundle extras = entry.getSbn().getNotification().extras;
+        String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
+        if (TextUtils.isEmpty(nameString)) {
+            nameString = extras.getString(Notification.EXTRA_TITLE);
+        }
+        if (TextUtils.isEmpty(nameString)) {
+            nameString = "fallback";
+        }
+        return nameString;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a9bb416..66b2ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1141,6 +1141,7 @@
         if (mMenuRow.shouldUseDefaultMenuItems()) {
             ArrayList<MenuItem> items = new ArrayList<>();
             items.add(NotificationMenuRow.createConversationItem(mContext));
+            items.add(NotificationMenuRow.createPartialConversationItem(mContext));
             items.add(NotificationMenuRow.createInfoItem(mContext));
             items.add(NotificationMenuRow.createSnoozeItem(mContext));
             items.add(NotificationMenuRow.createAppOpsItem(mContext));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index f23f3bf..e9849ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1347,11 +1347,11 @@
         if (bubbleButton == null || actionContainer == null) {
             return;
         }
-        boolean isPerson =
+        boolean isPersonWithShortcut =
                 mPeopleIdentifier.getPeopleNotificationType(entry.getSbn(), entry.getRanking())
-                        != PeopleNotificationIdentifier.TYPE_NON_PERSON;
+                        >= PeopleNotificationIdentifier.TYPE_FULL_PERSON;
         boolean showButton = isBubblesEnabled()
-                && isPerson
+                && isPersonWithShortcut
                 && entry.getBubbleMetadata() != null;
         if (showButton) {
             Drawable d = mContext.getResources().getDrawable(entry.isBubble()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 23b911b..863951e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -97,7 +97,6 @@
     private String mDelegatePkg;
     private NotificationChannel mNotificationChannel;
     private ShortcutInfo mShortcutInfo;
-    private String mConversationId;
     private StatusBarNotification mSbn;
     @Nullable private Notification.BubbleMetadata mBubbleMetadata;
     private Context mUserContext;
@@ -233,14 +232,10 @@
         mBuilderProvider = builderProvider;
 
         mShortcutManager = shortcutManager;
-        mConversationId = mNotificationChannel.getConversationId();
-        if (TextUtils.isEmpty(mNotificationChannel.getConversationId())) {
-            mConversationId = mSbn.getShortcutId(mContext);
-        }
-        if (TextUtils.isEmpty(mConversationId)) {
+        mShortcutInfo = entry.getRanking().getShortcutInfo();
+        if (mShortcutInfo == null) {
             throw new IllegalArgumentException("Does not have required information");
         }
-        mShortcutInfo = entry.getRanking().getShortcutInfo();
 
         mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded(
                 getContext(), mINotificationManager, entry, mNotificationChannel);
@@ -319,31 +314,9 @@
 
     private void bindIcon(boolean important) {
         ImageView image = findViewById(R.id.conversation_icon);
-        if (mShortcutInfo != null) {
-            image.setImageDrawable(mIconFactory.getConversationDrawable(
-                    mShortcutInfo, mPackageName, mAppUid,
-                    important));
-        } else {
-            if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) {
-                // TODO: maybe use a generic group icon, or a composite of recent senders
-                image.setImageDrawable(mPm.getDefaultActivityIcon());
-            } else {
-                final List<Notification.MessagingStyle.Message> messages =
-                        Notification.MessagingStyle.Message.getMessagesFromBundleArray(
-                                (Parcelable[]) mSbn.getNotification().extras.get(
-                                        Notification.EXTRA_MESSAGES));
+        image.setImageDrawable(mIconFactory.getConversationDrawable(
+                mShortcutInfo, mPackageName, mAppUid, important));
 
-                final Notification.MessagingStyle.Message latestMessage =
-                        Notification.MessagingStyle.findLatestIncomingMessage(messages);
-                Icon personIcon = latestMessage.getSenderPerson().getIcon();
-                if (personIcon != null) {
-                    image.setImageIcon(latestMessage.getSenderPerson().getIcon());
-                } else {
-                    // TODO: choose something better
-                    image.setImageDrawable(mPm.getDefaultActivityIcon());
-                }
-            }
-        }
     }
 
     private void bindPackage() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 1c808cf9..9c7de2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -252,6 +252,9 @@
             } else if (gutsView instanceof NotificationConversationInfo) {
                 initializeConversationNotificationInfo(
                         row, (NotificationConversationInfo) gutsView);
+            } else if (gutsView instanceof PartialConversationInfo) {
+                initializePartialConversationNotificationInfo(row,
+                        (PartialConversationInfo) gutsView);
             }
             return true;
         } catch (Exception e) {
@@ -357,7 +360,47 @@
     }
 
     /**
-     * Sets up the {@link NotificationConversationInfo} inside the notification row's guts.
+     * Sets up the {@link PartialConversationInfo} inside the notification row's guts.
+     * @param row view to set up the guts for
+     * @param notificationInfoView view to set up/bind within {@code row}
+     */
+    @VisibleForTesting
+    void initializePartialConversationNotificationInfo(
+            final ExpandableNotificationRow row,
+            PartialConversationInfo notificationInfoView) throws Exception {
+        NotificationGuts guts = row.getGuts();
+        StatusBarNotification sbn = row.getEntry().getSbn();
+        String packageName = sbn.getPackageName();
+        // Settings link is only valid for notifications that specify a non-system user
+        NotificationInfo.OnSettingsClickListener onSettingsClick = null;
+        UserHandle userHandle = sbn.getUser();
+        PackageManager pmUser = StatusBar.getPackageManagerForUser(
+                mContext, userHandle.getIdentifier());
+
+        if (!userHandle.equals(UserHandle.ALL)
+                || mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
+            onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
+                mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
+                guts.resetFalsingCheck();
+                mOnSettingsClickListener.onSettingsClick(sbn.getKey());
+                startAppNotificationSettingsActivity(packageName, appUid, channel, row);
+            };
+        }
+
+        notificationInfoView.bindNotification(
+                pmUser,
+                mNotificationManager,
+                packageName,
+                row.getEntry().getChannel(),
+                row.getUniqueChannels(),
+                row.getEntry(),
+                onSettingsClick,
+                mDeviceProvisionedController.isDeviceProvisioned(),
+                row.getIsNonblockable());
+    }
+
+    /**
+     * Sets up the {@link ConversationInfo} inside the notification row's guts.
      * @param row view to set up the guts for
      * @param notificationInfoView view to set up/bind within {@code row}
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 83a6eb2..5e1e3b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -268,7 +268,9 @@
         NotificationEntry entry = mParent.getEntry();
         int personNotifType = mPeopleNotificationIdentifier
                 .getPeopleNotificationType(entry.getSbn(), entry.getRanking());
-        if (personNotifType != PeopleNotificationIdentifier.TYPE_NON_PERSON) {
+        if (personNotifType == PeopleNotificationIdentifier.TYPE_PERSON) {
+            mInfoItem = createPartialConversationItem(mContext);
+        } else if (personNotifType >= PeopleNotificationIdentifier.TYPE_FULL_PERSON) {
             mInfoItem = createConversationItem(mContext);
         } else {
             mInfoItem = createInfoItem(mContext);
@@ -667,6 +669,16 @@
                 R.drawable.ic_settings);
     }
 
+    static NotificationMenuItem createPartialConversationItem(Context context) {
+        Resources res = context.getResources();
+        String infoDescription = res.getString(R.string.notification_menu_gear_description);
+        PartialConversationInfo infoContent =
+                (PartialConversationInfo) LayoutInflater.from(context).inflate(
+                        R.layout.partial_conversation_info, null, false);
+        return new NotificationMenuItem(context, infoDescription, infoContent,
+                R.drawable.ic_settings);
+    }
+
     static NotificationMenuItem createInfoItem(Context context) {
         Resources res = context.getResources();
         String infoDescription = res.getString(R.string.notification_menu_gear_description);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
new file mode 100644
index 0000000..2189b87
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.notification.row;
+
+import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+
+import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
+import android.transition.ChangeBounds;
+import android.transition.Fade;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.lang.annotation.Retention;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The guts of a conversation notification that doesn't use valid shortcuts that is revealed when
+ * performing a long press.
+ */
+public class PartialConversationInfo extends LinearLayout implements
+        NotificationGuts.GutsContent {
+    private static final String TAG = "PartialConvoGuts";
+
+    private INotificationManager mINotificationManager;
+    private PackageManager mPm;
+    private String mPackageName;
+    private String mAppName;
+    private int mAppUid;
+    private String mDelegatePkg;
+    private NotificationChannel mNotificationChannel;
+    private StatusBarNotification mSbn;
+    private boolean mIsDeviceProvisioned;
+    private boolean mIsNonBlockable;
+    private Set<NotificationChannel> mUniqueChannelsInRow;
+    private Drawable mPkgIcon;
+
+    private @Action int mSelectedAction = -1;
+    private boolean mPressedApply;
+    private boolean mPresentingChannelEditorDialog = false;
+
+    private NotificationInfo.OnSettingsClickListener mOnSettingsClickListener;
+    private NotificationGuts mGutsContainer;
+    private ChannelEditorDialogController mChannelEditorDialogController;
+
+    @VisibleForTesting
+    boolean mSkipPost = false;
+
+    @Retention(SOURCE)
+    @IntDef({ACTION_SETTINGS})
+    private @interface Action {}
+    static final int ACTION_SETTINGS = 5;
+
+    private OnClickListener mOnDone = v -> {
+        mPressedApply = true;
+        closeControls(v, true);
+    };
+
+    public PartialConversationInfo(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void bindNotification(
+            PackageManager pm,
+            INotificationManager iNotificationManager,
+            String pkg,
+            NotificationChannel notificationChannel,
+            Set<NotificationChannel> uniqueChannelsInRow,
+            NotificationEntry entry,
+            NotificationInfo.OnSettingsClickListener onSettingsClick,
+            boolean isDeviceProvisioned,
+            boolean isNonBlockable) {
+        mSelectedAction = -1;
+        mINotificationManager = iNotificationManager;
+        mPackageName = pkg;
+        mSbn = entry.getSbn();
+        mPm = pm;
+        mAppName = mPackageName;
+        mOnSettingsClickListener = onSettingsClick;
+        mNotificationChannel = notificationChannel;
+        mAppUid = mSbn.getUid();
+        mDelegatePkg = mSbn.getOpPkg();
+        mIsDeviceProvisioned = isDeviceProvisioned;
+        mIsNonBlockable = isNonBlockable;
+        mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class);
+        mUniqueChannelsInRow = uniqueChannelsInRow;
+
+        bindHeader();
+        bindActions();
+
+        View turnOffButton = findViewById(R.id.turn_off_notifications);
+        turnOffButton.setOnClickListener(getTurnOffNotificationsClickListener());
+        turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonBlockable
+                ? VISIBLE : GONE);
+
+        View done = findViewById(R.id.done);
+        done.setOnClickListener(mOnDone);
+    }
+
+    private void bindActions() {
+        final View settingsButton = findViewById(R.id.info);
+        settingsButton.setOnClickListener(getSettingsOnClickListener());
+        settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
+
+        TextView msg = findViewById(R.id.non_configurable_text);
+        msg.setText(getResources().getString(R.string.no_shortcut, mAppName));
+    }
+
+    private void bindHeader() {
+        bindConversationDetails();
+
+        // Delegate
+        bindDelegate();
+    }
+
+    private OnClickListener getSettingsOnClickListener() {
+        if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
+            final int appUidF = mAppUid;
+            return ((View view) -> {
+                mOnSettingsClickListener.onClick(view, mNotificationChannel, appUidF);
+            });
+        }
+        return null;
+    }
+
+    private OnClickListener getTurnOffNotificationsClickListener() {
+        return ((View view) -> {
+            if (!mPresentingChannelEditorDialog && mChannelEditorDialogController != null) {
+                mPresentingChannelEditorDialog = true;
+
+                mChannelEditorDialogController.prepareDialogForApp(mAppName, mPackageName, mAppUid,
+                        mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
+                mChannelEditorDialogController.setOnFinishListener(() -> {
+                    mPresentingChannelEditorDialog = false;
+                    closeControls(this, false);
+                });
+                mChannelEditorDialogController.show();
+            }
+        });
+    }
+
+    private void bindConversationDetails() {
+        final TextView channelName = findViewById(R.id.parent_channel_name);
+        channelName.setText(mNotificationChannel.getName());
+
+        bindGroup();
+        bindName();
+        bindPackage();
+        bindIcon();
+    }
+
+    private void bindName() {
+        TextView name = findViewById(R.id.name);
+        Bundle extras = mSbn.getNotification().extras;
+        String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
+        if (TextUtils.isEmpty(nameString)) {
+            nameString = extras.getString(Notification.EXTRA_TITLE);
+        }
+        name.setText(nameString);
+    }
+
+    private void bindIcon() {
+        ImageView image = findViewById(R.id.conversation_icon);
+        if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) {
+            // TODO: maybe use a generic group icon, or a composite of recent senders
+            image.setImageDrawable(mPkgIcon);
+        } else {
+            final List<Notification.MessagingStyle.Message> messages =
+                    Notification.MessagingStyle.Message.getMessagesFromBundleArray(
+                            (Parcelable[]) mSbn.getNotification().extras.get(
+                                    Notification.EXTRA_MESSAGES));
+
+            final Notification.MessagingStyle.Message latestMessage =
+                    Notification.MessagingStyle.findLatestIncomingMessage(messages);
+            Icon personIcon = null;
+            if (latestMessage != null && latestMessage.getSenderPerson() != null) {
+                personIcon = latestMessage.getSenderPerson().getIcon();
+            }
+            if (personIcon != null) {
+                image.setImageIcon(latestMessage.getSenderPerson().getIcon());
+            } else {
+                image.setImageDrawable(mPkgIcon);
+            }
+        }
+    }
+
+    private void bindPackage() {
+        ApplicationInfo info;
+        try {
+            info = mPm.getApplicationInfo(
+                    mPackageName,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                            | PackageManager.MATCH_DISABLED_COMPONENTS
+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+            if (info != null) {
+                mAppName = String.valueOf(mPm.getApplicationLabel(info));
+                mPkgIcon = mPm.getApplicationIcon(info);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            mPkgIcon = mPm.getDefaultActivityIcon();
+        }
+        ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
+    }
+
+    private void bindDelegate() {
+        TextView delegateView = findViewById(R.id.delegate_name);
+
+        if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
+            // this notification was posted by a delegate!
+            delegateView.setVisibility(View.VISIBLE);
+        } else {
+            delegateView.setVisibility(View.GONE);
+        }
+    }
+
+    private void bindGroup() {
+        // Set group information if this channel has an associated group.
+        CharSequence groupName = null;
+        if (mNotificationChannel != null && mNotificationChannel.getGroup() != null) {
+            try {
+                final NotificationChannelGroup notificationChannelGroup =
+                        mINotificationManager.getNotificationChannelGroupForPackage(
+                                mNotificationChannel.getGroup(), mPackageName, mAppUid);
+                if (notificationChannelGroup != null) {
+                    groupName = notificationChannelGroup.getName();
+                }
+            } catch (RemoteException e) {
+            }
+        }
+        TextView groupNameView = findViewById(R.id.group_name);
+        View groupDivider = findViewById(R.id.group_divider);
+        if (groupName != null) {
+            groupNameView.setText(groupName);
+            groupNameView.setVisibility(VISIBLE);
+            groupDivider.setVisibility(VISIBLE);
+        } else {
+            groupNameView.setVisibility(GONE);
+            groupDivider.setVisibility(GONE);
+        }
+    }
+
+    @Override
+    public boolean post(Runnable action) {
+        if (mSkipPost) {
+            action.run();
+            return true;
+        } else {
+            return super.post(action);
+        }
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+    }
+
+    @Override
+    public void onFinishedClosing() {
+        // TODO: do we need to do anything here?
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        if (mGutsContainer != null &&
+                event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+            if (mGutsContainer.isExposed()) {
+                event.getText().add(mContext.getString(
+                        R.string.notification_channel_controls_opened_accessibility, mAppName));
+            } else {
+                event.getText().add(mContext.getString(
+                        R.string.notification_channel_controls_closed_accessibility, mAppName));
+            }
+        }
+    }
+
+    /**
+     * Closes the controls and commits the updated importance values (indirectly).
+     *
+     * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
+     * user does not have the ability to undo the action anymore.
+     */
+    @VisibleForTesting
+    void closeControls(View v, boolean save) {
+        int[] parentLoc = new int[2];
+        int[] targetLoc = new int[2];
+        mGutsContainer.getLocationOnScreen(parentLoc);
+        v.getLocationOnScreen(targetLoc);
+        final int centerX = v.getWidth() / 2;
+        final int centerY = v.getHeight() / 2;
+        final int x = targetLoc[0] - parentLoc[0] + centerX;
+        final int y = targetLoc[1] - parentLoc[1] + centerY;
+        mGutsContainer.closeControls(x, y, save, false /* force */);
+    }
+
+    @Override
+    public void setGutsParent(NotificationGuts guts) {
+        mGutsContainer = guts;
+    }
+
+    @Override
+    public boolean willBeRemoved() {
+        return false;
+    }
+
+    @Override
+    public boolean shouldBeSaved() {
+        return mPressedApply;
+    }
+
+    @Override
+    public View getContentView() {
+        return this;
+    }
+
+    @Override
+    public boolean handleCloseControls(boolean save, boolean force) {
+        return false;
+    }
+
+    @Override
+    public int getActualHeight() {
+        return getHeight();
+    }
+
+    @VisibleForTesting
+    public boolean isAnimating() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 6193a8e..428de9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -30,6 +30,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
 
@@ -47,6 +48,8 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -54,7 +57,8 @@
  */
 @Singleton
 public class StatusBarRemoteInputCallback implements Callback, Callbacks,
-        StatusBarStateController.StateListener {
+        StatusBarStateController.StateListener, KeyguardStateController.Callback {
+    private static final String TAG = StatusBarRemoteInputCallback.class.getSimpleName();
 
     private final KeyguardStateController mKeyguardStateController;
     private final SysuiStatusBarStateController mStatusBarStateController;
@@ -72,6 +76,7 @@
     private int mDisabled2;
     protected BroadcastReceiver mChallengeReceiver = new ChallengeReceiver();
     private Handler mMainHandler = new Handler();
+    private final AtomicReference<Intent> mPendingConfirmCredentialIntent = new AtomicReference();
 
     /**
      */
@@ -98,6 +103,9 @@
         mCommandQueue.addCallback(this);
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
         mGroupManager = groupManager;
+        // Listen to onKeyguardShowingChanged in case a managed profile needs to be unlocked
+        // once the primary profile's keyguard is no longer shown.
+        mKeyguardStateController.addCallback(this);
     }
 
     @Override
@@ -201,12 +209,39 @@
         // Clear pending remote view, as we do not want to trigger pending remote input view when
         // it's called by other code
         mPendingWorkRemoteInputView = null;
-        // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
-        final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
-                null, userId);
+
+        final Intent newIntent = createConfirmDeviceCredentialIntent(
+                userId, intendSender, notificationKey);
         if (newIntent == null) {
+            Log.w(TAG, String.format("Cannot create intent to unlock user %d", userId));
             return false;
         }
+
+        mPendingConfirmCredentialIntent.set(newIntent);
+
+        // If the Keyguard is currently showing, starting the ConfirmDeviceCredentialActivity
+        // would cause it to pause, not letting the user actually unlock the managed profile.
+        // Instead, wait until we receive a callback indicating it is no longer showing and
+        // then start the pending intent.
+        if (mKeyguardStateController.isShowing()) {
+            // Do nothing, since the callback will get the pending intent and start it.
+            Log.w(TAG, String.format("Keyguard is showing, waiting until it's not"));
+        } else {
+            startPendingConfirmDeviceCredentialIntent();
+        }
+
+        return true;
+    }
+
+    private Intent createConfirmDeviceCredentialIntent(
+            int userId, IntentSender intendSender, String notificationKey) {
+        final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
+                null, userId);
+
+        if (newIntent == null) {
+            return null;
+        }
+
         final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
         callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
         callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
@@ -222,14 +257,40 @@
         newIntent.putExtra(
                 Intent.EXTRA_INTENT,
                 callBackPendingIntent.getIntentSender());
+
+        return newIntent;
+    }
+
+    private void startPendingConfirmDeviceCredentialIntent() {
+        final Intent pendingIntent = mPendingConfirmCredentialIntent.getAndSet(null);
+        if (pendingIntent == null) {
+            return;
+        }
+
         try {
-            ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
+            if (mKeyguardStateController.isShowing()) {
+                Log.w(TAG, "Keyguard is showing while starting confirm device credential intent.");
+            }
+            ActivityManager.getService().startConfirmDeviceCredentialIntent(pendingIntent,
                     null /*options*/);
         } catch (RemoteException ex) {
             // ignore
         }
-        return true;
-        // End old BaseStatusBar.startWorkChallengeIfNecessary.
+    }
+
+    @Override
+    public void onKeyguardShowingChanged() {
+        if (mKeyguardStateController.isShowing()) {
+            // In order to avoid jarring UX where/ the managed profile challenge is shown and
+            // immediately dismissed, do not attempt to start the confirm device credential
+            // activity if the keyguard is still showing.
+            if (mPendingConfirmCredentialIntent.get() != null) {
+                Log.w(TAG, "There's a pending unlock intent but keyguard is still showing, abort.");
+            }
+            return;
+        }
+
+        startPendingConfirmDeviceCredentialIntent();
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 3847028..dbf40e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -386,7 +386,10 @@
                 applicationInfo);
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
 
-        NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
+        NotificationEntry entry = new NotificationEntryBuilder()
+                .setSbn(mSbn)
+                .setShortcutInfo(mShortcutInfo)
+                .build();
         mNotificationInfo.bindNotification(
                 mShortcutManager,
                 mMockPackageManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
new file mode 100644
index 0000000..c390e39
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.notification.row;
+
+import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.Person;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class PartialConversationInfoTest extends SysuiTestCase {
+    private static final String TEST_PACKAGE_NAME = "test_package";
+    private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME;
+    private static final int TEST_UID = 1;
+    private static final String TEST_CHANNEL = "test_channel";
+    private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
+
+    private TestableLooper mTestableLooper;
+    private PartialConversationInfo mInfo;
+    private NotificationChannel mNotificationChannel;
+    private NotificationChannel mDefaultNotificationChannel;
+    private Set<NotificationChannel> mNotificationChannelSet = new HashSet<>();
+    private Set<NotificationChannel> mDefaultNotificationChannelSet = new HashSet<>();
+    private StatusBarNotification mSbn;
+    private NotificationEntry mEntry;
+
+    @Rule
+    public MockitoRule mockito = MockitoJUnit.rule();
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private INotificationManager mMockINotificationManager;
+    @Mock
+    private PackageManager mMockPackageManager;
+
+    @Mock
+    private Icon mIcon;
+    @Mock
+    private Drawable mDrawable;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestableLooper = TestableLooper.get(this);
+
+        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+        // Inflate the layout
+        final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+        mInfo = (PartialConversationInfo) layoutInflater.inflate(R.layout.partial_conversation_info,
+                null);
+        mInfo.setGutsParent(mock(NotificationGuts.class));
+        // Our view is never attached to a window so the View#post methods in NotificationInfo never
+        // get called. Setting this will skip the post and do the action immediately.
+        mInfo.mSkipPost = true;
+
+        // PackageManager must return a packageInfo and applicationInfo.
+        final PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = TEST_PACKAGE_NAME;
+        when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()))
+                .thenReturn(packageInfo);
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.uid = TEST_UID;  // non-zero
+        when(mMockPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt())).thenReturn(
+                applicationInfo);
+        final PackageInfo systemPackageInfo = new PackageInfo();
+        systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME;
+        when(mMockPackageManager.getPackageInfo(eq(TEST_SYSTEM_PACKAGE_NAME), anyInt()))
+                .thenReturn(systemPackageInfo);
+        when(mMockPackageManager.getPackageInfo(eq("android"), anyInt()))
+                .thenReturn(packageInfo);
+
+        // Package has one channel by default.
+        when(mMockINotificationManager.getNumNotificationChannelsForPackage(
+                eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(1);
+
+        when(mIcon.loadDrawable(any())).thenReturn(mDrawable);
+
+        // Some test channels.
+        mNotificationChannel = new NotificationChannel(
+                TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
+        mNotificationChannelSet.add(mNotificationChannel);
+        mDefaultNotificationChannel = new NotificationChannel(
+                NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
+                IMPORTANCE_LOW);
+        mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
+        mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
+                new Notification(), UserHandle.CURRENT, null, 0);
+        mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+    }
+
+    @Test
+    public void testBindNotification_SetsTextApplicationName() throws Exception {
+        when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final TextView textView = mInfo.findViewById(R.id.pkg_name);
+        assertTrue(textView.getText().toString().contains("App Name"));
+        assertEquals(VISIBLE, mInfo.findViewById(R.id.header).getVisibility());
+    }
+
+    @Test
+    public void testBindNotification_groupSetsPackageIcon() {
+        mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, true);
+        final Drawable iconDrawable = mock(Drawable.class);
+        when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
+                .thenReturn(iconDrawable);
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
+        assertEquals(iconDrawable, iconView.getDrawable());
+    }
+
+    @Test
+    public void testBindNotification_notGroupSetsMessageIcon() {
+        Notification n = new Notification.Builder(mContext, TEST_CHANNEL_NAME)
+                .setStyle(new Notification.MessagingStyle(
+                        new Person.Builder().setName("me").build())
+                .addMessage(new Notification.MessagingStyle.Message("hello", 0,
+                        new Person.Builder().setName("friend").setIcon(mIcon).build())))
+                .build();
+        mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
+                n, UserHandle.CURRENT, null, 0);
+        mEntry.setSbn(mSbn);
+        mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, false);
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
+        assertEquals(mDrawable.hashCode() + "", mDrawable, iconView.getDrawable());
+    }
+
+    @Test
+    public void testBindNotification_noDelegate() {
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final TextView nameView = mInfo.findViewById(R.id.delegate_name);
+        assertEquals(GONE, nameView.getVisibility());
+        final TextView dividerView = mInfo.findViewById(R.id.group_divider);
+        assertEquals(GONE, dividerView.getVisibility());
+    }
+
+    @Test
+    public void testBindNotification_delegate() throws Exception {
+        mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, "other", 0, null, TEST_UID, 0,
+                new Notification(), UserHandle.CURRENT, null, 0);
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.uid = 7;  // non-zero
+        when(mMockPackageManager.getApplicationInfo(eq("other"), anyInt())).thenReturn(
+                applicationInfo);
+        when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
+
+        NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                entry,
+                null,
+                true,
+                false);
+        final TextView nameView = mInfo.findViewById(R.id.delegate_name);
+        assertEquals(VISIBLE, nameView.getVisibility());
+        assertTrue(nameView.getText().toString().contains("Proxied"));
+    }
+
+    @Test
+    public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final TextView groupNameView = mInfo.findViewById(R.id.group_name);
+        assertEquals(GONE, groupNameView.getVisibility());
+        final TextView dividerView = mInfo.findViewById(R.id.group_divider);
+        assertEquals(GONE, dividerView.getVisibility());
+    }
+
+    @Test
+    public void testBindNotification_SetsGroupNameIfNonNull() throws Exception {
+        mNotificationChannel.setGroup("test_group_id");
+        final NotificationChannelGroup notificationChannelGroup =
+                new NotificationChannelGroup("test_group_id", "Test Group Name");
+        when(mMockINotificationManager.getNotificationChannelGroupForPackage(
+                eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
+                .thenReturn(notificationChannelGroup);
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final TextView groupNameView = mInfo.findViewById(R.id.group_name);
+        assertEquals(View.VISIBLE, groupNameView.getVisibility());
+        assertEquals("Test Group Name", groupNameView.getText());
+        final TextView dividerView = mInfo.findViewById(R.id.group_divider);
+        assertEquals(View.VISIBLE, dividerView.getVisibility());
+    }
+
+    @Test
+    public void testBindNotification_SetsTextChannelName() {
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final TextView textView = mInfo.findViewById(R.id.parent_channel_name);
+        assertEquals(TEST_CHANNEL_NAME, textView.getText());
+    }
+
+    @Test
+    public void testBindNotification_SetsOnClickListenerForSettings() {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                (View v, NotificationChannel c, int appUid) -> {
+                    assertEquals(mNotificationChannel, c);
+                    latch.countDown();
+                },
+                true,
+                false);
+
+        final View settingsButton = mInfo.findViewById(R.id.info);
+        settingsButton.performClick();
+        // Verify that listener was triggered.
+        assertEquals(0, latch.getCount());
+    }
+
+    @Test
+    public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() {
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                false);
+        final View settingsButton = mInfo.findViewById(R.id.info);
+        assertTrue(settingsButton.getVisibility() != View.VISIBLE);
+    }
+
+    @Test
+    public void testBindNotification_SettingsButtonInvisibleWhenDeviceUnprovisioned() {
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                (View v, NotificationChannel c, int appUid) -> {
+                    assertEquals(mNotificationChannel, c);
+                },
+                false,
+                false);
+        final View settingsButton = mInfo.findViewById(R.id.info);
+        assertTrue(settingsButton.getVisibility() != View.VISIBLE);
+    }
+
+    @Test
+    public void testBindNotification_whenAppUnblockable() {
+        mInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                true,
+                true);
+
+        assertEquals(GONE,
+                mInfo.findViewById(R.id.turn_off_notifications).getVisibility());
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
index 83ca699..2f60e42 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
@@ -47,7 +47,7 @@
         NotificationChannel updatedChannel = mConfig.getConversationNotificationChannel(
                 record.getSbn().getPackageName(),
                 record.getSbn().getUid(), record.getChannel().getId(),
-                record.getSbn().getShortcutId(mContext), true, false);
+                record.getSbn().getShortcutId(), true, false);
         record.updateNotificationChannel(updatedChannel);
 
         return null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6c3177f..2f76a1f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2718,12 +2718,12 @@
         }
         return text == null ? null : String.valueOf(text);
     }
-    
+
     protected void maybeRegisterMessageSent(NotificationRecord r) {
         Context appContext = r.getSbn().getPackageContext(getContext());
-        Notification.Builder nb = 
+        Notification.Builder nb =
                 Notification.Builder.recoverBuilder(appContext, r.getNotification());
-        if (nb.getStyle() instanceof Notification.MessagingStyle) {
+        if (nb.getStyle() instanceof Notification.MessagingStyle && r.getShortcutInfo() == null) {
             mPreferencesHelper.setMessageSent(r.getSbn().getPackageName(), r.getUid());
             handleSavePolicyFile();
         }
@@ -5627,7 +5627,7 @@
         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
             channelId = (new Notification.TvExtender(notification)).getChannelId();
         }
-        String shortcutId = n.getShortcutId(getContext());
+        String shortcutId = n.getShortcutId();
         final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
                 pkg, notificationUid, channelId, shortcutId,
                 true /* parent ok */, false /* includeDeleted */);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index e45b41d..8e3de15 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1386,10 +1386,6 @@
                 || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
             return false;
         }
-        if (mShortcutInfo == null && Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 1) {
-            return false;
-        }
         if (mIsNotConversationOverride) {
             return false;
         }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 6d7b410..a4b99b3 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -116,7 +116,7 @@
     private static final String ATT_ENABLED = "enabled";
     private static final String ATT_USER_ALLOWED = "allowed";
     private static final String ATT_HIDE_SILENT = "hide_gentle";
-    private static final String ATT_SENT_MESSAGE = "sent_msg";
+    private static final String ATT_SENT_MESSAGE = "sent_invalid_msg";
 
     private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
     private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
@@ -194,8 +194,6 @@
         updateBadgingEnabled();
         updateBubblesEnabled();
         syncChannelsBypassingDnd(mContext.getUserId());
-        mAllowInvalidShortcuts = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0;
     }
 
     public void readXml(XmlPullParser parser, boolean forRestore, int userId)
@@ -1313,7 +1311,9 @@
             int N = r.channels.size();
             for (int i = 0; i < N; i++) {
                 final NotificationChannel nc = r.channels.valueAt(i);
-                if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()) {
+                if (!TextUtils.isEmpty(nc.getConversationId())
+                        && !nc.isDeleted()
+                        && !nc.isDemoted()) {
                     ConversationChannelWrapper conversation = new ConversationChannelWrapper();
                     conversation.setPkg(r.pkg);
                     conversation.setUid(r.uid);
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index 13892ba0..94f69e9 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -152,9 +152,13 @@
         if (shortcutInfo == null || !shortcutInfo.isLongLived() || !shortcutInfo.isEnabled()) {
             return false;
         }
-        return mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
+        // TODO (b/155016294) uncomment when sharing shortcuts are required
+        /*
+        mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
                 shortcutInfo.getPackage(), shortcutInfo.getId(), shortcutInfo.getUserId(),
                 SHARING_FILTER);
+         */
+        return true;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 982df4b..5a27f47 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1431,15 +1431,15 @@
 
     @Override
     void removeChild(WindowContainer child) {
-        // A rootable child task that is now being removed from an organized task. Making sure
-        // the stack references is keep updated.
-        if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
-            getDisplayArea().removeStackReferenceIfNeeded((ActivityStack) child);
-        }
         removeChild(child, "removeChild");
     }
 
     void removeChild(WindowContainer r, String reason) {
+        // A rootable child task that is now being removed from an organized task. Making sure
+        // the stack references is keep updated.
+        if (mTaskOrganizer != null && mCreatedByOrganizer && r.asTask() != null) {
+            getDisplayArea().removeStackReferenceIfNeeded((ActivityStack) r);
+        }
         if (!mChildren.contains(r)) {
             Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
             return;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
index a23ade6..77ce2f0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
@@ -76,8 +76,6 @@
 
     @Test
     public void testInvalidShortcutFlagEnabled_looksUpCorrectChannel() {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
 
         NotificationChannelExtractor extractor = new NotificationChannelExtractor();
         extractor.setConfig(mConfig);
@@ -96,7 +94,7 @@
         NotificationChannel updatedChannel =
                 new NotificationChannel("a", "", IMPORTANCE_HIGH);
         when(mConfig.getConversationNotificationChannel(
-                any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId(mContext)),
+                any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId()),
                 eq(true), eq(false)))
                 .thenReturn(updatedChannel);
 
@@ -106,8 +104,6 @@
 
     @Test
     public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
 
         NotificationChannelExtractor extractor = new NotificationChannelExtractor();
         extractor.setConfig(mConfig);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 41748b8..d5ecfeb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6589,14 +6589,45 @@
     }
 
     @Test
-    public void testRecordMessages() throws RemoteException {
+    public void testRecordMessages_invalidMsg() throws RemoteException {
         NotificationRecord nr =
                 generateMessageBubbleNotifRecord(mTestNotificationChannel,
-                        "testRecordMessages");
+                        "testRecordMessages_invalidMsg");
         mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
         waitForIdle();
 
         assertTrue(mBinderService.hasSentMessage(PKG, mUid));
     }
+
+    @Test
+    public void testRecordMessages_validMsg() throws RemoteException {
+        // Messaging notification with shortcut info
+        Notification.BubbleMetadata metadata =
+                new Notification.BubbleMetadata.Builder("id").build();
+        Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
+                null /* groupKey */, false /* isSummary */);
+        nb.setShortcutId("id");
+        nb.setBubbleMetadata(metadata);
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+                "testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        // Pretend the shortcut exists
+        List<ShortcutInfo> shortcutInfos = new ArrayList<>();
+        ShortcutInfo info = mock(ShortcutInfo.class);
+        when(info.getPackage()).thenReturn(PKG);
+        when(info.getId()).thenReturn("id");
+        when(info.getUserId()).thenReturn(USER_SYSTEM);
+        when(info.isLongLived()).thenReturn(true);
+        when(info.isEnabled()).thenReturn(true);
+        shortcutInfos.add(info);
+        when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        assertFalse(mBinderService.hasSentMessage(PKG, mUid));
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 3139bfa..9f593ce 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -123,8 +123,6 @@
         when(mMockContext.getResources()).thenReturn(getContext().getResources());
         when(mMockContext.getPackageManager()).thenReturn(mPm);
         when(mMockContext.getContentResolver()).thenReturn(mContentResolver);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.targetSdkVersion = Build.VERSION_CODES.O;
         when(mMockContext.getApplicationInfo()).thenReturn(appInfo);
@@ -1127,18 +1125,7 @@
     }
 
     @Test
-    public void testIsConversation_nullShortcut() {
-        StatusBarNotification sbn = getMessagingStyleNotification();
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        record.setShortcutInfo(null);
-
-        assertFalse(record.isConversation());
-    }
-
-    @Test
-    public void testIsConversation_bypassShortcutFlagEnabled() {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
+    public void testIsConversation_noShortcut() {
         StatusBarNotification sbn = getMessagingStyleNotification();
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         record.setShortcutInfo(null);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index e11392b..4320f1c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -3023,31 +3023,7 @@
     }
 
     @Test
-    public void testPlaceholderConversationId_shortcutNotRequired() throws Exception {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
-
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
-                mAppOpsManager);
-
-        final String xml = "<ranking version=\"1\">\n"
-                + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
-                + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>"
-                + "</package>"
-                + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
-                null);
-        parser.nextTag();
-        mHelper.readXml(parser, false, UserHandle.USER_ALL);
-
-        assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
-    }
-
-    @Test
     public void testPlaceholderConversationId_shortcutRequired() throws Exception {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
                 mAppOpsManager);
 
@@ -3067,8 +3043,6 @@
 
     @Test
     public void testNormalConversationId_shortcutRequired() throws Exception {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
                 mAppOpsManager);
 
@@ -3088,8 +3062,6 @@
 
     @Test
     public void testNoConversationId_shortcutRequired() throws Exception {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
                 mAppOpsManager);
 
@@ -3276,6 +3248,19 @@
     }
 
     @Test
+    public void testGetConversations_noDemoted() {
+        NotificationChannel parent = new NotificationChannel("parent", "p", 1);
+        mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+        NotificationChannel channel =
+                new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
+        channel.setConversationId("parent", "convo");
+        channel.setDemoted(true);
+        mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+        assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
+    }
+
+    @Test
     public void testGetConversations() {
         NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name");
         mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index 3095c87..eb2d9fe 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -40,6 +40,7 @@
 import com.android.server.UiServiceTestCase;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -184,6 +185,7 @@
         assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isNull();
     }
 
+    @Ignore("b/155016294")
     @Test
     public void testGetValidShortcutInfo_notSharingShortcut() {
         ShortcutInfo si = mock(ShortcutInfo.class);
@@ -229,8 +231,9 @@
         ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
         shortcuts.add(si);
         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcuts);
-        when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
-                anyString(), anyInt(), any())).thenReturn(true);
+        // TODO: b/155016294
+        //when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
+         //       anyString(), anyInt(), any())).thenReturn(true);
 
         assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isSameAs(si);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 6c209e4..5227f3c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -234,6 +234,25 @@
     }
 
     @Test
+    public void testRemoveOrganizedTask_UpdateStackReference() {
+        final ActivityStack rootHomeTask = mDefaultTaskDisplayArea.getRootHomeTask();
+        final ActivityRecord homeActivity = new ActivityBuilder(mService)
+                .setStack(rootHomeTask)
+                .setCreateTask(true)
+                .build();
+        final ActivityStack secondaryStack = (ActivityStack) WindowContainer.fromBinder(
+                mService.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(),
+                        WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token.asBinder());
+
+        rootHomeTask.reparent(secondaryStack, POSITION_TOP);
+        assertEquals(secondaryStack, rootHomeTask.getParent());
+
+        // This should call to {@link TaskDisplayArea#removeStackReferenceIfNeeded}.
+        homeActivity.removeImmediately();
+        assertNull(mDefaultTaskDisplayArea.getRootHomeTask());
+    }
+
+    @Test
     public void testStackInheritsDisplayWindowingMode() {
         final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);