Merge "Cache EGLImage and VkImage used by SurfaceTexture"
diff --git a/api/current.txt b/api/current.txt
index 11f7ce1..c06d618 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11271,11 +11271,11 @@
     method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
-    method public void startPackageInstallerSessionDetailsActivity(android.content.pm.PackageInstaller.SessionInfo, android.graphics.Rect, android.os.Bundle);
+    method public void startPackageInstallerSessionDetailsActivity(@NonNull android.content.pm.PackageInstaller.SessionInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle);
     method public void startShortcut(@NonNull String, @NonNull String, @Nullable android.graphics.Rect, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
     method public void startShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
-    method public void unregisterPackageInstallerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
+    method public void unregisterPackageInstallerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback);
     field public static final String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
     field public static final String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
     field public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
@@ -11465,7 +11465,7 @@
     method public long getSize();
     method public int getStagedSessionErrorCode();
     method @NonNull public String getStagedSessionErrorMessage();
-    method public android.os.UserHandle getUser();
+    method @NonNull public android.os.UserHandle getUser();
     method public boolean isActive();
     method public boolean isMultiPackage();
     method public boolean isSealed();
diff --git a/api/system-current.txt b/api/system-current.txt
index aec8cc1..28104d5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -546,10 +546,10 @@
 
   public class NotificationManager {
     method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
-    method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(android.os.UserHandle);
+    method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(@NonNull android.os.UserHandle);
     method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
-    method public void setNotificationAssistantAccessGranted(android.content.ComponentName, boolean);
-    method public void setNotificationAssistantAccessGrantedForUser(android.content.ComponentName, android.os.UserHandle, boolean);
+    method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+    method public void setNotificationAssistantAccessGrantedForUser(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, boolean);
   }
 
   public final class StatsManager {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index ed7aa4a..204fb6a 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1277,7 +1277,8 @@
      * @hide
      */
     @SystemApi
-    public void setNotificationAssistantAccessGranted(ComponentName assistant, boolean granted) {
+    public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant,
+            boolean granted) {
         INotificationManager service = getService();
         try {
             service.setNotificationAssistantAccessGranted(assistant, granted);
@@ -1296,8 +1297,8 @@
      * @hide
      */
     @SystemApi
-    public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
-            UserHandle user, boolean granted) {
+    public void setNotificationAssistantAccessGrantedForUser(@Nullable ComponentName assistant,
+            @NonNull UserHandle user, boolean granted) {
         INotificationManager service = getService();
         try {
             service.setNotificationAssistantAccessGrantedForUser(assistant, user.getIdentifier(),
@@ -1319,7 +1320,8 @@
 
     /** @hide */
     @SystemApi
-    public @Nullable ComponentName getAllowedNotificationAssistantForUser(UserHandle user) {
+    public @Nullable ComponentName getAllowedNotificationAssistantForUser(
+            @NonNull UserHandle user) {
         INotificationManager service = getService();
         try {
             return service.getAllowedNotificationAssistantForUser(user.getIdentifier());
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 0cc5f39..2a19763 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -585,8 +585,8 @@
      * @param sourceBounds The Rect containing the source bounds of the clicked icon
      * @param opts Options to pass to startActivity
      */
-    public void startPackageInstallerSessionDetailsActivity(SessionInfo sessionInfo,
-            Rect sourceBounds, Bundle opts) {
+    public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo,
+            @Nullable Rect sourceBounds, @Nullable Bundle opts) {
         try {
             mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
                     mContext.getPackageName(), sessionInfo, sourceBounds, opts,
@@ -1503,7 +1503,7 @@
      * @param callback The callback to unregister.
      * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
      */
-    public void unregisterPackageInstallerSessionCallback(SessionCallback callback) {
+    public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) {
         synchronized (mDelegates) {
             for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
                 final SessionCallbackDelegate delegate = i.next();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 7b4dd19..f14b228 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1833,7 +1833,7 @@
         /**
          * Return the user associated with this session.
          */
-        public UserHandle getUser() {
+        public @NonNull UserHandle getUser() {
             return new UserHandle(userId);
         }
 
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 45860b3..95d66bb 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -62,7 +62,7 @@
  *
  * The handshake timeout does not apply to actual TCP socket connection.
  * If you want a connection timeout as well, use {@link #createSocket()}
- * and {@link Socket#connect(SocketAddress, int)}, after which you
+ * and {@link Socket#connect(java.net.SocketAddress, int)}, after which you
  * must verify the identity of the server you are connected to.
  *
  * <p class="caution"><b>Most {@link SSLSocketFactory} implementations do not
@@ -211,14 +211,14 @@
     }
 
     /**
-     * Verify the hostname of the certificate used by the other end of a
-     * connected socket.  You MUST call this if you did not supply a hostname
-     * to {@link #createSocket()}.  It is harmless to call this method
-     * redundantly if the hostname has already been verified.
+     * Verify the hostname of the certificate used by the other end of a connected socket using the
+     * {@link HostnameVerifier} obtained from {@code
+     * HttpsURLConnection.getDefaultHostnameVerifier()}. You MUST call this if you did not supply a
+     * hostname to {@link #createSocket()}.  It is harmless to call this method redundantly if the
+     * hostname has already been verified.
      *
-     * <p>Wildcard certificates are allowed to verify any matching hostname,
-     * so "foo.bar.example.com" is verified if the peer has a certificate
-     * for "*.example.com".
+     * <p>Wildcard certificates are allowed to verify any matching hostname, so
+     * "foo.bar.example.com" is verified if the peer has a certificate for "*.example.com".
      *
      * @param socket An SSL socket which has been connected to a server
      * @param hostname The expected hostname of the remote server
@@ -483,7 +483,8 @@
      * {@inheritDoc}
      *
      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
-     * certificate hostname after connecting; if this instance was created with
+     * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
+     * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
      * instead.
      */
@@ -562,7 +563,8 @@
      * {@inheritDoc}
      *
      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
-     * certificate hostname after connecting; if this instance was created with
+     * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
+     * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
      * instead.
      */
@@ -585,7 +587,8 @@
      * {@inheritDoc}
      *
      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
-     * certificate hostname after connecting; if this instance was created with
+     * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
+     * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
      * instead.
      */
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index efdc968..ddbff7b 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -18,9 +18,11 @@
 
 import android.annotation.Nullable;
 import android.app.Person;
+import android.app.RemoteAction;
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -118,12 +120,60 @@
     @Nullable
     public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
         if (ConversationAction.TYPE_OPEN_URL.equals(actionType)) {
-            return (labeledIntent, resolveInfo) -> resolveInfo.handleAllWebDataURI
-                    ? labeledIntent.titleWithEntity : labeledIntent.titleWithoutEntity;
+            return (labeledIntent, resolveInfo) -> {
+                if (resolveInfo.handleAllWebDataURI) {
+                    return labeledIntent.titleWithEntity;
+                }
+                if ("android".equals(resolveInfo.activityInfo.packageName)) {
+                    return labeledIntent.titleWithEntity;
+                }
+                return labeledIntent.titleWithoutEntity;
+            };
         }
         return null;
     }
 
+    /**
+     * Returns a list of {@link ConversationAction}s that have 0 duplicates. Two actions are
+     * duplicates if they may look the same to users. This function assumes every
+     * ConversationActions with a non-null RemoteAction also have a non-null intent in the extras.
+     */
+    public static List<ConversationAction> removeActionsWithDuplicates(
+            List<ConversationAction> conversationActions) {
+        // Ideally, we should compare title and icon here, but comparing icon is expensive and thus
+        // we use the component name of the target handler as the heuristic.
+        Map<Pair<String, String>, Integer> counter = new ArrayMap<>();
+        for (ConversationAction conversationAction : conversationActions) {
+            Pair<String, String> representation = getRepresentation(conversationAction);
+            if (representation == null) {
+                continue;
+            }
+            Integer existingCount = counter.getOrDefault(representation, 0);
+            counter.put(representation, existingCount + 1);
+        }
+        List<ConversationAction> result = new ArrayList<>();
+        for (ConversationAction conversationAction : conversationActions) {
+            Pair<String, String> representation = getRepresentation(conversationAction);
+            if (representation == null || counter.getOrDefault(representation, 0) == 1) {
+                result.add(conversationAction);
+            }
+        }
+        return result;
+    }
+
+    @Nullable
+    private static Pair<String, String> getRepresentation(
+            ConversationAction conversationAction) {
+        RemoteAction remoteAction = conversationAction.getAction();
+        if (remoteAction == null) {
+            return null;
+        }
+        return new Pair<>(
+                conversationAction.getAction().getTitle().toString(),
+                ExtrasUtils.getActionIntent(
+                        conversationAction.getExtras()).getComponent().getPackageName());
+    }
+
     private static final class PersonEncoder {
         private final Map<Person, Integer> mMapping = new ArrayMap<>();
         private int mNextUserId = FIRST_NON_LOCAL_USER;
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index 2ad17a8..df548ae 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -29,6 +29,7 @@
  */
 public final class ExtrasUtils {
 
+    private static final String ACTION_INTENT = "action-intent";
     private static final String ACTIONS_INTENTS = "actions-intents";
     private static final String FOREIGN_LANGUAGE = "foreign-language";
     private static final String ENTITY_TYPE = "entity-type";
@@ -77,6 +78,22 @@
     }
 
     /**
+     * Stores {@code actionIntents} information in TextClassifier response object's extras
+     * {@code container}.
+     */
+    public static void putActionIntent(Bundle container, @Nullable Intent actionIntent) {
+        container.putParcelable(ACTION_INTENT, actionIntent);
+    }
+
+    /**
+     * Returns {@code actionIntent} information contained in a TextClassifier response object.
+     */
+    @Nullable
+    public static Intent getActionIntent(Bundle container) {
+        return container.getParcelable(ACTION_INTENT);
+    }
+
+    /**
      * Returns {@code actionIntents} information contained in the TextClassification object.
      */
     @Nullable
diff --git a/core/java/android/view/textclassifier/LabeledIntent.java b/core/java/android/view/textclassifier/LabeledIntent.java
index 7544dc1..d2897b2 100644
--- a/core/java/android/view/textclassifier/LabeledIntent.java
+++ b/core/java/android/view/textclassifier/LabeledIntent.java
@@ -91,15 +91,22 @@
             Context context, @Nullable TitleChooser titleChooser) {
         final PackageManager pm = context.getPackageManager();
         final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
-        final String packageName = resolveInfo != null && resolveInfo.activityInfo != null
-                ? resolveInfo.activityInfo.packageName : null;
-        Icon icon = null;
+
+        if (resolveInfo == null || resolveInfo.activityInfo == null) {
+            Log.w(TAG, "resolveInfo or activityInfo is null");
+            return null;
+        }
+        final String packageName = resolveInfo.activityInfo.packageName;
+        final String className = resolveInfo.activityInfo.name;
+        if (packageName == null || className == null) {
+            Log.w(TAG, "packageName or className is null");
+            return null;
+        }
         Intent resolvedIntent = new Intent(intent);
+        resolvedIntent.setComponent(new ComponentName(packageName, className));
         boolean shouldShowIcon = false;
-        if (packageName != null && !"android".equals(packageName)) {
-            // There is a default activity handling the intent.
-            resolvedIntent.setComponent(
-                    new ComponentName(packageName, resolveInfo.activityInfo.name));
+        Icon icon = null;
+        if (!"android".equals(packageName)) {
             if (resolveInfo.activityInfo.getIconResource() != 0) {
                 icon = Icon.createWithResource(
                         packageName, resolveInfo.activityInfo.getIconResource());
@@ -113,9 +120,6 @@
         }
         final PendingIntent pendingIntent =
                 TextClassification.createPendingIntent(context, resolvedIntent, requestCode);
-        if (pendingIntent == null) {
-            return null;
-        }
         if (titleChooser == null) {
             titleChooser = DEFAULT_TITLE_CHOOSER;
         }
@@ -150,6 +154,7 @@
     public interface TitleChooser {
         /**
          * Picks a title from a {@link LabeledIntent} by looking into resolved info.
+         * {@code resolveInfo} is guaranteed to have a non-null {@code activityInfo}.
          */
         @Nullable
         CharSequence chooseTitle(LabeledIntent labeledIntent, ResolveInfo resolveInfo);
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 034da01..a275f0f 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -25,8 +25,6 @@
 import android.app.RemoteAction;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.AdaptiveIconDrawable;
@@ -304,53 +302,10 @@
      * @throws IllegalArgumentException if context or intent is null
      * @hide
      */
-    @Nullable
     public static PendingIntent createPendingIntent(
             @NonNull final Context context, @NonNull final Intent intent, int requestCode) {
-        final int flags = PendingIntent.FLAG_UPDATE_CURRENT;
-        switch (getIntentType(intent, context)) {
-            case IntentType.ACTIVITY:
-                return PendingIntent.getActivity(context, requestCode, intent, flags);
-            case IntentType.SERVICE:
-                return PendingIntent.getService(context, requestCode, intent, flags);
-            default:
-                return null;
-        }
-    }
-
-    @IntentType
-    private static int getIntentType(@NonNull Intent intent, @NonNull Context context) {
-        Preconditions.checkArgument(context != null);
-        Preconditions.checkArgument(intent != null);
-
-        final ResolveInfo activityRI = context.getPackageManager().resolveActivity(intent, 0);
-        if (activityRI != null) {
-            if (context.getPackageName().equals(activityRI.activityInfo.packageName)) {
-                return IntentType.ACTIVITY;
-            }
-            final boolean exported = activityRI.activityInfo.exported;
-            if (exported && hasPermission(context, activityRI.activityInfo.permission)) {
-                return IntentType.ACTIVITY;
-            }
-        }
-
-        final ResolveInfo serviceRI = context.getPackageManager().resolveService(intent, 0);
-        if (serviceRI != null) {
-            if (context.getPackageName().equals(serviceRI.serviceInfo.packageName)) {
-                return IntentType.SERVICE;
-            }
-            final boolean exported = serviceRI.serviceInfo.exported;
-            if (exported && hasPermission(context, serviceRI.serviceInfo.permission)) {
-                return IntentType.SERVICE;
-            }
-        }
-
-        return IntentType.UNSUPPORTED;
-    }
-
-    private static boolean hasPermission(@NonNull Context context, @NonNull String permission) {
-        return permission == null
-                || context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
+        return PendingIntent.getActivity(
+                context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 632328b..35cd678 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -84,12 +84,17 @@
     private final GenerateLinksLogger mGenerateLinksLogger;
 
     private final Object mLock = new Object();
+
     @GuardedBy("mLock") // Do not access outside this lock.
     private ModelFileManager.ModelFile mAnnotatorModelInUse;
     @GuardedBy("mLock") // Do not access outside this lock.
     private AnnotatorModel mAnnotatorImpl;
+
+    @GuardedBy("mLock") // Do not access outside this lock.
+    private ModelFileManager.ModelFile mLangIdModelInUse;
     @GuardedBy("mLock") // Do not access outside this lock.
     private LangIdModel mLangIdImpl;
+
     @GuardedBy("mLock") // Do not access outside this lock.
     private ModelFileManager.ModelFile mActionModelInUse;
     @GuardedBy("mLock") // Do not access outside this lock.
@@ -403,6 +408,12 @@
         return mFallback.suggestConversationActions(request);
     }
 
+    /**
+     * Returns the {@link ConversationAction} result, with a non-null extras.
+     * <p>
+     * Whenever the RemoteAction is non-null, you can expect its corresponding intent
+     * with a non-null component name is in the extras.
+     */
     private ConversationActions createConversationActionResult(
             ConversationActions.Request request,
             ActionsSuggestionsModel.ActionSuggestion[] nativeSuggestions) {
@@ -419,6 +430,7 @@
             }
             List<LabeledIntent> labeledIntents =
                     mTemplateIntentFactory.create(nativeSuggestion.getRemoteActionTemplates());
+            Bundle extras = new Bundle();
             RemoteAction remoteAction = null;
             // Given that we only support implicit intent here, we should expect there is just one
             // intent for each action type.
@@ -428,6 +440,7 @@
                 LabeledIntent.Result result = labeledIntents.get(0).resolve(mContext, titleChooser);
                 if (result != null) {
                     remoteAction = result.remoteAction;
+                    ExtrasUtils.putActionIntent(extras, result.resolvedIntent);
                 }
             }
             conversationActions.add(
@@ -435,8 +448,11 @@
                             .setConfidenceScore(nativeSuggestion.getScore())
                             .setTextReply(nativeSuggestion.getResponseText())
                             .setAction(remoteAction)
+                            .setExtras(extras)
                             .build());
         }
+        conversationActions =
+                ActionsSuggestionsHelper.removeActionsWithDuplicates(conversationActions);
         String resultId = ActionsSuggestionsHelper.createResultId(
                 mContext,
                 request.getConversation(),
@@ -504,17 +520,19 @@
 
     private LangIdModel getLangIdImpl() throws FileNotFoundException {
         synchronized (mLock) {
-            if (mLangIdImpl == null) {
-                final ModelFileManager.ModelFile bestModel =
-                        mLangIdModelFileManager.findBestModelFile(null);
-                if (bestModel == null) {
-                    throw new FileNotFoundException("No LangID model is found");
-                }
+            final ModelFileManager.ModelFile bestModel =
+                    mLangIdModelFileManager.findBestModelFile(null);
+            if (bestModel == null) {
+                throw new FileNotFoundException("No LangID model is found");
+            }
+            if (mLangIdImpl == null || !Objects.equals(mLangIdModelInUse, bestModel)) {
+                Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
                 final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
                         new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
                 try {
                     if (pfd != null) {
                         mLangIdImpl = new LangIdModel(pfd.getFd());
+                        mLangIdModelInUse = bestModel;
                     }
                 } finally {
                     maybeCloseAndLogError(pfd);
@@ -527,13 +545,14 @@
     @Nullable
     private ActionsSuggestionsModel getActionsImpl() throws FileNotFoundException {
         synchronized (mLock) {
-            if (mActionsImpl == null) {
-                // TODO: Use LangID to determine the locale we should use here?
-                final ModelFileManager.ModelFile bestModel =
-                        mActionsModelFileManager.findBestModelFile(LocaleList.getDefault());
-                if (bestModel == null) {
-                    return null;
-                }
+            // TODO: Use LangID to determine the locale we should use here?
+            final ModelFileManager.ModelFile bestModel =
+                    mActionsModelFileManager.findBestModelFile(LocaleList.getDefault());
+            if (bestModel == null) {
+                return null;
+            }
+            if (mActionsImpl == null || !Objects.equals(mActionModelInUse, bestModel)) {
+                Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
                 final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
                         new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
                 try {
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 44f44d4..dbea13e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1996,7 +1996,9 @@
          {@link #AndroidManifestApplication application} tag. -->
     <declare-styleable name="AndroidManifestUsesPackage" parent="AndroidManifestApplication">
         <!-- Required type of association with the package, for example "android.package.ad_service"
-             if it provides an advertising service. -->
+             if it provides an advertising service.  This should use the standard scoped naming
+             convention as used for other things such as package names, based on the Java naming
+             convention. -->
         <attr name="packageType" format="string" />
         <!-- Required name of the package you use. -->
         <attr name="name" />
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index 5022e30..f440953 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -21,8 +21,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.PendingIntent;
 import android.app.Person;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -36,6 +43,7 @@
 import java.time.ZonedDateTime;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 import java.util.function.Function;
 
@@ -129,6 +137,73 @@
         assertNativeMessage(conversationMessages[2], thirdMessage.getText(), 1, 2000);
     }
 
+    @Test
+    public void testDeduplicateActions() {
+        Bundle phoneExtras = new Bundle();
+        Intent phoneIntent = new Intent();
+        phoneIntent.setComponent(new ComponentName("phone", "intent"));
+        ExtrasUtils.putActionIntent(phoneExtras, phoneIntent);
+
+        Bundle anotherPhoneExtras = new Bundle();
+        Intent anotherPhoneIntent = new Intent();
+        anotherPhoneIntent.setComponent(new ComponentName("phone", "another.intent"));
+        ExtrasUtils.putActionIntent(anotherPhoneExtras, anotherPhoneIntent);
+
+        Bundle urlExtras = new Bundle();
+        Intent urlIntent = new Intent();
+        urlIntent.setComponent(new ComponentName("url", "intent"));
+        ExtrasUtils.putActionIntent(urlExtras, urlIntent);
+
+        PendingIntent pendingIntent = PendingIntent.getActivity(
+                InstrumentationRegistry.getTargetContext(),
+                0,
+                phoneIntent,
+                0);
+        Icon icon = Icon.createWithData(new byte[0], 0, 0);
+        ConversationAction action =
+                new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+                        .setAction(new RemoteAction(icon, "label", "1", pendingIntent))
+                        .setExtras(phoneExtras)
+                        .build();
+        ConversationAction actionWithSameLabel =
+                new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+                        .setAction(new RemoteAction(
+                                icon, "label", "2", pendingIntent))
+                        .setExtras(phoneExtras)
+                        .build();
+        ConversationAction actionWithSamePackageButDifferentClass =
+                new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+                        .setAction(new RemoteAction(
+                                icon, "label", "3", pendingIntent))
+                        .setExtras(anotherPhoneExtras)
+                        .build();
+        ConversationAction actionWithDifferentLabel =
+                new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+                        .setAction(new RemoteAction(
+                                icon, "another_label", "4", pendingIntent))
+                        .setExtras(phoneExtras)
+                        .build();
+        ConversationAction actionWithDifferentPackage =
+                new ConversationAction.Builder(ConversationAction.TYPE_OPEN_URL)
+                        .setAction(new RemoteAction(icon, "label", "5", pendingIntent))
+                        .setExtras(urlExtras)
+                        .build();
+        ConversationAction actionWithoutRemoteAction =
+                new ConversationAction.Builder(ConversationAction.TYPE_CREATE_REMINDER)
+                        .build();
+
+        List<ConversationAction> conversationActions =
+                ActionsSuggestionsHelper.removeActionsWithDuplicates(
+                        Arrays.asList(action, actionWithSameLabel,
+                                actionWithSamePackageButDifferentClass, actionWithDifferentLabel,
+                                actionWithDifferentPackage, actionWithoutRemoteAction));
+
+        assertThat(conversationActions).hasSize(3);
+        assertThat(conversationActions.get(0).getAction().getContentDescription()).isEqualTo("4");
+        assertThat(conversationActions.get(1).getAction().getContentDescription()).isEqualTo("5");
+        assertThat(conversationActions.get(2).getAction()).isNull();
+    }
+
     private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
         return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneId.of("UTC"));
     }
diff --git a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
index e4e9cde..6520c8f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
@@ -132,7 +132,6 @@
         assertThat(intent.getComponent()).isNotNull();
     }
 
-
     @Test
     public void resolve_missingTitle() {
         assertThrows(
@@ -146,4 +145,19 @@
                                 REQUEST_CODE
                         ));
     }
+
+    @Test
+    public void resolve_noIntentHandler() {
+        Intent intent = new Intent("some.thing.does.not.exist");
+        LabeledIntent labeledIntent = new LabeledIntent(
+                TITLE_WITHOUT_ENTITY,
+                null,
+                DESCRIPTION,
+                intent,
+                REQUEST_CODE);
+
+        LabeledIntent.Result result = labeledIntent.resolve(mContext, null);
+
+        assertThat(result).isNull();
+    }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index d2d03e56..bcaf663 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -24,6 +24,7 @@
 import android.app.RemoteAction;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.text.Spannable;
@@ -32,6 +33,8 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
+import com.google.common.truth.Truth;
+
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
@@ -403,7 +406,6 @@
 
         ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
         assertTrue(conversationActions.getConversationActions().size() > 0);
-        assertTrue(conversationActions.getConversationActions().size() == 1);
         for (ConversationAction conversationAction :
                 conversationActions.getConversationActions()) {
             assertThat(conversationAction,
@@ -438,6 +440,34 @@
         }
     }
 
+    @Test
+    public void testSuggestConversationActions_openUrl() {
+        if (isTextClassifierDisabled()) return;
+        ConversationActions.Message message =
+                new ConversationActions.Message.Builder(
+                        ConversationActions.Message.PERSON_USER_OTHERS)
+                        .setText("Check this out: https://www.android.com")
+                        .build();
+        TextClassifier.EntityConfig typeConfig =
+                new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
+                        .setIncludedTypes(
+                                Collections.singletonList(ConversationAction.TYPE_OPEN_URL))
+                        .build();
+        ConversationActions.Request request =
+                new ConversationActions.Request.Builder(Collections.singletonList(message))
+                        .setMaxSuggestions(1)
+                        .setTypeConfig(typeConfig)
+                        .build();
+
+        ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+        Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
+        ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
+        Truth.assertThat(conversationAction.getType()).isEqualTo(ConversationAction.TYPE_OPEN_URL);
+        Intent actionIntent = ExtrasUtils.getActionIntent(conversationAction.getExtras());
+        Truth.assertThat(actionIntent.getAction()).isEqualTo(Intent.ACTION_VIEW);
+        Truth.assertThat(actionIntent.getData()).isEqualTo(Uri.parse("https://www.android.com"));
+    }
+
 
     private boolean isTextClassifierDisabled() {
         return mClassifier == null || mClassifier == TextClassifier.NO_OP;
diff --git a/packages/SystemUI/res/drawable/circle_blue_40dp.xml b/packages/SystemUI/res/drawable/circle_blue_40dp.xml
new file mode 100644
index 0000000..00d2c52
--- /dev/null
+++ b/packages/SystemUI/res/drawable/circle_blue_40dp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <size android:height="40dp"
+          android:width="40dp" />
+    <solid android:color="#4285f4" />
+    <stroke android:color="#f1f3f4" android:width="1dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/circle_white_40dp.xml b/packages/SystemUI/res/drawable/circle_white_40dp.xml
new file mode 100644
index 0000000..bcb1640
--- /dev/null
+++ b/packages/SystemUI/res/drawable/circle_white_40dp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <size android:height="40dp"
+          android:width="40dp" />
+    <solid android:color="#ffffff" />
+    <stroke android:color="#f1f3f4" android:width="1dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 7e0f3ae..725ace4 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -220,48 +220,142 @@
                     android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
                     style="@style/TextAppearance.NotificationInfo.Button"/>
             </LinearLayout>
-
-
         </RelativeLayout>
         <LinearLayout
             android:id="@+id/interruptiveness_settings"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/notification_guts_button_spacing"
-            android:layout_marginStart="@dimen/notification_guts_button_side_margin"
-            android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
-            android:gravity="center"
-            android:orientation="horizontal"
+            android:orientation="vertical"
             android:visibility="gone">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="2dp"
+                android:layout_marginStart="@dimen/notification_guts_button_side_margin"
+                android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
+                android:gravity="center"
+                android:orientation="horizontal">
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:gravity="center_horizontal"
+                    android:orientation="vertical">
+                    <FrameLayout
+                        android:id="@+id/int_block_wrapper"
+                        android:padding="4dp"
+                        android:layout_width="48dp"
+                        android:layout_height="48dp"
+                        android:gravity="center">
+                        <ImageButton
+                            android:id="@+id/int_block"
+                            android:background="@drawable/circle_white_40dp"
+                            android:src="@drawable/ic_notification_block"
+                            android:layout_gravity="center"
+                            android:layout_width="40dp"
+                            android:layout_height="40dp"
+                            android:clickable="false"
+                            android:tint="@color/GM2_grey_400"
+                            style="@style/TextAppearance.NotificationInfo.Button"/>
+                    </FrameLayout>
+                    <TextView
+                        android:id="@+id/int_block_label"
+                        android:text="@string/inline_block_button"
+                        android:layout_gravity="center_horizontal"
+                        android:gravity="center"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:ellipsize="end"
+                        android:maxLines="1"
+                        style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+                </LinearLayout>
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:gravity="center_horizontal"
+                    android:orientation="vertical">
+                    <FrameLayout
+                        android:id="@+id/int_silent_wrapper"
+                        android:padding="4dp"
+                        android:layout_width="48dp"
+                        android:layout_height="48dp"
+                        android:gravity="center">
+                        <ImageButton
+                            android:id="@+id/int_silent"
+                            android:background="@drawable/circle_white_40dp"
+                            android:src="@drawable/ic_notifications_silence"
+                            android:layout_gravity="center"
+                            android:layout_width="40dp"
+                            android:layout_height="40dp"
+                            android:clickable="false"
+                            android:tint="@color/GM2_grey_400"
+                            style="@style/TextAppearance.NotificationInfo.Button"/>
+                    </FrameLayout>
+                    <TextView
+                        android:id="@+id/int_silent_label"
+                        android:text="@string/inline_silent_button_silent"
+                        android:layout_gravity="center_horizontal"
+                        android:gravity="center"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:ellipsize="end"
+                        android:maxLines="1"
+                        style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+                </LinearLayout>
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:gravity="center_horizontal"
+                    android:orientation="vertical">
+                    <FrameLayout
+                        android:id="@+id/int_alert_wrapper"
+                        android:padding="4dp"
+                        android:layout_width="48dp"
+                        android:layout_height="48dp"
+                        android:gravity="center">
+                        <ImageButton
+                            android:id="@+id/int_alert"
+                            android:background="@drawable/circle_white_40dp"
+                            android:src="@drawable/ic_notifications_alert"
+                            android:layout_gravity="center"
+                            android:layout_width="40dp"
+                            android:layout_height="40dp"
+                            android:clickable="false"
+                            android:tint="@color/GM2_grey_400"
+                            style="@style/TextAppearance.NotificationInfo.Button"/>
+                    </FrameLayout>
+                    <TextView
+                        android:id="@+id/int_alert_label"
+                        android:text="@string/inline_silent_button_alert"
+                        android:layout_gravity="center_horizontal"
+                        android:gravity="center"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:ellipsize="end"
+                        android:maxLines="1"
+                        style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+                </LinearLayout>
+            </LinearLayout>
             <TextView
-                android:id="@+id/int_block"
-                android:text="@string/inline_block_button"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:drawableTop="@drawable/ic_notification_block"
-                android:drawableTint="?android:attr/colorAccent"
-                android:layout_weight="1"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
+                android:id="@+id/hint_text"
+                android:layout_marginStart="@*android:dimen/notification_content_margin_start"
+                android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.NotificationInfo.HintText" />
             <TextView
-                android:id="@+id/int_silent"
-                android:text="@string/inline_minimize_button"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:drawableTop="@drawable/ic_notifications_silence"
-                android:drawableTint="?android:attr/colorAccent"
-                android:layout_weight="1"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
-            <TextView
-                android:id="@+id/int_alert"
-                android:text="@string/inline_keep_button"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:drawableTop="@drawable/ic_notifications_alert"
-                android:drawableTint="?android:attr/colorAccent"
-                android:layout_weight="1"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
+                android:id="@+id/done_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="right"
+                android:paddingRight="24dp"
+                android:text="@string/inline_done_button"
+                style="@style/TextAppearance.NotificationInfo.Button" />
         </LinearLayout>
     </LinearLayout>
+
     <com.android.systemui.statusbar.notification.row.NotificationUndoLayout
         android:id="@+id/confirmation"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 223e7b0..16222f7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1608,7 +1608,7 @@
     <string name="inline_silent_button_stay_silent">Stay silent</string>
 
     <!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] -->
-    <string name="inline_silent_button_alert">Alert me</string>
+    <string name="inline_silent_button_alert">Alert</string>
 
     <!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] -->
     <string name="inline_silent_button_keep_alerting">Keep alerting</string>
@@ -1616,6 +1616,15 @@
     <!-- Notification Inline controls: continue receiving notifications prompt, app level -->
     <string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
 
+    <!-- Hint text for block button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
+    <string name="hint_text_block">Blocked notifications do not appear anywhere or play a sound. You can unblock notifications in settings.</string>
+
+    <!-- Hint text for silent button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
+    <string name="hint_text_silent">Silent notifications appear in the shade, but do not appear on the lock screen, present a banner, or play a sound.</string>
+
+    <!-- Hint text for alert button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
+    <string name="hint_text_alert">Alerted notifications appear in the shade, on the lock screen, present a banner, and play a sound.</string>
+
     <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
     <string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4adece9..0f5df45 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -444,6 +444,19 @@
         <item name="android:alpha">0.54</item>
     </style>
 
+    <style name="TextAppearance.NotificationInfo.ButtonLabel">
+        <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:alpha">0.54</item>
+        <item name="android:paddingTop">4dp</item>
+        <item name="android:paddingBottom">16dp</item>
+    </style>
+
+    <style name="TextAppearance.NotificationInfo.HintText">
+        <item name="android:textSize">12sp</item>
+        <item name="android:alpha">0.54</item>
+    </style>
+
     <style name="TextAppearance.NotificationInfo.Secondary.Warning">
         <item name="android:textColor">?android:attr/colorError</item>
     </style>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 3723731..2e4325b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.notification.row;
 
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -38,6 +37,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.metrics.LogMaker;
 import android.os.Handler;
@@ -81,10 +81,11 @@
     }
 
     public static final int ACTION_NONE = 0;
-    public static final int ACTION_UNDO = 1;
-    public static final int ACTION_TOGGLE_SILENT = 2;
-    public static final int ACTION_BLOCK = 3;
-    public static final int ACTION_DELIVER_SILENTLY = 4;
+    static final int ACTION_UNDO = 1;
+    static final int ACTION_TOGGLE_SILENT = 2;
+    static final int ACTION_BLOCK = 3;
+    static final int ACTION_DELIVER_SILENTLY = 4;
+    private static final int ACTION_ALERT = 5;
 
     private INotificationManager mINotificationManager;
     private PackageManager mPm;
@@ -98,6 +99,7 @@
     private NotificationChannel mSingleNotificationChannel;
     private int mStartingChannelImportance;
     private boolean mWasShownHighPriority;
+    private int mNotificationBlockState = ACTION_NONE;
     /**
      * The last importance level chosen by the user.  Null if the user has not chosen an importance
      * level; non-null once the user takes an action which indicates an explicit preference.
@@ -117,7 +119,6 @@
 
     /** Whether this view is being shown as part of the blocking helper. */
     private boolean mIsForBlockingHelper;
-    private boolean mNegativeUserSentiment;
 
     /**
      * String that describes how the user exit or quit out of this view, also used as a counter tag.
@@ -126,8 +127,8 @@
 
     private OnClickListener mOnKeepShowing = v -> {
         mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
-        closeControls(v);
         if (mIsForBlockingHelper) {
+            closeControls(v);
             mMetricsLogger.write(getLogMaker().setCategory(
                     MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
                     .setType(MetricsEvent.TYPE_ACTION)
@@ -135,23 +136,36 @@
         }
     };
 
-    private OnClickListener mOnToggleSilent = v -> {
-        handleSaveImportance(ACTION_TOGGLE_SILENT, MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME);
+    private OnClickListener mOnAlert = v -> {
+        mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+        mChosenImportance = IMPORTANCE_DEFAULT;
+        updateButtonsAndHelpText(ACTION_ALERT);
+    };
+
+    private OnClickListener mOnDismissSettings = v -> {
+        closeControls(v);
     };
 
     private OnClickListener mOnDeliverSilently = v -> {
         handleSaveImportance(
                 ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
+        if (!mIsForBlockingHelper) {
+            updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
+        }
     };
 
     private OnClickListener mOnStopOrMinimizeNotifications = v -> {
         handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED);
+        if (!mIsForBlockingHelper) {
+            updateButtonsAndHelpText(ACTION_BLOCK);
+        }
     };
 
     private void handleSaveImportance(int action, int metricsSubtype) {
         Runnable saveImportance = () -> {
-            swapContent(action, true /* animate */);
+            saveImportanceAndExitReason(action);
             if (mIsForBlockingHelper) {
+                swapContent(action, true /* animate */);
                 mMetricsLogger.write(getLogMaker()
                         .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
                         .setType(MetricsEvent.TYPE_ACTION)
@@ -177,6 +191,7 @@
         } else {
             mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
         }
+        saveImportanceAndExitReason(ACTION_UNDO);
         swapContent(ACTION_UNDO, true /* animate */);
     };
 
@@ -252,7 +267,6 @@
         mSingleNotificationChannel = notificationChannel;
         mStartingChannelImportance = mSingleNotificationChannel.getImportance();
         mWasShownHighPriority = wasShownHighPriority;
-        mNegativeUserSentiment = isUserSentimentNegative;
         mIsNonblockable = isNonblockable;
         mIsForeground =
                 (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
@@ -329,14 +343,6 @@
         bindGroup();
         if (mIsNonblockable) {
             blockPrompt.setText(R.string.notification_unblockable_desc);
-        } else {
-            if (mNegativeUserSentiment) {
-                blockPrompt.setText(R.string.inline_blocking_helper);
-            }  else if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) {
-                blockPrompt.setText(R.string.inline_keep_showing_app);
-            } else {
-                blockPrompt.setText(R.string.inline_keep_showing);
-            }
         }
     }
 
@@ -403,6 +409,7 @@
         }
     }
 
+
     @VisibleForTesting
     void logBlockingHelperCounter(String counterTag) {
         if (mIsForBlockingHelper) {
@@ -454,21 +461,20 @@
         if (showInterruptivenessSettings) {
             findViewById(R.id.block_or_minimize).setVisibility(GONE);
             findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
-            View block = findViewById(R.id.int_block);
-            TextView silent = findViewById(R.id.int_silent);
-            TextView alert = findViewById(R.id.int_alert);
-
+            View done = findViewById(R.id.done_button);
+            done.setOnClickListener(mOnDismissSettings);
+            View block = findViewById(R.id.int_block_wrapper);
+            View silent = findViewById(R.id.int_silent_wrapper);
+            View alert = findViewById(R.id.int_alert_wrapper);
             block.setOnClickListener(mOnStopOrMinimizeNotifications);
-            if (mWasShownHighPriority) {
-                silent.setOnClickListener(mOnToggleSilent);
-                silent.setText(R.string.inline_silent_button_silent);
-                alert.setOnClickListener(mOnKeepShowing);
-                alert.setText(R.string.inline_silent_button_keep_alerting);
+            silent.setOnClickListener(mOnDeliverSilently);
+            alert.setOnClickListener(mOnAlert);
+            if (mNotificationBlockState != ACTION_NONE) {
+                updateButtonsAndHelpText(mNotificationBlockState);
+            } else if (mWasShownHighPriority) {
+                updateButtonsAndHelpText(ACTION_ALERT);
             } else {
-                silent.setOnClickListener(mOnKeepShowing);
-                silent.setText(R.string.inline_silent_button_stay_silent);
-                alert.setOnClickListener(mOnToggleSilent);
-                alert.setText(R.string.inline_silent_button_alert);
+                updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
             }
         } else {
             findViewById(R.id.block_or_minimize).setVisibility(VISIBLE);
@@ -515,6 +521,73 @@
         }
     }
 
+    private void updateButtonsAndHelpText(int blockState) {
+        mNotificationBlockState = blockState;
+        ImageView block = findViewById(R.id.int_block);
+        ImageView silent = findViewById(R.id.int_silent);
+        ImageView alert = findViewById(R.id.int_alert);
+        TextView hintText = findViewById(R.id.hint_text);
+        switch (blockState) {
+            case ACTION_BLOCK:
+                block.setBackgroundResource(R.drawable.circle_blue_40dp);
+                block.setColorFilter(Color.WHITE);
+                silent.setBackgroundResource(R.drawable.circle_white_40dp);
+                silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+                alert.setBackgroundResource(R.drawable.circle_white_40dp);
+                alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+                hintText.setText(R.string.hint_text_block);
+                break;
+            case ACTION_DELIVER_SILENTLY:
+                silent.setBackgroundResource(R.drawable.circle_blue_40dp);
+                silent.setColorFilter(Color.WHITE);
+                block.setBackgroundResource(R.drawable.circle_white_40dp);
+                block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+                alert.setBackgroundResource(R.drawable.circle_white_40dp);
+                alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+                hintText.setText(R.string.hint_text_silent);
+                break;
+            case ACTION_ALERT:
+                alert.setBackgroundResource(R.drawable.circle_blue_40dp);
+                alert.setColorFilter(Color.WHITE);
+                block.setBackgroundResource(R.drawable.circle_white_40dp);
+                block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+                silent.setBackgroundResource(R.drawable.circle_white_40dp);
+                silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+                hintText.setText(R.string.hint_text_alert);
+                break;
+        }
+    }
+
+    private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
+        switch (action) {
+            case ACTION_UNDO:
+                mChosenImportance = mStartingChannelImportance;
+                break;
+            case ACTION_DELIVER_SILENTLY:
+                mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
+                mChosenImportance = IMPORTANCE_LOW;
+                break;
+            case ACTION_TOGGLE_SILENT:
+                mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
+                if (mWasShownHighPriority) {
+                    mChosenImportance = IMPORTANCE_LOW;
+                } else {
+                    mChosenImportance = IMPORTANCE_DEFAULT;
+                }
+                break;
+            case ACTION_BLOCK:
+                mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
+                if (mIsForeground) {
+                    mChosenImportance = IMPORTANCE_MIN;
+                } else {
+                    mChosenImportance = IMPORTANCE_NONE;
+                }
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
     private void swapContent(@NotificationInfoAction int action, boolean animate) {
         if (mExpandAnimation != null) {
             mExpandAnimation.cancel();
@@ -525,32 +598,25 @@
         TextView confirmationText = findViewById(R.id.confirmation_text);
         View header = findViewById(R.id.header);
 
+        saveImportanceAndExitReason(action);
+
         switch (action) {
             case ACTION_UNDO:
-                mChosenImportance = mStartingChannelImportance;
                 break;
             case ACTION_DELIVER_SILENTLY:
-                mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
-                mChosenImportance = IMPORTANCE_LOW;
                 confirmationText.setText(R.string.notification_channel_silenced);
                 break;
             case ACTION_TOGGLE_SILENT:
-                mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
                 if (mWasShownHighPriority) {
-                    mChosenImportance = IMPORTANCE_LOW;
                     confirmationText.setText(R.string.notification_channel_silenced);
                 } else {
-                    mChosenImportance = IMPORTANCE_DEFAULT;
                     confirmationText.setText(R.string.notification_channel_unsilenced);
                 }
                 break;
             case ACTION_BLOCK:
-                mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
                 if (mIsForeground) {
-                    mChosenImportance = IMPORTANCE_MIN;
                     confirmationText.setText(R.string.notification_channel_minimized);
                 } else {
-                    mChosenImportance = IMPORTANCE_NONE;
                     confirmationText.setText(R.string.notification_channel_disabled);
                 }
                 break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 19a73f6..fb4fd31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -341,79 +341,62 @@
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT, true);
-        final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
+        final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
         assertEquals(VISIBLE, silent.getVisibility());
         assertEquals(
                 mContext.getString(R.string.inline_silent_button_silent), silent.getText());
     }
 
     @Test
-    public void testBindNotification_SilenceButton_CurrentlySilent() throws Exception {
+    public void testBindNotification_verifyButtonTexts() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_LOW, false);
-        final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
+        final TextView block = mNotificationInfo.findViewById(R.id.int_block_label);
+        final TextView alert = mNotificationInfo.findViewById(R.id.int_alert_label);
+        final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
         assertEquals(VISIBLE, silent.getVisibility());
+        assertEquals(VISIBLE, block.getVisibility());
+        assertEquals(VISIBLE, alert.getVisibility());
         assertEquals(
-                mContext.getString(R.string.inline_silent_button_stay_silent),
+                mContext.getString(R.string.inline_silent_button_silent),
                 silent.getText());
+        assertEquals(
+                mContext.getString(R.string.inline_silent_button_alert), alert.getText());
+        assertEquals(
+                mContext.getString(R.string.inline_block_button), block.getText());
     }
 
     @Test
-    public void testBindNotification_AlertButton_CurrentlySilent() throws Exception {
+    public void testBindNotification_verifyHintTextForSilent() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_LOW, false);
-        final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
-        assertEquals(VISIBLE, alert.getVisibility());
-        assertEquals(
-                mContext.getString(R.string.inline_silent_button_alert), alert.getText());
+        TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
+        assertEquals(mContext.getString(R.string.hint_text_silent), hintText.getText());
     }
 
     @Test
-    public void testBindNotification_UnSilenceButton_currentlyAlerting() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, true);
-        final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
-        assertEquals(VISIBLE, alert.getVisibility());
-        assertEquals(
-                mContext.getString(R.string.inline_silent_button_keep_alerting), alert.getText());
-    }
-
-    @Test
-    public void testBindNotification_ChannelImportanceUnspecified_NotifAlerting() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, true);
-        final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
-        final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
-        assertEquals(VISIBLE, silent.getVisibility());
-        assertEquals(VISIBLE, alert.getVisibility());
-        assertEquals(
-                mContext.getString(R.string.inline_silent_button_silent), silent.getText());
-        assertEquals(
-                mContext.getString(R.string.inline_silent_button_keep_alerting), alert.getText());
-    }
-
-    @Test
-    public void testBindNotification_ChannelImportanceUnspecified_NotifSilent() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
+    public void testBindNotification_verifyHintTextForBlock() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_LOW, false);
-        final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
-        final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
-        assertEquals(VISIBLE, silent.getVisibility());
-        assertEquals(VISIBLE, alert.getVisibility());
-        assertEquals(
-                mContext.getString(R.string.inline_silent_button_stay_silent), silent.getText());
-        assertEquals(
-                mContext.getString(R.string.inline_silent_button_alert), alert.getText());
+        View blockWrapper = mNotificationInfo.findViewById(R.id.int_block_wrapper);
+        blockWrapper.performClick();
+        TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
+        assertEquals(mContext.getString(R.string.hint_text_block), hintText.getText());
+    }
+
+    @Test
+    public void testBindNotification_verifyHintTextForAlert() throws Exception {
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+                IMPORTANCE_DEFAULT, true);
+        TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
+        assertEquals(mContext.getString(R.string.hint_text_alert), hintText.getText());
     }
 
     @Test
@@ -560,16 +543,6 @@
     }
 
     @Test
-    public void testbindNotification_BlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false,
-                true, true, IMPORTANCE_DEFAULT, true);
-        final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
-        assertEquals(View.VISIBLE, view.getVisibility());
-        assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText());
-    }
-
-    @Test
     public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
@@ -687,8 +660,8 @@
                 true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
         );
 
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(true, false);
 
         mTestableLooper.processAllMessages();
@@ -709,8 +682,8 @@
                 true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
         );
 
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(true, false);
 
         mTestableLooper.processAllMessages();
@@ -842,7 +815,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT, false);
+                true, false, IMPORTANCE_DEFAULT, false);
         mNotificationInfo.findViewById(R.id.block).performClick();
         waitForUndoButton();
 
@@ -861,8 +834,8 @@
                 true, false,
                 IMPORTANCE_DEFAULT, false);
 
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(true, false);
 
         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
@@ -929,7 +902,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT, false);
+                true, false, IMPORTANCE_DEFAULT, false);
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
 
@@ -944,7 +917,7 @@
         mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, false);
+                true, false, IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
@@ -1014,63 +987,14 @@
     }
 
     @Test
-    public void testBlockUndoDoesNotBlockNotificationChannel_notBlockingHelper() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
-                null, null, null,
-                true, false,
-                IMPORTANCE_DEFAULT, false);
-
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
-        mNotificationInfo.findViewById(R.id.undo).performClick();
-        waitForStopButton();
-        // mNotificationInfo.handleCloseControls doesn't get called by this interaction.
-
-        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
-        verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture());
-        assertEquals(MetricsEvent.ACTION_SAVE_IMPORTANCE,
-                logMakerCaptor.getValue().getCategory());
-        assertEquals(MetricsEvent.TYPE_DISMISS,
-                logMakerCaptor.getValue().getType());
-        assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW,
-                logMakerCaptor.getValue().getSubtype());
-
-
-        mTestableLooper.processAllMessages();
-        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), any());
-    }
-
-    @Test
-    public void testMinUndoDoesNotMinNotificationChannel_notBlockingHelper() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
-                null, null, null, true,
-                true, IMPORTANCE_DEFAULT, false);
-
-        mNotificationInfo.findViewById(R.id.minimize).performClick();
-        waitForUndoButton();
-        mNotificationInfo.findViewById(R.id.undo).performClick();
-        waitForStopButton();
-        // mNotificationInfo.handleCloseControls doesn't get called by this code path
-
-        mTestableLooper.processAllMessages();
-        verify(mMockINotificationManager, times(0)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), any());
-    }
-
-    @Test
     public void testSilenceCallsUpdateNotificationChannel() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT, true);
 
-        mNotificationInfo.findViewById(R.id.int_silent).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(true, false);
 
         mTestableLooper.processAllMessages();
@@ -1090,8 +1014,8 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT, false);
 
-        mNotificationInfo.findViewById(R.id.int_alert).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(true, false);
 
         mTestableLooper.processAllMessages();
@@ -1112,8 +1036,8 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT, true);
 
-        mNotificationInfo.findViewById(R.id.int_silent).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(true, false);
 
         mTestableLooper.processAllMessages();
@@ -1134,8 +1058,8 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_LOW, false);
 
-        mNotificationInfo.findViewById(R.id.int_alert).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(true, false);
 
         mTestableLooper.processAllMessages();
@@ -1153,7 +1077,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT, false);
+                true, false, IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
@@ -1171,8 +1095,8 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT, false);
 
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mNotificationInfo.handleCloseControls(false, false);
 
         mTestableLooper.processAllMessages();
@@ -1188,9 +1112,8 @@
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
                 }, null, null, true, true, IMPORTANCE_DEFAULT, false);
 
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
+        mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
         mTestableLooper.processAllMessages();
-        ensureNoUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
 
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -1207,12 +1130,12 @@
                 }, null, null, true, false, IMPORTANCE_DEFAULT, false
         );
 
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
+        mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+        mNotificationInfo.findViewById(R.id.done_button).performClick();
         mTestableLooper.processAllMessages();
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
 
-        waitForUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
 
         mTestableLooper.processAllMessages();
@@ -1231,78 +1154,11 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT, false);
+                true, false, IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
         TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
         assertTrue(confirmationText.getText().toString().contains("minimized"));
     }
-
-    @Test
-    public void testUndoText_block() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, false);
-
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
-        TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
-        assertTrue(confirmationText.getText().toString().contains("won't see"));
-    }
-
-    @Test
-    public void testUndoText_silence() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, true);
-
-        mNotificationInfo.findViewById(R.id.int_silent).performClick();
-        waitForUndoButton();
-        TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
-        assertEquals(mContext.getString(R.string.notification_channel_silenced),
-                confirmationText.getText());
-    }
-
-    @Test
-    public void testUndoText_unsilence() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, false);
-
-        mNotificationInfo.findViewById(R.id.int_alert).performClick();
-        waitForUndoButton();
-        TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
-        assertEquals(mContext.getString(R.string.notification_channel_unsilenced),
-                confirmationText.getText());
-    }
-
-    @Test
-    public void testNoHeaderOnConfirmation() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, false);
-
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
-        assertEquals(GONE, mNotificationInfo.findViewById(R.id.header).getVisibility());
-    }
-
-    @Test
-    public void testHeaderOnUndo() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT, false);
-
-        mNotificationInfo.findViewById(R.id.int_block).performClick();
-        waitForUndoButton();
-        mNotificationInfo.findViewById(R.id.undo).performClick();
-        waitForStopButton();
-        assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
-    }
 }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index abc1066a..0387774 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -519,10 +519,10 @@
 
     public void setProcess(ProcessRecord _proc) {
         app = _proc;
-        if (pendingConnectionGroup > 0) {
-            app.connectionService = this;
-            app.connectionGroup = pendingConnectionGroup;
-            app.connectionImportance = pendingConnectionImportance;
+        if (pendingConnectionGroup > 0 && _proc != null) {
+            _proc.connectionService = this;
+            _proc.connectionGroup = pendingConnectionGroup;
+            _proc.connectionImportance = pendingConnectionImportance;
             pendingConnectionGroup = pendingConnectionImportance = 0;
         }
         if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index c072d4e..83c0af9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -59,7 +59,7 @@
     public void setUpOnDisplay(DisplayContent dc) {
         mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(dc, false /* skipOnParentChanged */);
+        mToken = WindowTestUtils.createTestAppWindowToken(dc);
 
         mTask.addChild(mToken, 0);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index a98a604..db04f11 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -60,7 +60,7 @@
         MockitoAnnotations.initMocks(this);
 
         mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */);
+                ACTIVITY_TYPE_STANDARD);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 68b40b9..70c8c93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -81,8 +81,7 @@
     public void setUp() throws Exception {
         mStack = createTaskStackOnDisplay(mDisplayContent);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent,
-                false /* skipOnParentChanged */);
+        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
 
         mTask.addChild(mToken, 0);
     }
@@ -219,9 +218,6 @@
 
     @Test
     public void testSizeCompatBounds() {
-        // The real surface transaction is unnecessary.
-        mToken.setSkipPrepareSurfaces(true);
-
         final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 0dec8ee..a7a785d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -56,24 +56,15 @@
 
     static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
         synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc, true /* skipOnParentChanged */);
-        }
-    }
-
-    static TestAppWindowToken createTestAppWindowToken(DisplayContent dc,
-            boolean skipOnParentChanged) {
-        synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc, skipOnParentChanged);
+            return new TestAppWindowToken(dc);
         }
     }
 
     /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
     static class TestAppWindowToken extends AppWindowToken {
         boolean mOnTop = false;
-        private boolean mSkipPrepareSurfaces;
-        boolean mSkipOnParentChanged = true;
 
-        private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) {
+        private TestAppWindowToken(DisplayContent dc) {
             super(dc.mWmService, new IApplicationToken.Stub() {
                 @Override
                 public String getName() {
@@ -81,7 +72,6 @@
                 }
             }, new ComponentName("", ""), false, dc, true /* fillsParent */);
             mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT;
-            mSkipOnParentChanged = skipOnParentChanged;
             mActivityRecord = mock(ActivityRecord.class);
             mActivityRecord.app = mock(WindowProcessController.class);
         }
@@ -103,44 +93,10 @@
         }
 
         @Override
-        void onParentChanged() {
-            if (!mSkipOnParentChanged) {
-                super.onParentChanged();
-            } else {
-                updateConfigurationFromParent(this);
-            }
-        }
-
-        @Override
         boolean isOnTop() {
             return mOnTop;
         }
 
-        @Override
-        void prepareSurfaces() {
-            if (!mSkipPrepareSurfaces) {
-                super.prepareSurfaces();
-            }
-        }
-
-        void setSkipPrepareSurfaces(boolean ignore) {
-            mSkipPrepareSurfaces = ignore;
-        }
-    }
-
-    /**
-     * Used when we don't want to perform surface related operation in
-     * {@link WindowContainer#onParentChanged} or the overridden method, but the configuration
-     * still needs to propagate from parent.
-     *
-     * @see ConfigurationContainer#onParentChanged
-     */
-    static void updateConfigurationFromParent(WindowContainer container) {
-        final WindowContainer parent = container.getParent();
-        if (parent != null) {
-            container.onConfigurationChanged(parent.getConfiguration());
-            container.onMergedOverrideConfigurationChanged();
-        }
     }
 
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
@@ -246,10 +202,5 @@
 
             mHasSurface = hadSurface;
         }
-
-        @Override
-        void onParentChanged() {
-            updateConfigurationFromParent(this);
-        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 032eba1..fb698d9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -269,16 +269,10 @@
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
-        return createTestAppWindowToken(dc, windowingMode, activityType,
-                false /*skipOnParentChanged */);
-    }
-
-    WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
-            windowingMode, int activityType, boolean skipOnParentChanged) {
         final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final WindowTestUtils.TestAppWindowToken appWindowToken =
-                WindowTestUtils.createTestAppWindowToken(dc, skipOnParentChanged);
+                WindowTestUtils.createTestAppWindowToken(dc);
         task.addChild(appWindowToken, 0);
         return appWindowToken;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 2fc6efa..7d7c3985 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -43,7 +43,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.After;
@@ -212,7 +211,6 @@
         return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithNoTarget() {
         mDisplayContent.mInputMethodTarget = null;
@@ -230,7 +228,6 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithAppTarget() {
         final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -250,7 +247,6 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
         final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -277,7 +273,6 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
         final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
@@ -301,7 +296,6 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeNonAppImeTarget() {
         final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
@@ -329,7 +323,6 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForStatusBarImeTarget() {
         mDisplayContent.mInputMethodTarget = mStatusBarWindow;
@@ -344,7 +337,6 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testStackLayers() {
         final WindowState anyWindow1 = createWindow("anyWindow");
@@ -432,7 +424,6 @@
         }
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testDockedDividerPosition() {
         final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,