Merge "Import translations. DO NOT MERGE" into rvc-d1-dev
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 8a3fbde..cc3017a 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -841,6 +841,35 @@
      */
     public static final String PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT =
             "android.media.mediaParser.exposeChunkIndexAsMediaFormat";
+    /**
+     * Sets a list of closed-caption {@link MediaFormat MediaFormats} that should be exposed as part
+     * of the extracted media. {@code List<MediaFormat>} expected. Default value is an empty list.
+     *
+     * <p>Expected keys in the {@link MediaFormat} are:
+     *
+     * <ul>
+     *   <p>{@link MediaFormat#KEY_MIME}: Determine the type of captions (for example,
+     *   application/cea-608). Mandatory.
+     *   <p>{@link MediaFormat#KEY_CAPTION_SERVICE_NUMBER}: Determine the channel on which the
+     *   captions are transmitted. Optional.
+     * </ul>
+     *
+     * @hide
+     */
+    public static final String PARAMETER_EXPOSE_CAPTION_FORMATS =
+            "android.media.mediaParser.exposeCaptionFormats";
+    /**
+     * Sets whether the value associated with {@link #PARAMETER_EXPOSE_CAPTION_FORMATS} should
+     * override any in-band caption service declarations. {@code boolean} expected. Default value is
+     * {@link false}.
+     *
+     * <p>When {@code false}, any present in-band caption services information will override the
+     * values associated with {@link #PARAMETER_EXPOSE_CAPTION_FORMATS}.
+     *
+     * @hide
+     */
+    public static final String PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS =
+            "android.media.mediaParser.overrideInBandCaptionDeclarations";
 
     // Private constants.
 
@@ -1000,6 +1029,7 @@
     private final DataReaderAdapter mScratchDataReaderAdapter;
     private final ParsableByteArrayAdapter mScratchParsableByteArrayAdapter;
     @Nullable private final Constructor<DrmInitData.SchemeInitData> mSchemeInitDataConstructor;
+    private final ArrayList<Format> mMuxedCaptionFormats;
     private boolean mInBandCryptoInfo;
     private boolean mIncludeSupplementalData;
     private boolean mIgnoreTimestampOffset;
@@ -1071,6 +1101,9 @@
         if (PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT.equals(parameterName)) {
             mExposeChunkIndexAsMediaFormat = (boolean) value;
         }
+        if (PARAMETER_EXPOSE_CAPTION_FORMATS.equals(parameterName)) {
+            setMuxedCaptionFormats((List<MediaFormat>) value);
+        }
         mParserParameters.put(parameterName, value);
         return this;
     }
@@ -1109,8 +1142,8 @@
      *
      * <p>This method will block until some progress has been made.
      *
-     * <p>If this instance was created using {@link #create}. the first call to this method will
-     * sniff the content with the parsers with the provided names.
+     * <p>If this instance was created using {@link #create}, the first call to this method will
+     * sniff the content using the selected parser implementations.
      *
      * @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media
      *     container data.
@@ -1242,6 +1275,14 @@
         mScratchDataReaderAdapter = new DataReaderAdapter();
         mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter();
         mSchemeInitDataConstructor = getSchemeInitDataConstructor();
+        mMuxedCaptionFormats = new ArrayList<>();
+    }
+
+    private void setMuxedCaptionFormats(List<MediaFormat> mediaFormats) {
+        mMuxedCaptionFormats.clear();
+        for (MediaFormat mediaFormat : mediaFormats) {
+            mMuxedCaptionFormats.add(toExoPlayerCaptionFormat(mediaFormat));
+        }
     }
 
     private boolean isPendingSeek() {
@@ -1280,7 +1321,11 @@
                                 ? FragmentedMp4Extractor
                                         .FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
                                 : 0;
-                return new FragmentedMp4Extractor(flags, timestampAdjuster);
+                return new FragmentedMp4Extractor(
+                        flags,
+                        timestampAdjuster,
+                        /* sideloadedTrack= */ null,
+                        mMuxedCaptionFormats);
             case PARSER_NAME_MP4:
                 flags |=
                         getBooleanParameter(PARAMETER_MP4_IGNORE_EDIT_LISTS)
@@ -1331,6 +1376,10 @@
                         getBooleanParameter(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM)
                                 ? DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM
                                 : 0;
+                flags |=
+                        getBooleanParameter(PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS)
+                                ? DefaultTsPayloadReaderFactory.FLAG_OVERRIDE_CAPTION_DESCRIPTORS
+                                : 0;
                 String tsMode = getStringParameter(PARAMETER_TS_MODE, TS_MODE_SINGLE_PMT);
                 int hlsMode =
                         TS_MODE_SINGLE_PMT.equals(tsMode)
@@ -1343,7 +1392,7 @@
                         timestampAdjuster != null
                                 ? timestampAdjuster
                                 : new TimestampAdjuster(/* firstSampleTimestampUs= */ 0),
-                        new DefaultTsPayloadReaderFactory(flags));
+                        new DefaultTsPayloadReaderFactory(flags, mMuxedCaptionFormats));
             case PARSER_NAME_FLV:
                 return new FlvExtractor();
             case PARSER_NAME_OGG:
@@ -1789,6 +1838,16 @@
 
     // Private static methods.
 
+    private static Format toExoPlayerCaptionFormat(MediaFormat mediaFormat) {
+        Format.Builder formatBuilder =
+                new Format.Builder().setSampleMimeType(mediaFormat.getString(MediaFormat.KEY_MIME));
+        if (mediaFormat.containsKey(MediaFormat.KEY_CAPTION_SERVICE_NUMBER)) {
+            formatBuilder.setAccessibilityChannel(
+                    mediaFormat.getInteger(MediaFormat.KEY_CAPTION_SERVICE_NUMBER));
+        }
+        return formatBuilder.build();
+    }
+
     private static MediaFormat toMediaFormat(Format format) {
         MediaFormat result = new MediaFormat();
         setOptionalMediaFormatInt(result, MediaFormat.KEY_BIT_RATE, format.bitrate);
@@ -2041,6 +2100,11 @@
         expectedTypeByParameterName.put(PARAMETER_EXPOSE_DUMMY_SEEKMAP, Boolean.class);
         expectedTypeByParameterName.put(
                 PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT, Boolean.class);
+        expectedTypeByParameterName.put(
+                PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS, Boolean.class);
+        // We do not check PARAMETER_EXPOSE_CAPTION_FORMATS here, and we do it in setParameters
+        // instead. Checking that the value is a List is insufficient to catch wrong parameter
+        // value types.
         EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
     }
 }
diff --git a/api/test-current.txt b/api/test-current.txt
index 5bae370..7fd5698 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5264,6 +5264,7 @@
     ctor public AutofillId(int, int);
     ctor public AutofillId(@NonNull android.view.autofill.AutofillId, long, int);
     method public boolean equalsIgnoreSession(@Nullable android.view.autofill.AutofillId);
+    method @NonNull public static android.view.autofill.AutofillId withoutSession(@NonNull android.view.autofill.AutofillId);
   }
 
   public final class AutofillManager {
@@ -5505,6 +5506,19 @@
 
 }
 
+package android.widget.inline {
+
+  public class InlineContentView extends android.view.ViewGroup {
+    method public void setChildSurfacePackageUpdater(@Nullable android.widget.inline.InlineContentView.SurfacePackageUpdater);
+  }
+
+  public static interface InlineContentView.SurfacePackageUpdater {
+    method public void getSurfacePackage(@NonNull java.util.function.Consumer<android.view.SurfaceControlViewHost.SurfacePackage>);
+    method public void onSurfacePackageReleased();
+  }
+
+}
+
 package android.window {
 
   public final class DisplayAreaInfo implements android.os.Parcelable {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 86a3579..a828aac 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1900,11 +1900,13 @@
 
     @Override
     public Object getSystemService(String name) {
+        // We may override this API from outer context.
+        final boolean isUiContext = isUiContext() || getOuterContext().isUiContext();
         // Check incorrect Context usage.
-        if (isUiComponent(name) && !isUiContext() && vmIncorrectContextUseEnabled()) {
+        if (isUiComponent(name) && !isUiContext && vmIncorrectContextUseEnabled()) {
             final String errorMessage = "Tried to access visual service "
                     + SystemServiceRegistry.getSystemServiceClassName(name)
-                    + " from a non-visual Context. ";
+                    + " from a non-visual Context:" + getOuterContext();
             final String message = "Visual services, such as WindowManager, WallpaperService or "
                     + "LayoutInflater should be accessed from Activity or other visual Context. "
                     + "Use an Activity or a Context created with "
@@ -2369,6 +2371,7 @@
         context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
                 overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
                 mResources.getLoaders()));
+        context.mIsUiContext = isUiContext() || getOuterContext().isUiContext();
         return context;
     }
 
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index d8b1f41..5647bf9 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -471,6 +471,10 @@
 
     final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
         onComputeInsets(mTmpInsets);
+        if (!mViewsCreated) {
+            // The IME views are not ready, keep visible insets untouched.
+            mTmpInsets.visibleTopInsets = 0;
+        }
         if (isExtractViewShown()) {
             // In true fullscreen mode, we just say the window isn't covering
             // any content so we don't impact whatever is behind.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index ef2a8a1..b36aeb8 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -133,12 +133,23 @@
      * <a href="/training/articles/security-key-attestation.html">key attestation</a> to obtain
      * proof of the device's original identifiers.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). The profile
-     * owner is an app that owns a managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link
+     *     android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription.
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     android.app.role.RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -150,7 +161,7 @@
      *     the READ_PHONE_STATE permission, or if the calling app is targeting API level 29 or
      *     higher, then a SecurityException is thrown.</li>
      * </ul>
-     * *
+     *
      * @return The serial number if specified.
      */
     @SuppressAutoDoc // No support for device / profile owner.
diff --git a/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl b/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl
index bf0bb9e..7cd372f 100644
--- a/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl
+++ b/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl
@@ -29,6 +29,12 @@
 oneway interface IInlineSuggestionRenderService {
     void renderSuggestion(in IInlineSuggestionUiCallback callback,
                           in InlinePresentation presentation, int width, int height,
-                          in IBinder hostInputToken, int displayId);
+                          in IBinder hostInputToken, int displayId, int userId, int sessionId);
     void getInlineSuggestionsRendererInfo(in RemoteCallback callback);
+
+    /**
+     * Releases the inline suggestion SurfaceControlViewHosts hosted in the service, for the
+     * provided userId and sessionId.
+     */
+    void destroySuggestionViews(int userId, int sessionId);
 }
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index 8790fb2..839caff 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -41,6 +41,8 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 
 /**
@@ -82,7 +84,7 @@
                         Boolean newValue) {
                     if (evicted) {
                         Log.w(TAG,
-                                "Hit max=100 entries in the cache. Releasing oldest one to make "
+                                "Hit max=30 entries in the cache. Releasing oldest one to make "
                                         + "space.");
                         key.releaseSurfaceControlViewHost();
                     }
@@ -130,7 +132,7 @@
 
     private void handleRenderSuggestion(IInlineSuggestionUiCallback callback,
             InlinePresentation presentation, int width, int height, IBinder hostInputToken,
-            int displayId) {
+            int displayId, int userId, int sessionId) {
         if (hostInputToken == null) {
             try {
                 callback.onError();
@@ -192,7 +194,8 @@
                 }
                 return true;
             });
-            final InlineSuggestionUiImpl uiImpl = new InlineSuggestionUiImpl(host, mMainHandler);
+            final InlineSuggestionUiImpl uiImpl = new InlineSuggestionUiImpl(host, mMainHandler,
+                    userId, sessionId);
             mActiveInlineSuggestions.put(uiImpl, true);
 
             // We post the callback invocation to the end of the main thread handler queue, to make
@@ -218,6 +221,18 @@
         callback.sendResult(rendererInfo);
     }
 
+    private void handleDestroySuggestionViews(int userId, int sessionId) {
+        Log.v(TAG, "handleDestroySuggestionViews called for " + userId + ":" + sessionId);
+        for (final InlineSuggestionUiImpl inlineSuggestionUi :
+                mActiveInlineSuggestions.snapshot().keySet()) {
+            if (inlineSuggestionUi.mUserId == userId
+                    && inlineSuggestionUi.mSessionId == sessionId) {
+                Log.v(TAG, "Destroy " + inlineSuggestionUi);
+                inlineSuggestionUi.releaseSurfaceControlViewHost();
+            }
+        }
+    }
+
     /**
      * A wrapper class around the {@link InlineSuggestionUiImpl} to ensure it's not strongly
      * reference by the remote system server process.
@@ -260,10 +275,15 @@
         private SurfaceControlViewHost mViewHost;
         @NonNull
         private final Handler mHandler;
+        private final int mUserId;
+        private final int mSessionId;
 
-        InlineSuggestionUiImpl(SurfaceControlViewHost viewHost, Handler handler) {
+        InlineSuggestionUiImpl(SurfaceControlViewHost viewHost, Handler handler, int userId,
+                int sessionId) {
             this.mViewHost = viewHost;
             this.mHandler = handler;
+            this.mUserId = userId;
+            this.mSessionId = sessionId;
         }
 
         /**
@@ -302,6 +322,16 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected final void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+            @NonNull String[] args) {
+        pw.println("mActiveInlineSuggestions: " + mActiveInlineSuggestions.size());
+        for (InlineSuggestionUiImpl impl : mActiveInlineSuggestions.snapshot().keySet()) {
+            pw.printf("ui: [%s] - [%d]  [%d]\n", impl, impl.mUserId, impl.mSessionId);
+        }
+    }
+
     @Override
     @Nullable
     public final IBinder onBind(@NonNull Intent intent) {
@@ -311,11 +341,12 @@
                 @Override
                 public void renderSuggestion(@NonNull IInlineSuggestionUiCallback callback,
                         @NonNull InlinePresentation presentation, int width, int height,
-                        @Nullable IBinder hostInputToken, int displayId) {
+                        @Nullable IBinder hostInputToken, int displayId, int userId,
+                        int sessionId) {
                     mMainHandler.sendMessage(
                             obtainMessage(InlineSuggestionRenderService::handleRenderSuggestion,
                                     InlineSuggestionRenderService.this, callback, presentation,
-                                    width, height, hostInputToken, displayId));
+                                    width, height, hostInputToken, displayId, userId, sessionId));
                 }
 
                 @Override
@@ -324,6 +355,12 @@
                             InlineSuggestionRenderService::handleGetInlineSuggestionsRendererInfo,
                             InlineSuggestionRenderService.this, callback));
                 }
+                @Override
+                public void destroySuggestionViews(int userId, int sessionId) {
+                    mMainHandler.sendMessage(obtainMessage(
+                            InlineSuggestionRenderService::handleDestroySuggestionViews,
+                            InlineSuggestionRenderService.this, userId, sessionId));
+                }
             }.asBinder();
         }
 
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index 4e5aa00..6bd376a 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -296,6 +296,10 @@
 
     /**
      * Request SystemUI to prompt the user to add a control to favorites.
+     * <br>
+     * SystemUI may not honor this request in some cases, for example if the requested
+     * {@link Control} is already a favorite, or the requesting package is not currently in the
+     * foreground.
      *
      * @param context A context
      * @param componentName Component name of the {@link ControlsProviderService}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index a3c88ba..c6be91f 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -514,6 +514,12 @@
     /** Set of inset types for which an animation was started since last resetting this field */
     private @InsetsType int mLastStartedAnimTypes;
 
+    /** Set of inset types which cannot be controlled by the user animation */
+    private @InsetsType int mDisabledUserAnimationInsetsTypes;
+
+    private Runnable mInvokeControllableInsetsChangedListeners =
+            this::invokeControllableInsetsChangedListeners;
+
     public InsetsController(Host host) {
         this(host, (controller, type) -> {
             if (type == ITYPE_IME) {
@@ -628,22 +634,57 @@
 
     private void updateState(InsetsState newState) {
         mState.setDisplayFrame(newState.getDisplayFrame());
-        for (int i = 0; i < InsetsState.SIZE; i++) {
-            InsetsSource source = newState.peekSource(i);
-            if (source == null) continue;;
-            getSourceConsumer(source.getType()).updateSource(source);
-        }
-        for (int i = 0; i < InsetsState.SIZE; i++) {
-            InsetsSource source = mState.peekSource(i);
+        @InsetsType int disabledUserAnimationTypes = 0;
+        @InsetsType int[] cancelledUserAnimationTypes = {0};
+        for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
+            InsetsSource source = newState.peekSource(type);
             if (source == null) continue;
-            if (newState.peekSource(source.getType()) == null) {
-                mState.removeSource(source.getType());
+            @AnimationType int animationType = getAnimationType(type);
+            if (!source.isUserControllable()) {
+                @InsetsType int insetsType = toPublicType(type);
+                // The user animation is not allowed when visible frame is empty.
+                disabledUserAnimationTypes |= insetsType;
+                if (animationType == ANIMATION_TYPE_USER) {
+                    // Existing user animation needs to be cancelled.
+                    animationType = ANIMATION_TYPE_NONE;
+                    cancelledUserAnimationTypes[0] |= insetsType;
+                }
+            }
+            getSourceConsumer(type).updateSource(source, animationType);
+        }
+        for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
+            InsetsSource source = mState.peekSource(type);
+            if (source == null) continue;
+            if (newState.peekSource(type) == null) {
+                mState.removeSource(type);
             }
         }
         if (mCaptionInsetsHeight != 0) {
             mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
                     mFrame.right, mFrame.top + mCaptionInsetsHeight));
         }
+
+        updateDisabledUserAnimationTypes(disabledUserAnimationTypes);
+
+        if (cancelledUserAnimationTypes[0] != 0) {
+            mHandler.post(() -> show(cancelledUserAnimationTypes[0]));
+        }
+    }
+
+    private void updateDisabledUserAnimationTypes(@InsetsType int disabledUserAnimationTypes) {
+        @InsetsType int diff = mDisabledUserAnimationInsetsTypes ^ disabledUserAnimationTypes;
+        if (diff != 0) {
+            for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
+                InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
+                if (consumer.getControl() != null
+                        && (toPublicType(consumer.getType()) & diff) != 0) {
+                    mHandler.removeCallbacks(mInvokeControllableInsetsChangedListeners);
+                    mHandler.post(mInvokeControllableInsetsChangedListeners);
+                    break;
+                }
+            }
+            mDisabledUserAnimationInsetsTypes = disabledUserAnimationTypes;
+        }
     }
 
     private boolean captionInsetsUnchanged() {
@@ -847,6 +888,18 @@
                     + " while an existing " + Type.toString(mTypesBeingCancelled)
                     + " is being cancelled.");
         }
+        if (animationType == ANIMATION_TYPE_USER) {
+            final @InsetsType int disabledTypes = types & mDisabledUserAnimationInsetsTypes;
+            if (DEBUG) Log.d(TAG, "user animation disabled types: " + disabledTypes);
+            types &= ~mDisabledUserAnimationInsetsTypes;
+
+            if (fromIme && (disabledTypes & ime()) != 0
+                    && !mState.getSource(ITYPE_IME).isVisible()) {
+                // We've requested IMM to show IME, but the IME is not controllable. We need to
+                // cancel the request.
+                getSourceConsumer(ITYPE_IME).hide(true, animationType);
+            }
+        }
         if (types == 0) {
             // nothing to animate.
             listener.onCancelled(null);
@@ -1320,7 +1373,8 @@
         @InsetsType int result = 0;
         for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
             InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
-            if (consumer.getControl() != null) {
+            InsetsSource source = mState.peekSource(consumer.mType);
+            if (consumer.getControl() != null && source != null && source.isUserControllable()) {
                 result |= toPublicType(consumer.mType);
             }
         }
@@ -1331,6 +1385,7 @@
      * @return The types that are now animating due to a listener invoking control/show/hide
      */
     private @InsetsType int invokeControllableInsetsChangedListeners() {
+        mHandler.removeCallbacks(mInvokeControllableInsetsChangedListeners);
         mLastStartedAnimTypes = 0;
         @InsetsType int types = calculateControllableTypes();
         int size = mControllableInsetsChangedListeners.size();
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 15b9a93..dbf7570 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -92,6 +92,11 @@
         return mVisible;
     }
 
+    boolean isUserControllable() {
+        // If mVisibleFrame is null, it will be the same area as mFrame.
+        return mVisibleFrame == null || !mVisibleFrame.isEmpty();
+    }
+
     /**
      * Calculates the insets this source will cause to a client window.
      *
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index b62e67c..40e6f4b 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -18,8 +18,8 @@
 
 import static android.view.InsetsController.ANIMATION_TYPE_NONE;
 import static android.view.InsetsController.AnimationType;
-import static android.view.InsetsState.getDefaultVisibility;
 import static android.view.InsetsController.DEBUG;
+import static android.view.InsetsState.getDefaultVisibility;
 import static android.view.InsetsState.toPublicType;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
@@ -284,9 +284,9 @@
     }
 
     @VisibleForTesting(visibility = PACKAGE)
-    public void updateSource(InsetsSource newSource) {
+    public void updateSource(InsetsSource newSource, @AnimationType int animationType) {
         InsetsSource source = mState.peekSource(mType);
-        if (source == null || mController.getAnimationType(mType) == ANIMATION_TYPE_NONE
+        if (source == null || animationType == ANIMATION_TYPE_NONE
                 || source.getFrame().equals(newSource.getFrame())) {
             mPendingFrame = null;
             mPendingVisibleFrame = null;
@@ -295,7 +295,7 @@
         }
 
         // Frame is changing while animating. Keep note of the new frame but keep existing frame
-        // until animaition is finished.
+        // until animation is finished.
         newSource = new InsetsSource(newSource);
         mPendingFrame = new Rect(newSource.getFrame());
         mPendingVisibleFrame = newSource.getVisibleFrame() != null
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 19eff72..51b0c6b 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -487,6 +487,21 @@
     public static final int FLAG_TAINTED = 0x80000000;
 
     /**
+     * Private flag indicating that this event was synthesized by the system and should be delivered
+     * to the accessibility focused view first. When being dispatched such an event is not handled
+     * by predecessors of the accessibility focused view and after the event reaches that view the
+     * flag is cleared and normal event dispatch is performed. This ensures that the platform can
+     * click on any view that has accessibility focus which is semantically equivalent to asking the
+     * view to perform a click accessibility action but more generic as views not implementing click
+     * action correctly can still be activated.
+     *
+     * @hide
+     * @see #isTargetAccessibilityFocus()
+     * @see #setTargetAccessibilityFocus(boolean)
+     */
+    public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000;
+
+    /**
      * Flag indicating the motion event intersected the top edge of the screen.
      */
     public static final int EDGE_TOP = 0x00000001;
@@ -2140,6 +2155,20 @@
     }
 
     /** @hide */
+    public  boolean isTargetAccessibilityFocus() {
+        final int flags = getFlags();
+        return (flags & FLAG_TARGET_ACCESSIBILITY_FOCUS) != 0;
+    }
+
+    /** @hide */
+    public void setTargetAccessibilityFocus(boolean targetsFocus) {
+        final int flags = getFlags();
+        nativeSetFlags(mNativePtr, targetsFocus
+                ? flags | FLAG_TARGET_ACCESSIBILITY_FOCUS
+                : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS);
+    }
+
+    /** @hide */
     public final boolean isHoverExitPending() {
         final int flags = getFlags();
         return (flags & FLAG_HOVER_EXIT_PENDING) != 0;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 3b38365..daeb1c9 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -63,8 +63,10 @@
 import libcore.util.NativeAllocationRegistry;
 
 import java.io.Closeable;
+import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.ArrayList;
 import java.util.Objects;
 
 /**
@@ -226,24 +228,86 @@
     private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject,
             int transformHint);
 
+    @Nullable
+    @GuardedBy("mLock")
+    private ArrayList<OnReparentListener> mReparentListeners;
+
+    /**
+     * Listener to observe surface reparenting.
+     *
+     * @hide
+     */
+    public interface OnReparentListener {
+
+        /**
+         * Callback for reparenting surfaces.
+         *
+         * Important: You should only interact with the provided surface control
+         * only if you have a contract with its owner to avoid them closing it
+         * under you or vise versa.
+         *
+         * @param transaction The transaction that would commit reparenting.
+         * @param parent The future parent surface.
+         */
+        void onReparent(@NonNull Transaction transaction, @Nullable SurfaceControl parent);
+    }
+
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
-    /**
+
+     /**
      * @hide
      */
     public long mNativeObject;
     private long mNativeHandle;
 
-    // TODO: Move this to native.
-    private final Object mSizeLock = new Object();
-    @GuardedBy("mSizeLock")
+    // TODO: Move width/height to native and fix locking through out.
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
     private int mWidth;
-    @GuardedBy("mSizeLock")
+    @GuardedBy("mLock")
     private int mHeight;
 
+    private WeakReference<View> mLocalOwnerView;
+
     static Transaction sGlobalTransaction;
     static long sTransactionNestCount = 0;
 
+    /**
+     * Adds a reparenting listener.
+     *
+     * @param listener The listener.
+     * @return Whether listener was added.
+     *
+     * @hide
+     */
+    public boolean addOnReparentListener(@NonNull OnReparentListener listener) {
+        synchronized (mLock) {
+            if (mReparentListeners == null) {
+                mReparentListeners = new ArrayList<>(1);
+            }
+            return mReparentListeners.add(listener);
+        }
+    }
+
+    /**
+     * Removes a reparenting listener.
+     *
+     * @param listener The listener.
+     * @return Whether listener was removed.
+     *
+     * @hide
+     */
+    public boolean removeOnReparentListener(@NonNull OnReparentListener listener) {
+        synchronized (mLock) {
+            final boolean removed = mReparentListeners.remove(listener);
+            if (mReparentListeners.isEmpty()) {
+                mReparentListeners = null;
+            }
+            return removed;
+        }
+    }
+
     /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
 
     /**
@@ -455,6 +519,7 @@
         mName = other.mName;
         mWidth = other.mWidth;
         mHeight = other.mHeight;
+        mLocalOwnerView = other.mLocalOwnerView;
         assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject));
     }
 
@@ -553,6 +618,7 @@
         private int mHeight;
         private int mFormat = PixelFormat.OPAQUE;
         private String mName;
+        private WeakReference<View> mLocalOwnerView;
         private SurfaceControl mParent;
         private SparseIntArray mMetadata;
 
@@ -587,7 +653,8 @@
                         "Only buffer layers can set a valid buffer size.");
             }
             return new SurfaceControl(
-                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata);
+                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
+                    mLocalOwnerView);
         }
 
         /**
@@ -602,6 +669,27 @@
         }
 
         /**
+         * Set the local owner view for the surface. This view is only
+         * valid in the same process and is not transferred in an IPC.
+         *
+         * Note: This is used for cases where we want to know the view
+         * that manages the surface control while intercepting reparenting.
+         * A specific example is InlineContentView which exposes is surface
+         * control for reparenting as a way to implement clipping of several
+         * InlineContentView instances within a certain area.
+         *
+         * @param view The owner view.
+         * @return This builder.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setLocalOwnerView(@NonNull View view) {
+            mLocalOwnerView = new WeakReference<>(view);
+            return this;
+        }
+
+        /**
          * Set the initial size of the controlled surface's buffers in pixels.
          *
          * @param width The buffer width in pixels.
@@ -858,7 +946,7 @@
      * @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
      */
     private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
-            SurfaceControl parent, SparseIntArray metadata)
+            SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView)
                     throws OutOfResourcesException, IllegalArgumentException {
         if (name == null) {
             throw new IllegalArgumentException("name must not be null");
@@ -867,6 +955,7 @@
         mName = name;
         mWidth = w;
         mHeight = h;
+        mLocalOwnerView = localOwnerView;
         Parcel metaParcel = Parcel.obtain();
         try {
             if (metadata != null && metadata.size() > 0) {
@@ -1307,7 +1396,7 @@
      * @hide
      */
     public int getWidth() {
-        synchronized (mSizeLock) {
+        synchronized (mLock) {
             return mWidth;
         }
     }
@@ -1316,11 +1405,22 @@
      * @hide
      */
     public int getHeight() {
-        synchronized (mSizeLock) {
+        synchronized (mLock) {
             return mHeight;
         }
     }
 
+    /**
+     * Gets the local view that owns this surface.
+     *
+     * @return The owner view.
+     *
+     * @hide
+     */
+    public @Nullable View getLocalOwnerView() {
+        return (mLocalOwnerView != null) ? mLocalOwnerView.get() : null;
+    }
+
     @Override
     public String toString() {
         return "Surface(name=" + mName + ")/@0x" +
@@ -2165,6 +2265,9 @@
         public long mNativeObject;
 
         private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
+        private final ArrayMap<SurfaceControl, SurfaceControl> mReparentedSurfaces =
+                 new ArrayMap<>();
+
         Runnable mFreeNativeResources;
         private static final float[] INVALID_COLOR = {-1, -1, -1};
 
@@ -2205,6 +2308,8 @@
          */
         @Override
         public void close() {
+            mResizedSurfaces.clear();
+            mReparentedSurfaces.clear();
             mFreeNativeResources.run();
             mNativeObject = 0;
         }
@@ -2215,6 +2320,7 @@
          */
         public void apply(boolean sync) {
             applyResizedSurfaces();
+            notifyReparentedSurfaces();
             nativeApplyTransaction(mNativeObject, sync);
         }
 
@@ -2222,7 +2328,7 @@
             for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) {
                 final Point size = mResizedSurfaces.valueAt(i);
                 final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i);
-                synchronized (surfaceControl.mSizeLock) {
+                synchronized (surfaceControl.mLock) {
                     surfaceControl.mWidth = size.x;
                     surfaceControl.mHeight = size.y;
                 }
@@ -2230,6 +2336,22 @@
             mResizedSurfaces.clear();
         }
 
+        private void notifyReparentedSurfaces() {
+            final int reparentCount = mReparentedSurfaces.size();
+            for (int i = reparentCount - 1; i >= 0; i--) {
+                final SurfaceControl child = mReparentedSurfaces.keyAt(i);
+                synchronized (child.mLock) {
+                    final int listenerCount = (child.mReparentListeners != null)
+                            ? child.mReparentListeners.size() : 0;
+                    for (int j = 0; j < listenerCount; j++) {
+                        final OnReparentListener listener = child.mReparentListeners.get(j);
+                        listener.onReparent(this, mReparentedSurfaces.valueAt(i));
+                    }
+                    mReparentedSurfaces.removeAt(i);
+                }
+            }
+        }
+
         /**
          * Toggle the visibility of a given Layer and it's sub-tree.
          *
@@ -2632,6 +2754,7 @@
                 otherObject = newParent.mNativeObject;
             }
             nativeReparent(mNativeObject, sc.mNativeObject, otherObject);
+            mReparentedSurfaces.put(sc, newParent);
             return this;
         }
 
@@ -2912,6 +3035,8 @@
             }
             mResizedSurfaces.putAll(other.mResizedSurfaces);
             other.mResizedSurfaces.clear();
+            mReparentedSurfaces.putAll(other.mReparentedSurfaces);
+            other.mReparentedSurfaces.clear();
             nativeMergeTransaction(mNativeObject, other.mNativeObject);
             return this;
         }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 90e1eab..0d21eb5 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -44,7 +44,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.SurfaceControl.Transaction;
-import android.view.SurfaceControlViewHost;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityEmbeddedConnection;
 
@@ -988,6 +987,7 @@
 
                     mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
                         .setName(name)
+                        .setLocalOwnerView(this)
                         .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
                         .setBufferSize(mSurfaceWidth, mSurfaceHeight)
                         .setFormat(mFormat)
@@ -996,6 +996,7 @@
                         .build();
                     mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
                         .setName("Background for -" + name)
+                        .setLocalOwnerView(this)
                         .setOpaque(true)
                         .setColorLayer()
                         .setParent(mSurfaceControl)
@@ -1051,11 +1052,12 @@
                     // we still need to latch a buffer).
                     // b/28866173
                     if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
-                        mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left,
-                                mScreenRect.top);
-                        mTmpTransaction.setMatrix(mSurfaceControl,
-                                mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f,
-                                mScreenRect.height() / (float) mSurfaceHeight);
+                        onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+                                mScreenRect.left, /*positionLeft*/
+                                mScreenRect.top /*positionTop*/ ,
+                                mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
+                                mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
+
                         // Set a window crop when creating the surface or changing its size to
                         // crop the buffer to the surface size since the buffer producer may
                         // use SCALING_MODE_SCALE and submit a larger size than the surface
@@ -1211,6 +1213,40 @@
             Surface viewRootSurface, long nextViewRootFrameNumber) {
     }
 
+    /**
+     * Sets the surface position and scale. Can be called on
+     * the UI thread as well as on the renderer thread.
+     *
+     * @param transaction Transaction in which to execute.
+     * @param surface Surface whose location to set.
+     * @param positionLeft The left position to set.
+     * @param positionTop The top position to set.
+     * @param postScaleX The X axis post scale
+     * @param postScaleY The Y axis post scale
+     *
+     * @hide
+     */
+    protected void onSetSurfacePositionAndScaleRT(@NonNull Transaction transaction,
+            @NonNull SurfaceControl surface, int positionLeft, int positionTop,
+            float postScaleX, float postScaleY) {
+        transaction.setPosition(surface, positionLeft, positionTop);
+        transaction.setMatrix(surface, postScaleX /*dsdx*/, 0f /*dtdx*/,
+                0f /*dtdy*/, postScaleY /*dsdy*/);
+    }
+
+    /** @hide */
+    public void requestUpdateSurfacePositionAndScale() {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+                mScreenRect.left, /*positionLeft*/
+                mScreenRect.top/*positionTop*/ ,
+                mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
+                mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
+        mTmpTransaction.apply();
+    }
+
     private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
             Rect position, long frameNumber) {
         final ViewRootImpl viewRoot = getViewRootImpl();
@@ -1219,16 +1255,26 @@
                     frameNumber);
         }
 
-        t.setPosition(surface, position.left, position.top);
-        t.setMatrix(surface,
-                position.width() / (float) mSurfaceWidth,
-                0.0f, 0.0f,
-                position.height() / (float) mSurfaceHeight);
+        onSetSurfacePositionAndScaleRT(t, surface,
+                position.left /*positionLeft*/,
+                position.top /*positionTop*/,
+                position.width() / (float) mSurfaceWidth /*postScaleX*/,
+                position.height() / (float) mSurfaceHeight /*postScaleY*/);
+
         if (mViewVisibility) {
             t.show(surface);
         }
     }
 
+    /**
+     * @return The last render position of the backing surface or an empty rect.
+     *
+     * @hide
+     */
+    public @NonNull Rect getSurfaceRenderPosition() {
+        return mRTLastReportedPosition;
+    }
+
     private void setParentSpaceRectangle(Rect position, long frameNumber) {
         final ViewRootImpl viewRoot = getViewRootImpl();
         final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1226202..df1c672 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14274,6 +14274,14 @@
      */
     public boolean dispatchTouchEvent(MotionEvent event) {
         // If the event should be handled by accessibility focus first.
+        if (event.isTargetAccessibilityFocus()) {
+            // We don't have focus or no virtual descendant has it, do not handle the event.
+            if (!isAccessibilityFocusedViewOrHost()) {
+                return false;
+            }
+            // We have focus and got the event, then use normal event dispatch.
+            event.setTargetAccessibilityFocus(false);
+        }
         boolean result = false;
 
         if (mInputEventConsistencyVerifier != null) {
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 0d2d4d1..ffeeb80 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -500,12 +500,13 @@
      */
     public static ViewConfiguration get(Context context) {
         if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
-            final String errorMessage = "Tried to access UI constants from a non-visual Context.";
+            final String errorMessage = "Tried to access UI constants from a non-visual Context:"
+                    + context;
             final String message = "UI constants, such as display metrics or window metrics, "
                     + "must be accessed from Activity or other visual Context. "
                     + "Use an Activity or a Context created with "
                     + "Context#createWindowContext(int, Bundle), which are adjusted to the "
-                    + "configuration and visual bounds of an area on screen.";
+                    + "configuration and visual bounds of an area on screen";
             final Exception exception = new IllegalArgumentException(errorMessage);
             StrictMode.onIncorrectContextUsed(message, exception);
             Log.e(TAG, errorMessage + message, exception);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e3362aa..77fedd7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2048,8 +2048,26 @@
             for (int i = childrenCount - 1; i >= 0; i--) {
                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+                View childWithAccessibilityFocus =
+                        event.isTargetAccessibilityFocus()
+                                ? findChildWithAccessibilityFocus()
+                                : null;
+
                 if (!child.canReceivePointerEvents()
                         || !isTransformedTouchPointInView(x, y, child, null)) {
+
+                    // If there is a view that has accessibility focus we want it
+                    // to get the event first and if not handled we will perform a
+                    // normal dispatch. We may do a double iteration but this is
+                    // safer given the timeframe.
+                    if (childWithAccessibilityFocus != null) {
+                        if (childWithAccessibilityFocus != child) {
+                            continue;
+                        }
+                        childWithAccessibilityFocus = null;
+                        i = childrenCount - 1;
+                    }
+                    event.setTargetAccessibilityFocus(false);
                     continue;
                 }
                 final PointerIcon pointerIcon =
@@ -2617,6 +2635,12 @@
             mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
         }
 
+        // If the event targets the accessibility focused view and this is it, start
+        // normal event dispatch. Maybe a descendant is what will handle the click.
+        if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
+            ev.setTargetAccessibilityFocus(false);
+        }
+
         boolean handled = false;
         if (onFilterTouchEventForSecurity(ev)) {
             final int action = ev.getAction();
@@ -2647,6 +2671,13 @@
                 // so this view group continues to intercept touches.
                 intercepted = true;
             }
+
+            // If intercepted, start normal event dispatch. Also if there is already
+            // a view that is handling the gesture, do normal event dispatch.
+            if (intercepted || mFirstTouchTarget != null) {
+                ev.setTargetAccessibilityFocus(false);
+            }
+
             // Check for cancelation.
             final boolean canceled = resetCancelNextUpFlag(this)
                     || actionMasked == MotionEvent.ACTION_CANCEL;
@@ -2658,6 +2689,14 @@
             TouchTarget newTouchTarget = null;
             boolean alreadyDispatchedToNewTouchTarget = false;
             if (!canceled && !intercepted) {
+                // If the event is targeting accessibility focus we give it to the
+                // view that has accessibility focus and if it does not handle it
+                // we clear the flag and dispatch the event to all children as usual.
+                // We are looking up the accessibility focused host to avoid keeping
+                // state since these events are very rare.
+                View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
+                        ? findChildWithAccessibilityFocus() : null;
+
                 if (actionMasked == MotionEvent.ACTION_DOWN
                         || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                         || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
@@ -2720,6 +2759,10 @@
                                 alreadyDispatchedToNewTouchTarget = true;
                                 break;
                             }
+
+                            // The accessibility focus didn't handle the event, so clear
+                            // the flag and do a normal dispatch to all children.
+                            ev.setTargetAccessibilityFocus(false);
                         }
                         if (preorderedList != null) preorderedList.clear();
                     }
@@ -2803,6 +2846,34 @@
         return buildOrderedChildList();
     }
 
+     /**
+     * Finds the child which has accessibility focus.
+     *
+     * @return The child that has focus.
+     */
+    private View findChildWithAccessibilityFocus() {
+        ViewRootImpl viewRoot = getViewRootImpl();
+        if (viewRoot == null) {
+            return null;
+        }
+
+        View current = viewRoot.getAccessibilityFocusedHost();
+        if (current == null) {
+            return null;
+        }
+
+        ViewParent parent = current.getParent();
+        while (parent instanceof View) {
+            if (parent == this) {
+                return current;
+            }
+            current = (View) parent;
+            parent = current.getParent();
+        }
+
+        return null;
+    }
+
     /**
      * Resets all touch state in preparation for a new cycle.
      */
@@ -3257,9 +3328,10 @@
                 break;
             }
             default:
-                throw new IllegalStateException("descendant focusability must be "
-                        + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
-                        + "but is " + descendantFocusability);
+                throw new IllegalStateException(
+                        "descendant focusability must be one of FOCUS_BEFORE_DESCENDANTS,"
+                            + " FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS but is "
+                                + descendantFocusability);
         }
         if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {
             mPrivateFlags |= PFLAG_WANTS_FOCUS;
@@ -4925,7 +4997,8 @@
         if (params == null) {
             params = generateDefaultLayoutParams();
             if (params == null) {
-                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
+                throw new IllegalArgumentException(
+                        "generateDefaultLayoutParams() cannot return null");
             }
         }
         addView(child, index, params);
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 68943bf..32b9cf7 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -73,6 +73,8 @@
     }
 
     /** @hide */
+    @NonNull
+    @TestApi
     public static AutofillId withoutSession(@NonNull AutofillId id) {
         final int flags = id.mFlags & ~FLAG_HAS_SESSION;
         final long virtualChildId =
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 8ca218c1..1b666aa 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -18,17 +18,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.PointF;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.ViewTreeObserver;
 
+import java.lang.ref.WeakReference;
 import java.util.function.Consumer;
 
 /**
@@ -87,8 +92,10 @@
      *
      * @hide
      */
+    @TestApi
     public interface SurfacePackageUpdater {
 
+
         /**
          * Called when the previous surface package is released due to view being detached
          * from the window.
@@ -100,14 +107,16 @@
          *
          * @param consumer consumes the updated surface package.
          */
-        void getSurfacePackage(Consumer<SurfaceControlViewHost.SurfacePackage> consumer);
+        void getSurfacePackage(@NonNull Consumer<SurfaceControlViewHost.SurfacePackage> consumer);
     }
 
     @NonNull
     private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
         @Override
         public void surfaceCreated(@NonNull SurfaceHolder holder) {
-            mSurfaceControlCallback.onCreated(mSurfaceView.getSurfaceControl());
+            final SurfaceControl surfaceControl = mSurfaceView.getSurfaceControl();
+            surfaceControl.addOnReparentListener(mOnReparentListener);
+            mSurfaceControlCallback.onCreated(surfaceControl);
         }
 
         @Override
@@ -118,7 +127,36 @@
 
         @Override
         public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
-            mSurfaceControlCallback.onDestroyed(mSurfaceView.getSurfaceControl());
+            final SurfaceControl surfaceControl = mSurfaceView.getSurfaceControl();
+            surfaceControl.removeOnReparentListener(mOnReparentListener);
+            mSurfaceControlCallback.onDestroyed(surfaceControl);
+        }
+    };
+
+    @NonNull
+    private final SurfaceControl.OnReparentListener mOnReparentListener =
+            new SurfaceControl.OnReparentListener() {
+                @Override
+                public void onReparent(SurfaceControl.Transaction transaction,
+                        SurfaceControl parent) {
+                    final View parentSurfaceOwnerView = (parent != null)
+                            ? parent.getLocalOwnerView() : null;
+                    if (parentSurfaceOwnerView instanceof SurfaceView) {
+                        mParentSurfaceOwnerView = new WeakReference<>(
+                                (SurfaceView) parentSurfaceOwnerView);
+                    } else {
+                        mParentSurfaceOwnerView = null;
+                    }
+                }
+            };
+
+    @NonNull
+    private final ViewTreeObserver.OnDrawListener mOnDrawListener =
+            new ViewTreeObserver.OnDrawListener() {
+        @Override
+        public void onDraw() {
+            computeParentPositionAndScale();
+            mSurfaceView.setVisibility(VISIBLE);
         }
     };
 
@@ -126,21 +164,20 @@
     private final SurfaceView mSurfaceView;
 
     @Nullable
+    private WeakReference<SurfaceView> mParentSurfaceOwnerView;
+
+    @Nullable
+    private int[] mParentPosition;
+
+    @Nullable
+    private PointF mParentScale;
+
+    @Nullable
     private SurfaceControlCallback mSurfaceControlCallback;
 
     @Nullable
     private SurfacePackageUpdater mSurfacePackageUpdater;
 
-    @NonNull
-    private final OnPreDrawListener mDrawListener = new OnPreDrawListener() {
-        @Override
-        public boolean onPreDraw() {
-            int visibility = InlineContentView.this.isShown() ? VISIBLE : GONE;
-            mSurfaceView.setVisibility(visibility);
-            return true;
-        }
-    };
-
     /**
      * @inheritDoc
      * @hide
@@ -164,6 +201,7 @@
     public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
+        mSurfaceView.setEnableSurfaceClipping(true);
     }
 
     /**
@@ -177,6 +215,12 @@
         return mSurfaceView.getSurfaceControl();
     }
 
+    @Override
+    public void setClipBounds(Rect clipBounds) {
+        super.setClipBounds(clipBounds);
+        mSurfaceView.setClipBounds(clipBounds);
+    }
+
     /**
      * @inheritDoc
      * @hide
@@ -184,10 +228,33 @@
     public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mSurfaceView = new SurfaceView(context, attrs, defStyleAttr, defStyleRes);
+        mSurfaceView = new SurfaceView(context, attrs, defStyleAttr, defStyleRes) {
+            @Override
+            protected void onSetSurfacePositionAndScaleRT(
+                    @NonNull SurfaceControl.Transaction transaction,
+                    @NonNull SurfaceControl surface, int positionLeft, int positionTop,
+                    float postScaleX, float postScaleY) {
+                // If we have a parent position, we need to make our coordinates relative
+                // to the parent in the rendering space.
+                if (mParentPosition != null) {
+                    positionLeft = (int) ((positionLeft - mParentPosition[0]) / mParentScale.x);
+                    positionTop = (int) ((positionTop - mParentPosition[1]) / mParentScale.y);
+                }
+
+                // Any scaling done to the parent or its predecessors would be applied
+                // via the surfaces parent -> child relation, so we only propagate any
+                // scaling set on the InlineContentView itself.
+                postScaleX = InlineContentView.this.getScaleX();
+                postScaleY = InlineContentView.this.getScaleY();
+
+                super.onSetSurfacePositionAndScaleRT(transaction, surface, positionLeft,
+                        positionTop, postScaleX, postScaleY);
+            }
+        };
         mSurfaceView.setZOrderOnTop(true);
         mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
         addView(mSurfaceView);
+        setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
     }
 
     /**
@@ -195,6 +262,7 @@
      *
      * @hide
      */
+    @TestApi
     public void setChildSurfacePackageUpdater(
             @Nullable SurfacePackageUpdater surfacePackageUpdater) {
         mSurfacePackageUpdater = surfacePackageUpdater;
@@ -213,8 +281,9 @@
                         }
                     });
         }
-        mSurfaceView.setVisibility(VISIBLE);
-        getViewTreeObserver().addOnPreDrawListener(mDrawListener);
+
+        mSurfaceView.setVisibility(getVisibility());
+        getViewTreeObserver().addOnDrawListener(mOnDrawListener);
     }
 
     @Override
@@ -224,7 +293,9 @@
         if (mSurfacePackageUpdater != null) {
             mSurfacePackageUpdater.onSurfacePackageReleased();
         }
-        getViewTreeObserver().removeOnPreDrawListener(mDrawListener);
+
+        getViewTreeObserver().removeOnDrawListener(mOnDrawListener);
+        mSurfaceView.setVisibility(View.GONE);
     }
 
     @Override
@@ -271,4 +342,67 @@
     public boolean setZOrderedOnTop(boolean onTop) {
         return mSurfaceView.setZOrderedOnTop(onTop, /*allowDynamicChange*/ true);
     }
+
+
+    private void computeParentPositionAndScale() {
+        boolean contentPositionOrScaleChanged = false;
+
+        // This method can be called on the UI or render thread but for the cases
+        // it is called these threads are not running concurrently, so no need to lock.
+        final SurfaceView parentSurfaceOwnerView = (mParentSurfaceOwnerView != null)
+                ? mParentSurfaceOwnerView.get() : null;
+
+        if (parentSurfaceOwnerView != null) {
+            if (mParentPosition == null) {
+                mParentPosition = new int[2];
+            }
+            final int oldParentPositionX = mParentPosition[0];
+            final int oldParentPositionY = mParentPosition[1];
+            parentSurfaceOwnerView.getLocationInSurface(mParentPosition);
+            if (oldParentPositionX != mParentPosition[0]
+                    || oldParentPositionY != mParentPosition[1]) {
+                contentPositionOrScaleChanged = true;
+            }
+
+            if (mParentScale == null) {
+                mParentScale = new PointF();
+            }
+
+            final float lastParentSurfaceWidth = parentSurfaceOwnerView
+                    .getSurfaceRenderPosition().width();
+            final float oldParentScaleX = mParentScale.x;
+            if (lastParentSurfaceWidth > 0) {
+                mParentScale.x = lastParentSurfaceWidth /
+                        (float) parentSurfaceOwnerView.getWidth();
+            } else {
+                mParentScale.x = 1.0f;
+            }
+            if (!contentPositionOrScaleChanged
+                    && Float.compare(oldParentScaleX, mParentScale.x) != 0) {
+                contentPositionOrScaleChanged = true;
+            }
+
+            final float lastParentSurfaceHeight = parentSurfaceOwnerView
+                    .getSurfaceRenderPosition().height();
+            final float oldParentScaleY = mParentScale.y;
+            if (lastParentSurfaceHeight > 0) {
+                mParentScale.y = lastParentSurfaceHeight
+                        / (float) parentSurfaceOwnerView.getHeight();
+            } else {
+                mParentScale.y = 1.0f;
+            }
+            if (!contentPositionOrScaleChanged
+                    && Float.compare(oldParentScaleY, mParentScale.y) != 0) {
+                contentPositionOrScaleChanged = true;
+            }
+        } else if (mParentPosition != null || mParentScale != null) {
+            contentPositionOrScaleChanged = true;
+            mParentPosition = null;
+            mParentScale = null;
+        }
+
+        if (contentPositionOrScaleChanged) {
+            mSurfaceView.requestUpdateSurfacePositionAndScale();
+        }
+    }
 }
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 79397b8..4b968b4 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -46,7 +46,8 @@
         SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE,
         SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME,
         SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED,
-        SoftInputShowHideReason.HIDE_RECENTS_ANIMATION})
+        SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
+        SoftInputShowHideReason.HIDE_BUBBLES})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -140,4 +141,10 @@
      * intercept touch from app window.
      */
     int HIDE_RECENTS_ANIMATION = 18;
+
+    /**
+     * Hide soft input when {@link com.android.systemui.bubbles.BubbleController} is expanding,
+     * switching, or collapsing Bubbles.
+     */
+    int HIDE_BUBBLES = 19;
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index c320824..4999ec0 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -79,6 +79,7 @@
     void onNotificationSettingsViewed(String key);
     void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
     void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed);
+    void hideCurrentInputMethodForBubbles();
     void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
     void clearInlineReplyUriPermissions(String key);
 
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 139185f..82e99e6 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -139,7 +139,7 @@
                 >
                     <TextView
                         android:id="@+id/conversation_text"
-                        android:layout_width="wrap_content"
+                        android:layout_width="0dp"
                         android:layout_height="wrap_content"
                         android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
                         android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f20470f5..5c10188 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1981,9 +1981,9 @@
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"توسيع"</string>
     <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"تصغير"</string>
     <string name="expand_action_accessibility" msgid="1947657036871746627">"تبديل التوسيع"</string>
-    <string name="usb_midi_peripheral_name" msgid="490523464968655741">"‏منفذ الأجهزة الطرفية المزودة بكابل USB ونظام التشغيل Android"</string>
+    <string name="usb_midi_peripheral_name" msgid="490523464968655741">"‏منفذ الأجهزة الملحقة المزودة بكابل USB ونظام التشغيل Android"</string>
     <string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"Android"</string>
-    <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"‏منفذ الأجهزة الطرفية المزودة بكابل USB"</string>
+    <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"‏منفذ الأجهزة الملحقة المزودة بكابل USB"</string>
     <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"خيارات أخرى"</string>
     <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"إغلاق التجاوز"</string>
     <string name="maximize_button_text" msgid="4258922519914732645">"تكبير"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 60931a6..99d7d86 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -308,7 +308,7 @@
     <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Физическа активност"</string>
     <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"достъп до физическата ви активност"</string>
     <string name="permgrouplab_camera" msgid="9090413408963547706">"Камера"</string>
-    <string name="permgroupdesc_camera" msgid="7585150538459320326">"да прави снимки и записва видеоклипове"</string>
+    <string name="permgroupdesc_camera" msgid="7585150538459320326">"да прави снимки и записва видео"</string>
     <string name="permgrouplab_calllog" msgid="7926834372073550288">"Списъци с обажданията"</string>
     <string name="permgroupdesc_calllog" msgid="2026996642917801803">"четене и запис на списъка с телефонните обаждания"</string>
     <string name="permgrouplab_phone" msgid="570318944091926620">"Телефон"</string>
@@ -436,9 +436,9 @@
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"разпознаване на физическата активност"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Това приложение може да разпознава физическата ви активност."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"правене на снимки и видеоклипове"</string>
-    <string name="permdesc_camera" msgid="1354600178048761499">"Това приложение може по всяко време да прави снимки и да записва видеоклипове посредством камерата."</string>
+    <string name="permdesc_camera" msgid="1354600178048761499">"Това приложение може по всяко време да прави снимки и да записва видео посредством камерата."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"Разрешаване на достъп на приложение или услуга до системните камери с цел правене на снимки и видеоклипове"</string>
-    <string name="permdesc_systemCamera" msgid="5938360914419175986">"Това привилегировано или системно приложение може по всяко време да прави снимки и да записва видеоклипове посредством системна камера. Необходимо е също на приложението да бъде дадено разрешението android.permission.CAMERA"</string>
+    <string name="permdesc_systemCamera" msgid="5938360914419175986">"Това привилегировано или системно приложение може по всяко време да прави снимки и да записва видео посредством системна камера. Необходимо е също на приложението да бъде дадено разрешението android.permission.CAMERA"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Разрешаване на приложение или услуга да получават обратни повиквания за отварянето или затварянето на снимачни устройства."</string>
     <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Това приложение може да получава обратни повиквания, когато снимачно устройство бъде отворено (от кое приложение) или затворено."</string>
     <string name="permlab_vibrate" msgid="8596800035791962017">"контролиране на вибрирането"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 903486e..d560ce9 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -238,7 +238,7 @@
     <string name="global_action_lock" msgid="6949357274257655383">"স্ক্রীণ লক"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"পাওয়ার বন্ধ করুন"</string>
     <string name="global_action_power_options" msgid="1185286119330160073">"ফোন বন্ধ করুন"</string>
-    <string name="global_action_restart" msgid="4678451019561687074">"ফোন আবার চালু করুন"</string>
+    <string name="global_action_restart" msgid="4678451019561687074">"ফোন রিস্টার্ট করুন"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"জরুরী"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"ত্রুটির প্রতিবেদন"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"সেশন শেষ করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 5da4183..a4c1ba4 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1645,7 +1645,7 @@
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritiskom i držanjem oba dugmeta za jačinu zvuka u trajanju od 3 sekunde pokrenut će se funkcija pristupačnosti."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"Uključiti funkcije pristupačnosti?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkcije pristupačnosti. Ovo može uticati na način rada uređaja.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane funkcije možete izmijeniti u odjeljku Postavke &gt; Pristupačnost."</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkcije pristupačnosti. Ovo može uticati na način rada uređaja.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane funkcije možete promijeniti u odjeljku Postavke &gt; Pristupačnost."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"Uključiti <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkciju pristupačnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Ovo može promijeniti način rada uređaja.\n\nOvu prečicu možete zamijeniti drugom funkcijom u odjeljku Postavke &gt; Pristupačnost."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index ee23378..0a5907e 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -237,7 +237,7 @@
     <string name="global_actions" product="default" msgid="6410072189971495460">"Opcions del telèfon"</string>
     <string name="global_action_lock" msgid="6949357274257655383">"Bloqueig de pantalla"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Apaga"</string>
-    <string name="global_action_power_options" msgid="1185286119330160073">"Engegada"</string>
+    <string name="global_action_power_options" msgid="1185286119330160073">"Engega"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Reinicia"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Emergència"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Informe d\'error"</string>
@@ -264,7 +264,7 @@
     <string name="global_action_settings" msgid="4671878836947494217">"Configuració"</string>
     <string name="global_action_assist" msgid="2517047220311505805">"Assistència"</string>
     <string name="global_action_voice_assist" msgid="6655788068555086695">"Assist. per veu"</string>
-    <string name="global_action_lockdown" msgid="2475471405907902963">"Bloq. de seguretat"</string>
+    <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueig de seguretat"</string>
     <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"+999"</string>
     <string name="notification_hidden_text" msgid="2835519769868187223">"Notificació nova"</string>
     <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclat virtual"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 3b7a6ed..3ce5723 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1695,7 +1695,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Převrácení barev"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Oprava barev"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Určete, jakou funkci aktivujete klepnutím na tlačítko přístupnosti:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Určete, jakou funkci aktivujete pomocí gesta přístupnosti (přejetí dvěma prsty ze spodní části obrazovky nahoru):"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 779fdff..551325d 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -316,7 +316,7 @@
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Body sensors"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"access sensor data about your vital signs"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Retrieve window content"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window that you\'re interacting with."</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window you\'re interacting with."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Turn on Explore by Touch"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Tapped items will be spoken aloud and the screen can be explored using gestures."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Observe text that you type"</string>
@@ -1794,7 +1794,7 @@
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
     <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'"</string>
-    <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
+    <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -1912,7 +1912,7 @@
     <string name="conference_call" msgid="5731633152336490471">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="7863719020269945722">"Tooltip"</string>
     <string name="app_category_game" msgid="4534216074910244790">"Games"</string>
-    <string name="app_category_audio" msgid="8296029904794676222">"Music &amp; Audio"</string>
+    <string name="app_category_audio" msgid="8296029904794676222">"Music and audio"</string>
     <string name="app_category_video" msgid="2590183854839565814">"Movies &amp; Video"</string>
     <string name="app_category_image" msgid="7307840291864213007">"Photos &amp; Images"</string>
     <string name="app_category_social" msgid="2278269325488344054">"Social &amp; Communication"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 2ec2805..4d3ca94b 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -316,10 +316,10 @@
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Body sensors"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"access sensor data about your vital signs"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Retrieve window content"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window that you\'re interacting with."</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window you\'re interacting with."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Turn on Explore by Touch"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Tapped items will be spoken aloud and the screen can be explored using gestures."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Observe text that you type"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Observe text you type"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Includes personal data such as credit card numbers and passwords."</string>
     <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Control display magnification"</string>
     <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Control the display\'s zoom level and positioning."</string>
@@ -682,7 +682,7 @@
     <string name="policydesc_resetPassword" msgid="4626419138439341851">"Change the screen lock."</string>
     <string name="policylab_forceLock" msgid="7360335502968476434">"Lock the screen"</string>
     <string name="policydesc_forceLock" msgid="1008844760853899693">"Control how and when the screen locks."</string>
-    <string name="policylab_wipeData" msgid="1359485247727537311">"Delete all data"</string>
+    <string name="policylab_wipeData" msgid="1359485247727537311">"Erase all data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Erase the tablet\'s data without warning by performing a factory data reset."</string>
     <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Delete your Android TV device\'s data without warning by performing a factory data reset."</string>
     <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Erase the phone\'s data without warning by performing a factory data reset."</string>
@@ -1648,7 +1648,7 @@
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Done"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string>
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
-    <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
+    <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour inversion"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
@@ -1792,9 +1792,9 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
-    <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'"</string>
-    <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like \"Hey Google\"\n\n"<annotation id="url">"Learn more"</annotation></string>
+    <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like \"Hey Google\""</string>
+    <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don\'t display until you tap them."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -1912,7 +1912,7 @@
     <string name="conference_call" msgid="5731633152336490471">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="7863719020269945722">"Tooltip"</string>
     <string name="app_category_game" msgid="4534216074910244790">"Games"</string>
-    <string name="app_category_audio" msgid="8296029904794676222">"Music &amp; Audio"</string>
+    <string name="app_category_audio" msgid="8296029904794676222">"Music and audio"</string>
     <string name="app_category_video" msgid="2590183854839565814">"Movies &amp; Video"</string>
     <string name="app_category_image" msgid="7307840291864213007">"Photos &amp; Images"</string>
     <string name="app_category_social" msgid="2278269325488344054">"Social &amp; Communication"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 779fdff..c290d9e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -316,7 +316,7 @@
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Body sensors"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"access sensor data about your vital signs"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Retrieve window content"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window that you\'re interacting with."</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window you\'re interacting with."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Turn on Explore by Touch"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Tapped items will be spoken aloud and the screen can be explored using gestures."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Observe text that you type"</string>
@@ -1006,7 +1006,7 @@
     <string name="hour" msgid="7796325297097314653">"hour"</string>
     <string name="hours" msgid="8517014849629200683">"hours"</string>
     <string name="minute" msgid="8369209540986467610">"min"</string>
-    <string name="minutes" msgid="3456532942641808971">"mins"</string>
+    <string name="minutes" msgid="3456532942641808971">"Min."</string>
     <string name="second" msgid="9210875257112211713">"sec"</string>
     <string name="seconds" msgid="2175052687727971048">"secs"</string>
     <string name="week" msgid="907127093960923779">"week"</string>
@@ -1649,7 +1649,7 @@
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string>
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
-    <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
+    <string name="color_correction_feature_name" msgid="3655077237805422597">"Color correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1912,7 +1912,7 @@
     <string name="conference_call" msgid="5731633152336490471">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="7863719020269945722">"Tooltip"</string>
     <string name="app_category_game" msgid="4534216074910244790">"Games"</string>
-    <string name="app_category_audio" msgid="8296029904794676222">"Music &amp; Audio"</string>
+    <string name="app_category_audio" msgid="8296029904794676222">"Music and audio"</string>
     <string name="app_category_video" msgid="2590183854839565814">"Movies &amp; Video"</string>
     <string name="app_category_image" msgid="7307840291864213007">"Photos &amp; Images"</string>
     <string name="app_category_social" msgid="2278269325488344054">"Social &amp; Communication"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index e4fe179..c26cc66 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1307,7 +1307,7 @@
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Audio-osagarri analogiko bat hauteman da"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Erantsitako gailua ez da telefono honekin bateragarria. Sakatu informazio gehiago lortzeko."</string>
     <string name="adb_active_notification_title" msgid="408390247354560331">"USB bidezko arazketa konektatuta"</string>
-    <string name="adb_active_notification_message" msgid="5617264033476778211">"Sakatu USB bidezko arazketa desaktibatzeko"</string>
+    <string name="adb_active_notification_message" msgid="5617264033476778211">"Sakatu hau USB bidezko arazketa desaktibatzeko"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Hautatu USB bidezko arazketa desgaitzeko."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Hari gabeko arazketa konektatuta dago"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Sakatu hau hari gabeko arazketa desaktibatzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 2cd3dbd..c1d0ae6 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -514,8 +514,8 @@
     <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"‏به برنامه اجازه می‎دهد تا پیکربندی بلوتوث در رایانهٔ لوحی را مشاهده کند و اتصال با دستگاه‌های مرتبط را برقرار کرده و بپذیرد."</string>
     <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"‏به برنامه اجازه می‌دهد پیکربندی بلوتوث را در دستگاه Android TV شما ببیند، و اتصالات با دستگاه‌های مرتبط‌شده را بپذیرد یا این اتصالات را برقرار کند."</string>
     <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"‏به برنامه اجازه می‎دهد تا پیکربندی بلوتوث در تلفن را مشاهده کند، و اتصالات دستگاه‌های مرتبط را برقرار کرده و بپذیرد."</string>
-    <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"‏اطلاعات ترجیحی سرویس پولی NFC"</string>
-    <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"‏به برنامه اجازه می‌دهد اطلاعات ترجیحی «سرویس پولی NFC»، مانند کمک‌های ثبت‌شده و مقصد مسیر را دریافت کند."</string>
+    <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"‏اطلاعات ترجیحی سرویس پولی «ارتباط میدان نزدیک» (NFC)"</string>
+    <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"‏به برنامه اجازه می‌دهد اطلاعات ترجیحی سرویس پولی «ارتباط میدان نزدیک» (NFC)، مانند کمک‌های ثبت‌شده و مقصد مسیر را دریافت کند."</string>
     <string name="permlab_nfc" msgid="1904455246837674977">"کنترل ارتباط راه نزدیک"</string>
     <string name="permdesc_nfc" msgid="8352737680695296741">"‏به برنامه اجازه می‎دهد تا با تگ‌های «ارتباط میدان نزدیک» (NFC)، کارت‌ها و فایل‌خوان ارتباط برقرار کند."</string>
     <string name="permlab_disableKeyguard" msgid="3605253559020928505">"غیرفعال کردن قفل صفحه شما"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 6fa6fbf..6aab2c3 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -238,7 +238,7 @@
     <string name="global_action_lock" msgid="6949357274257655383">"Näytön lukitus"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Katkaise virta"</string>
     <string name="global_action_power_options" msgid="1185286119330160073">"Virta"</string>
-    <string name="global_action_restart" msgid="4678451019561687074">"Uudelleenkäynnistys"</string>
+    <string name="global_action_restart" msgid="4678451019561687074">"Käynnistä uudelleen"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Hätäpuhelu"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Virheraportti"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"Lopeta käyttökerta"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 70f403c..2b42c12 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1651,7 +1651,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Choisissez une fonctionnalité à utiliser lorsque vous touchez le bouton d\'accessibilité :"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Choisissez une fonctionnalité à utiliser lorsque vous utilisez le geste d\'accessibilité (balayer l\'écran de bas en haut avec deux doigts) :"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 0b3a6af..08a8488 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -200,9 +200,9 @@
     <string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string>
     <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string>
     <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
-    <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activez profil professionnel"</string>
-    <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applications personnelles sont bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string>
-    <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Les applications personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à désactiver votre profil professionnel pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
+    <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activez votre profil pro"</string>
+    <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applications personnelles seront bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string>
+    <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Vos applications personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à désactiver votre profil professionnel pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
     <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activer"</string>
     <string name="me" msgid="6207584824693813140">"Moi"</string>
     <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 7e488376..5076aa9 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -239,7 +239,7 @@
     <string name="global_actions" product="default" msgid="6410072189971495460">"Opcije telefona"</string>
     <string name="global_action_lock" msgid="6949357274257655383">"Zaključavanje zaslona"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Isključi"</string>
-    <string name="global_action_power_options" msgid="1185286119330160073">"Napajanje"</string>
+    <string name="global_action_power_options" msgid="1185286119330160073">"Uključi"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Ponovo pokreni"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Hitne službe"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Izvješće o bugovima"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 06f50d5..e5e23f6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -237,7 +237,7 @@
     <string name="global_actions" product="default" msgid="6410072189971495460">"Valkostir síma"</string>
     <string name="global_action_lock" msgid="6949357274257655383">"Skjálás"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Slökkva"</string>
-    <string name="global_action_power_options" msgid="1185286119330160073">"Orka"</string>
+    <string name="global_action_power_options" msgid="1185286119330160073">"Slökkva/endurræsa"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Endurræsa"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Neyðarsímtal"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Villutilkynning"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 5b6b5fe..de4de72 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -201,7 +201,7 @@
     <string name="factory_reset_message" msgid="2657049595153992213">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string>
     <string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
     <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Attiva il profilo di lavoro"</string>
-    <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Le tue app personali sono bloccate fino all\'attivazione del tuo profilo di lavoro"</string>
+    <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Le tue app personali saranno bloccate finché non attivi il tuo profilo di lavoro."</string>
     <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Le app personali verranno bloccate il giorno <xliff:g id="DATE">%1$s</xliff:g> alle ore <xliff:g id="TIME">%2$s</xliff:g>. L\'amministratore IT non consente di mantenere disattivato il profilo di lavoro per più di <xliff:g id="NUMBER">%3$d</xliff:g> giorni."</string>
     <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Attiva"</string>
     <string name="me" msgid="6207584824693813140">"Io"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 72cf78f..2f89ba3 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1651,7 +1651,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"ಬಣ್ಣ ವಿಲೋಮ"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಲಾಗಿದೆ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್‌ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"ನೀವು ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಟ್ಯಾಪ್ ಮಾಡಿದಾಗ ಬಳಸುವುದಕ್ಕಾಗಿ ವೈಶಿಷ್ಟ್ಯವೊಂದನ್ನು ಆರಿಸಿ:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"ಪ್ರವೇಶಿಸುವಿಕೆ ಗೆಸ್ಚರ್‌ನೊಂದಿಗೆ ಬಳಸಲು ವೈಶಿಷ್ಟ್ಯವೊಂದನ್ನು ಆಯ್ಕೆಮಾಡಿ (ಎರಡು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಪರದೆಯ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ):"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index f8c92f4..f382ee9 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -243,7 +243,7 @@
     <string name="global_action_bug_report" msgid="5127867163044170003">"Извештај за грешка"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"Завршете ја сесијата"</string>
     <string name="global_action_screenshot" msgid="2610053466156478564">"Слика од екранот"</string>
-    <string name="bugreport_title" msgid="8549990811777373050">"Извештај за грешка"</string>
+    <string name="bugreport_title" msgid="8549990811777373050">"Извештај за грешки"</string>
     <string name="bugreport_message" msgid="5212529146119624326">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
     <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактивен извештај"</string>
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Користете го ова во повеќето ситуации. Ви дозволува да го следите напредокот на извештајот, да внесете повеќе детали во врска со проблемот и да сликате слики од екранот. Може да испушти некои помалку користени делови за коишто е потребно долго време за да се пријават."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 496ba21..65b80d5 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -224,7 +224,7 @@
     <string name="reboot_to_reset_message" msgid="3347690497972074356">"പുനരാരംഭിക്കുന്നു…"</string>
     <string name="shutdown_progress" msgid="5017145516412657345">"ഷട്ട്‌ഡൗൺ ചെയ്യുന്നു..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"നിങ്ങളുടെ ടാബ്‌ലെറ്റ് ഷട്ട്‌ഡൗൺ ചെയ്യും."</string>
-    <string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"നിങ്ങളുടെ Android ടിവി ഓഫാകും."</string>
+    <string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"നിങ്ങളുടെ Android TV ഓഫാകും."</string>
     <string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"നിങ്ങളുടെ വാച്ച് ഷട്ട്ഡൗൺ ചെയ്യും."</string>
     <string name="shutdown_confirm" product="default" msgid="136816458966692315">"നിങ്ങളുടെ ഫോൺ ഷട്ട്‌ഡൗൺ ചെയ്യും."</string>
     <string name="shutdown_confirm_question" msgid="796151167261608447">"നിങ്ങൾക്ക് ഷട്ട് ഡൗൺ ചെയ്യണോ?"</string>
@@ -357,7 +357,7 @@
     <string name="permdesc_sendSms" msgid="6757089798435130769">"SMS സന്ദേശങ്ങൾ അയയ്‌ക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് അപ്രതീക്ഷിത നിരക്കുകൾക്കിടയാക്കാം. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ സന്ദേശങ്ങൾ അയയ്‌ക്കുന്നത് പണച്ചെലവിനിടയാക്കാം."</string>
     <string name="permlab_readSms" msgid="5164176626258800297">"നിങ്ങളുടെ വാചക സന്ദേശങ്ങൾ വായിക്കുക (SMS അല്ലെങ്കിൽ MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ഈ ആപ്പിന് നിങ്ങളുടെ ടാബ്‌ലെറ്റിൽ സംഭരിച്ചിരിക്കുന്ന എല്ലാ SMS (വാചക) സന്ദേശങ്ങളും വായിക്കാൻ കഴിയും."</string>
-    <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"നിങ്ങളുടെ Android ടിവിയിൽ സംഭരിച്ചിരിക്കുന്ന എല്ലാ SMS (ടെക്‌സ്‌റ്റ്) സന്ദേശങ്ങളും വായിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
+    <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"നിങ്ങളുടെ Android TV-യിൽ സംഭരിച്ചിരിക്കുന്ന എല്ലാ SMS (ടെക്‌സ്‌റ്റ്) സന്ദേശങ്ങളും വായിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="permdesc_readSms" product="default" msgid="774753371111699782">"ഈ ആപ്പിന് നിങ്ങളുടെ ഫോണിൽ സംഭരിച്ചിരിക്കുന്ന എല്ലാ SMS (വാചക) സന്ദേശങ്ങളും വായിക്കാൻ കഴിയും."</string>
     <string name="permlab_receiveWapPush" msgid="4223747702856929056">"വാചക സന്ദേശം നേടുക (WAP)"</string>
     <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP സന്ദേശങ്ങൾ നേടാനും പ്രോസസ്സുചെയ്യാനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങൾക്ക് അയയ്‌ക്കുന്ന സന്ദേശങ്ങൾ നിങ്ങൾക്ക് ദൃശ്യമാക്കാതെ തന്നെ നിരീക്ഷിക്കാനോ ഇല്ലാതാക്കാനോ ഉള്ള കഴിവ് ഈ അനുമതികളിൽ ഉൾപ്പെടുന്നു."</string>
@@ -379,7 +379,7 @@
     <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"ഈ ആപ്പിന് പശ്ചാത്തലത്തിൽ ഡാറ്റ ഉപയോഗിക്കാൻ കഴിയും. ഇത് ഡാറ്റ ഉപയോഗം വർദ്ധിപ്പിച്ചേക്കാം."</string>
     <string name="permlab_persistentActivity" msgid="464970041740567970">"അപ്ലിക്കേഷൻ എപ്പോഴും പ്രവർത്തിക്കുന്നതാക്കുക"</string>
     <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"മെമ്മറിയിൽ അപ്ലിക്കേഷനുകളുടെ ഭാഗങ്ങൾ നിലനിർത്താൻ സ്വയം അനുവദിക്കുന്നു. ഇത് ടാബ്‌ലെറ്റിനെ മന്ദഗതിയിലാക്കുന്ന വിധത്തിൽ മറ്റ് അപ്ലിക്കേഷനുകൾക്ക് ലഭ്യമായ മെമ്മറി പരിമിതപ്പെടുത്താനിടയുണ്ട്."</string>
-    <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"ആപ്പിന്റെ ഭാഗങ്ങളെ മെമ്മറിയിൽ സ്ഥിരമായി നിലനിർത്താൻ അതിനെ അനുവദിക്കുന്നു. ഇത് മറ്റ് ആപ്പുകൾക്ക് ലഭ്യമായ മെമ്മറി പരിമിതപ്പെടുത്തുകയും Android ടിവിയുടെ വേഗത കുറയ്‌ക്കുകയും ചെയ്യും."</string>
+    <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"ആപ്പിന്റെ ഭാഗങ്ങളെ മെമ്മറിയിൽ സ്ഥിരമായി നിലനിർത്താൻ അതിനെ അനുവദിക്കുന്നു. ഇത് മറ്റ് ആപ്പുകൾക്ക് ലഭ്യമായ മെമ്മറി പരിമിതപ്പെടുത്തുകയും Android TV-യുടെ വേഗത കുറയ്‌ക്കുകയും ചെയ്യും."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"മെമ്മറിയിൽ അപ്ലിക്കേഷനുകളുടെ ഭാഗങ്ങൾ നിലനിർത്താൻ സ്വയം അനുവദിക്കുന്നു. ഇത് ഫോണിനെ മന്ദഗതിയിലാക്കുന്ന വിധത്തിൽ മറ്റ് അപ്ലിക്കേഷനുകൾക്ക് ലഭ്യമായ മെമ്മറി പരിമിതപ്പെടുത്താനിടയുണ്ട്."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"മുൻവശത്തുള്ള സേവനം റൺ ചെയ്യുക"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"മുൻവശത്തുള്ള സേവനങ്ങൾ ഉപയോഗിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
@@ -389,7 +389,7 @@
     <string name="permdesc_writeSettings" msgid="8293047411196067188">"സിസ്‌‌റ്റത്തിന്റെ സുരക്ഷ ക്രമീകരണങ്ങളുടെ ഡാറ്റ പരിഷ്‌ക്കരിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ദോഷകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സി‌സ്റ്റത്തിന്റെ കോൺഫിഗറേഷനെ കേടാക്കിയേക്കാം."</string>
     <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"സ്റ്റാർട്ടപ്പിൽ പ്രവർത്തിക്കുക"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"സിസ്‌റ്റം ബൂട്ടുചെയ്യുന്നത് പൂർത്തിയാകുമ്പോൾ തന്നെ സ്വയം ആരംഭിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് ടാബ്‌ലെറ്റ് അരംഭിക്കുന്നതിന് കൂടുതൽ ദൈർഘ്യമെടുക്കുന്നതിന് കാരണമാകാം ഒപ്പം പ്രവർത്തിക്കുമ്പോഴെല്ലാം ടാബ്‌ലെറ്റിന്റെ മൊത്തത്തിലുള്ള വേഗത കുറയ്ക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കും."</string>
-    <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"സിസ്‌റ്റം ബൂട്ട് ചെയ്യൽ പൂർത്തിയായിക്കഴിഞ്ഞ് ഉടൻ സ്വയം ആരംഭിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. ഇതിന് നിങ്ങളുടെ Android ടിവി ആരംഭിക്കുന്നതിന്റെ വേഗത കുറയ്‌ക്കാനും എപ്പോഴും പ്രവർത്തിക്കാൻ ആപ്പിനെ അനുവദിച്ചുകൊണ്ട് മൊത്തത്തിൽ ഉപകരണത്തിന്റെ വേഗത കുറയ്‌ക്കാനും കഴിയും."</string>
+    <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"സിസ്‌റ്റം ബൂട്ട് ചെയ്യൽ പൂർത്തിയായിക്കഴിഞ്ഞ് ഉടൻ സ്വയം ആരംഭിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. ഇതിന് നിങ്ങളുടെ Android TV ആരംഭിക്കുന്നതിന്റെ വേഗത കുറയ്‌ക്കാനും എപ്പോഴും പ്രവർത്തിക്കാൻ ആപ്പിനെ അനുവദിച്ചുകൊണ്ട് മൊത്തത്തിൽ ഉപകരണത്തിന്റെ വേഗത കുറയ്‌ക്കാനും കഴിയും."</string>
     <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"സിസ്‌റ്റം ബൂട്ടുചെയ്യുന്നത് പൂർത്തിയാകുമ്പോൾ തന്നെ സ്വയം ആരംഭിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് ഫോൺ ആരംഭിക്കുന്നതിന് കൂടുതൽ ദൈർഘ്യമെടുക്കാം ഒപ്പം പ്രവർത്തിക്കുമ്പോഴെല്ലാം മൊത്തം ഫോണിന്റെ മൊത്തത്തിലുള്ള വേഗത കുറയ്ക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കും."</string>
     <string name="permlab_broadcastSticky" msgid="4552241916400572230">"സ്റ്റിക്കി പ്രക്ഷേപണം അയ‌യ്‌ക്കുക"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"സ്റ്റിക്കി പ്രക്ഷേപണങ്ങൾ അയയ്‌ക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു, പ്രക്ഷേപണം അവസാനിച്ചതിനുശേഷവും അത് നിലനിൽക്കുന്നു. അമിതോപയോഗം വളരെയധികം മെമ്മറി ഉപയോഗിക്കുന്നതിനാൽ, അത് ടാബ്‌ലെറ്റിന്റെ പ്രവർത്തനത്തെ മന്ദഗതിയിലാക്കുകയോ അസ്ഥിരമാക്കുകയോ ചെയ്യാം."</string>
@@ -397,11 +397,11 @@
     <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"സ്റ്റിക്കി പ്രക്ഷേപണങ്ങൾ അയയ്‌ക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു, പ്രക്ഷേപണം അവസാനിച്ചതിനുശേഷവും അത് നിലനിൽക്കുന്നു. അമിതോപയോഗം വളരെയധികം മെമ്മറി ഉപയോഗിക്കുന്നതിനാൽ, അത് ഫോണിന്റെ പ്രവർത്തനത്തെ മന്ദഗതിയിലാക്കുകയോ അസ്ഥിരമാക്കുകയോ ചെയ്യാം."</string>
     <string name="permlab_readContacts" msgid="8776395111787429099">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ റീഡുചെയ്യുക"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"ടാബ്‌ലെറ്റിൽ സംഭരിച്ച നിങ്ങളുടെ കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ വായിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ ടാബ്‌ലെറ്റിൽ കോണ്ടാക്റ്റുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളിലേക്കുള്ള ആക്സസും ആപ്പുകൾക്ക് ഉണ്ടായിരിക്കും. നിങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്‍ത ആപ്പുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളും ഇതിൽ ഉൾപ്പെട്ടേക്കാം. നിങ്ങളുടെ കോണ്ടാക്റ്റ് ഡാറ്റ സംരക്ഷിക്കാൻ ആപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു, നിങ്ങളുടെ അറിവില്ലാതെ, ദോഷകരമായ ആപ്പുകൾ കോണ്ടാക്റ്റ് ഡാറ്റ പങ്കിടുകയും ചെയ്‌തേക്കാം."</string>
-    <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"നിങ്ങളുടെ Android ടിവിയിൽ സംഭരിച്ച കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ വായിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ Android ടിവിയിൽ കോണ്ടാക്റ്റുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളിലേക്കുള്ള ആക്സസും ആപ്പുകൾക്ക് ഉണ്ടായിരിക്കും. നിങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്‍ത ആപ്പുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളും ഇതിൽ ഉൾപ്പെട്ടേക്കാം. നിങ്ങളുടെ കോണ്ടാക്റ്റ് ഡാറ്റ സംരക്ഷിക്കാൻ ആപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു, നിങ്ങളുടെ അറിവില്ലാതെ, ദോഷകരമായ ആപ്പുകൾ കോണ്ടാക്റ്റ് ഡാറ്റ പങ്കിടുകയും ചെയ്‌തേക്കാം."</string>
+    <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"നിങ്ങളുടെ Android TV-യിൽ സംഭരിച്ച കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ വായിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ Android TV-യിൽ കോണ്ടാക്റ്റുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളിലേക്കുള്ള ആക്സസും ആപ്പുകൾക്ക് ഉണ്ടായിരിക്കും. നിങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്‍ത ആപ്പുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളും ഇതിൽ ഉൾപ്പെട്ടേക്കാം. നിങ്ങളുടെ കോണ്ടാക്റ്റ് ഡാറ്റ സംരക്ഷിക്കാൻ ആപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു, നിങ്ങളുടെ അറിവില്ലാതെ, ദോഷകരമായ ആപ്പുകൾ കോണ്ടാക്റ്റ് ഡാറ്റ പങ്കിടുകയും ചെയ്‌തേക്കാം."</string>
     <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"ഉപകരണത്തിൽ സംഭരിച്ച നിങ്ങളുടെ കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ വായിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ ഫോണിൽ കോണ്ടാക്റ്റുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളിലേക്കുള്ള ആക്സസും ആപ്പുകൾക്ക് ഉണ്ടായിരിക്കും. നിങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്‍ത ആപ്പുകൾ സൃഷ്ടിച്ച അക്കൗണ്ടുകളും ഇതിൽ ഉൾപ്പെട്ടേക്കാം. നിങ്ങളുടെ കോണ്ടാക്റ്റ് ഡാറ്റ സംരക്ഷിക്കാൻ ആപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു, നിങ്ങളുടെ അറിവില്ലാതെ, ദോഷകരമായ ആപ്പുകൾ കോണ്ടാക്റ്റ് ഡാറ്റ പങ്കിടുകയും ചെയ്‌തേക്കാം."</string>
     <string name="permlab_writeContacts" msgid="8919430536404830430">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ പരിഷ്‌ക്കരിക്കുക"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"ടാബ്‌ലെറ്റിൽ സംഭരിച്ച നിങ്ങളുടെ കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ പരിഷ്ക്കരിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. കോൺടാക്റ്റ് ഡാറ്റ ഇല്ലാതാക്കാൻ അപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു."</string>
-    <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"നിങ്ങളുടെ Android ടിവിയിൽ സംഭരിച്ച കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ പരിഷ്‌ക്കരിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. കോൺടാക്റ്റ് ഡാറ്റ ഇല്ലാതാക്കാൻ അപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു."</string>
+    <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"നിങ്ങളുടെ Android TV-യിൽ സംഭരിച്ച കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ പരിഷ്‌ക്കരിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. കോൺടാക്റ്റ് ഡാറ്റ ഇല്ലാതാക്കാൻ അപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു."</string>
     <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"ഫോണിൽ സംഭരിച്ച നിങ്ങളുടെ കോൺടാക്റ്റുകളെക്കുറിച്ചുള്ള ഡാറ്റ പരിഷ്ക്കരിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. കോൺടാക്റ്റ് ഡാറ്റ ഇല്ലാതാക്കാൻ അപ്പുകളെ ഈ അനുമതി അനുവദിക്കുന്നു."</string>
     <string name="permlab_readCallLog" msgid="1739990210293505948">"കോൾ ചരിത്രം റീഡ് ചെയ്യുക"</string>
     <string name="permdesc_readCallLog" msgid="8964770895425873433">"ഈ ആപ്പിന് നിങ്ങളുടെ കോൾ ചരിത്രം വായിക്കാൻ കഴിയും."</string>
@@ -498,11 +498,11 @@
     <string name="permdesc_changeWifiState" msgid="7170350070554505384">"വൈഫൈ ആക്‌സസ്സ് പോയിന്റുകളിലേക്ക് കണക്റ്റുചെയ്യാനും അതിൽ നിന്ന് വിച്ഛേദിക്കാനും വൈഫൈ നെറ്റ്‌വർക്കുകൾക്കായി ഉപകരണ കോൺഫിഗറേഷൻ മാറ്റാനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"വൈഫൈ മൾട്ടികാസ്‌റ്റ് റിസപ്‌ഷൻ അനുവദിക്കുക"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"മൾട്ടികാസ്‌റ്റ് വിലാസങ്ങൾ ഉപയോഗിച്ച് നിങ്ങളുടെ ടബ്‌ലെറ്റിലേക്ക് മാത്രമല്ലാതെ, ഒരു വൈഫൈ നെറ്റ്‌വർക്കിലെ എല്ലാ ഉപകരണങ്ങളിലേക്കും അയച്ച പായ്‌ക്കറ്റുകൾ നേടാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് മൾട്ടികാസ്റ്റ് ഇതര മോഡിനേക്കാൾ അധികം പവർ ഉപയോഗിക്കുന്നു."</string>
-    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"മൾട്ടികാസ്‌റ്റ് വിലാസങ്ങൾ ഉപയോഗിച്ച് നിങ്ങളുടെ Android ടിവിയിലേക്ക് മാത്രമല്ലാതെ ഒരു വൈഫൈ നെറ്റ്‌വർക്കിലെ എല്ലാ ഉപകരണങ്ങളിലേക്കും അയച്ച പാക്കറ്റുകൾ സ്വീകരിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. ഇത് മൾട്ടികാസ്‌റ്റ് ഇതര മോഡിനേക്കാൾ കൂടുതൽ പവർ ഉപയോഗിക്കുന്നു."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"മൾട്ടികാസ്‌റ്റ് വിലാസങ്ങൾ ഉപയോഗിച്ച് നിങ്ങളുടെ Android TV-യിലേക്ക് മാത്രമല്ലാതെ ഒരു വൈഫൈ നെറ്റ്‌വർക്കിലെ എല്ലാ ഉപകരണങ്ങളിലേക്കും അയച്ച പാക്കറ്റുകൾ സ്വീകരിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. ഇത് മൾട്ടികാസ്‌റ്റ് ഇതര മോഡിനേക്കാൾ കൂടുതൽ പവർ ഉപയോഗിക്കുന്നു."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"മൾട്ടികാസ്‌റ്റ് വിലാസങ്ങൾ ഉപയോഗിച്ച് നിങ്ങളുടെ ഫോണിലേക്ക് മാത്രമല്ലാതെ, ഒരു വൈഫൈ നെറ്റ്‌വർക്കിലെ എല്ലാ ഉപകരണങ്ങളിലേക്കും അയച്ച പായ്‌ക്കറ്റുകൾ നേടാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് മൾട്ടികാസ്റ്റ് ഇതര മോഡിനേക്കാൾ അധികം പവർ ഉപയോഗിക്കുന്നു."</string>
     <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"ബ്ലൂടൂത്ത് ക്രമീകരണങ്ങൾ ആക്സസ്സുചെയ്യുക"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"ഒരു പ്രാദേശിക ബ്ലൂടൂത്ത് ടാബ്‌ലെറ്റ് കോൺഫിഗർചെയ്യുന്നതിനും വിദൂര ഉപകരണങ്ങളെ കണ്ടെത്തി ജോടിയാക്കുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
-    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"നിങ്ങളുടെ Android ടിവിയിൽ Bluetooth കോൺഫിഗർ ചെയ്യാനും വിദൂര ഉപകരണങ്ങൾ കണ്ടെത്താനും അവ ജോടിയാക്കാനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
+    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"നിങ്ങളുടെ Android TV-യിൽ Bluetooth കോൺഫിഗർ ചെയ്യാനും വിദൂര ഉപകരണങ്ങൾ കണ്ടെത്താനും അവ ജോടിയാക്കാനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"ഒരു പ്രാദേശിക ബ്ലൂടൂത്ത് ഫോണിനെ കോൺഫിഗർചെയ്യുന്നതിനും വിദൂര ഉപകരണങ്ങളെ കണ്ടെത്തി ജോടിയാക്കുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_accessWimaxState" msgid="7029563339012437434">"WiMAX കണക്റ്റുചെയ്യുക, അതിൽ നിന്നും വിച്ഛേദിക്കുക"</string>
     <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"WiMAX പ്രവർത്തനക്ഷമമാണോയെന്നതും കണക്റ്റുചെയ്‌തിരിക്കുന്ന ഏതെങ്കിലും WiMAX നെറ്റ്‌വർക്കുകളെക്കുറിച്ചുള്ള വിവരങ്ങളും നിർണ്ണയിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
@@ -688,7 +688,7 @@
     <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ഒരു ഫാക്‌ടറി ഡാറ്റ പുനഃസജ്ജീകരണം നടപ്പിലാക്കുന്നതിലൂടെ ഫോണിന്റെ ഡാറ്റ മുന്നറിയിപ്പില്ലാതെ മായ്‌ക്കുക."</string>
     <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"ഉപയോക്തൃ ഡാറ്റ മായ്‌ക്കുക"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"മുന്നറിയിപ്പൊന്നും നൽകാതെ ഈ ടാബ്‌ലെറ്റിലെ ഈ ഉപയോക്താവിന്റെ ഡാറ്റ മായ്‌ക്കുക."</string>
-    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"ഈ Android ടിവിയിലെ ഈ ഉപയോക്തൃ ഡാറ്റ മുന്നറിയിപ്പില്ലാതെ മായ്‌ക്കുക."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"ഈ Android TV-യിലെ ഈ ഉപയോക്തൃ ഡാറ്റ മുന്നറിയിപ്പില്ലാതെ മായ്‌ക്കുക."</string>
     <string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"മുന്നറിയിപ്പൊന്നും നൽകാതെ ഈ ഫോണിലെ ഈ ഉപയോക്താവിന്റെ ഡാറ്റ മായ്‌ക്കുക."</string>
     <string name="policylab_setGlobalProxy" msgid="215332221188670221">"ഉപകരണ ഗ്ലോബൽ പ്രോക്‌സി സജ്ജീകരിക്കുക"</string>
     <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"നയം പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുമ്പോൾ ഉപകരണ ഗ്ലോബൽ പ്രോക്‌സി ഉപയോഗിക്കുന്നത് സജ്ജമാക്കുക. ഉപകരണ ഉടമയ്‌ക്ക് മാത്രമേ ഗ്ലോബൽ പ്രോക്‌സി സജ്ജമാക്കാനാകൂ."</string>
@@ -861,7 +861,7 @@
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"നിങ്ങളുടെ പാസ്‌വേഡ് <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്‌തു. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"നിങ്ങളുടെ പിൻ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്‌തു. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"നിങ്ങളുടെ അൺലോക്കുചെയ്യൽ പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> തെറ്റായ ശ്രമങ്ങൾക്കുശേഷം, Google സൈൻ ഇൻ ചെയ്യൽ ഉപയോഗിച്ച് നിങ്ങളുടെ ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യുന്നതിന് ആവശ്യപ്പടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ Google സൈൻ ഇൻ ഉപയോഗിച്ച് നിങ്ങളുടെ Android ടിവി അൺലോക്ക് ചെയ്യാൻ ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിന് ശേഷം വീണ്ടും ശ്രമിക്കുക."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ Google സൈൻ ഇൻ ഉപയോഗിച്ച് നിങ്ങളുടെ Android TV അൺലോക്ക് ചെയ്യാൻ ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിന് ശേഷം വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"നിങ്ങൾ അൺലോക്കുചെയ്യൽ പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> തെറ്റായ ശ്രമങ്ങൾക്കുശേഷം, Google സൈൻ ഇൻ ചെയ്യൽ ഉപയോഗിച്ച് നിങ്ങളുടെ ഫോൺ അൺലോക്കുചെയ്യുന്നതിന് ആവശ്യപ്പടും. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"നിങ്ങൾ ഫോൺ അൺലോക്കുചെയ്യാൻ തവണ <xliff:g id="NUMBER_0">%1$d</xliff:g> തെറ്റായി ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ടാബ്‌ലെറ്റ് ഫാക്‌ടറി സ്ഥിരമായതിലേക്ക് പുനഃസജ്ജികരിക്കുകയും ഉപയോക്തൃ ഡാറ്റയെല്ലാം നഷ്‌ടപ്പെടുകയും ചെയ്യും."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി Android TV അൺലോക്ക് ചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, നിങ്ങളുടെ Android TV ഫാക്‌ടറി ഡിഫോൾട്ടിലേക്ക് റീസെറ്റ് ചെയ്യപ്പെടുകയും എല്ലാ ഉപയോക്തൃ ഡാറ്റയും നഷ്‌ടപ്പെടുകയും ചെയ്യും."</string>
@@ -1609,7 +1609,7 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"നിങ്ങളുടെ പാസ്‌വേഡ് <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്‌തു. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"നിങ്ങളുടെ പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"നിങ്ങൾ ഫോൺ അൺലോക്കുചെയ്യാൻ തവണ <xliff:g id="NUMBER_0">%1$d</xliff:g> തെറ്റായി ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ടാബ്‌ലെറ്റ് ഫാക്‌ടറി ഡിഫോൾട്ടിലേക്ക് പുനഃസജ്ജികരിക്കുകയും ഉപയോക്തൃ ഡാറ്റയെല്ലാം നഷ്‌ടപ്പെടുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി Android ടിവി അൺലോക്ക് ചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, നിങ്ങളുടെ Android ടിവി ഫാക്‌ടറി ഡിഫോൾട്ടിലേക്ക് റീസെറ്റ് ചെയ്യപ്പെടുകയും എല്ലാ ഉപയോക്തൃ ഡാറ്റയും നഷ്‌ടപ്പെടുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി Android TV അൺലോക്ക് ചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, നിങ്ങളുടെ Android TV ഫാക്‌ടറി ഡിഫോൾട്ടിലേക്ക് റീസെറ്റ് ചെയ്യപ്പെടുകയും എല്ലാ ഉപയോക്തൃ ഡാറ്റയും നഷ്‌ടപ്പെടുകയും ചെയ്യും."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"നിങ്ങൾ ഫോൺ അൺലോക്കുചെയ്യാൻ തവണ <xliff:g id="NUMBER_0">%1$d</xliff:g> തെറ്റായി ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഫോൺ ഫാക്‌ടറി ഡിഫോൾട്ടിലേക്ക് പുനഃസജ്ജികരിക്കുകയും ഉപയോക്തൃ ഡാറ്റയെല്ലാം നഷ്‌ടപ്പെടുകയും ചെയ്യും."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"നിങ്ങൾ ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ തവണ <xliff:g id="NUMBER">%d</xliff:g> തെറ്റായി ശ്രമിച്ചു. ടാബ്‌ലെറ്റ് ഇപ്പോൾ ഫാക്‌ടറി ഡിഫോൾട്ടിലേക്ക് പുനസജ്ജീകരിക്കും."</string>
     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി Android TV അൺലോക്ക് ചെയ്യാൻ ശ്രമിച്ചു. നിങ്ങളുടെ Android TV ഇപ്പോൾ ഫാക്‌ടറി ഡിഫോൾട്ടിലേക്ക് റീസെറ്റ് ചെയ്യപ്പെടും."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index e5d1953..bc4450f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1651,7 +1651,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"रंगांची उलटापालट"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"रंग सुधारणा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> सुरू केला आहे."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केला आहे."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केले आहे."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"तुम्ही अ‍ॅक्सेसिबिलिटी बटणावर टॅप केल्यास वापरण्यासाठी एक वैशिष्ट्य निवडा:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"अ‍ॅक्सेसिबिलिटी जेश्चरसोबत वापराचे असलेले वैशिष्‍ट्य निवडा (दोन बोटांनी स्क्रीनच्या तळापासून वर स्वाइप करा):"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index a618eb5..e868676 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1947,12 +1947,12 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" मा अद्यावधिक गर्ने हो?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> लाई "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" मा अद्यावधिक गर्ने हो?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> र <xliff:g id="TYPE_1">%2$s</xliff:g> लाई "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" मा अद्यावधिक गर्ने हो?"</string>
-    <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"यी वस्तुहरू "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" मा अद्यावधिक गर्नुहोस्‌: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> र <xliff:g id="TYPE_2">%3$s</xliff:g> हो?"</string>
+    <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"यी वस्तुहरू "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" मा अपडेट गर्नुहोस्‌: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> र <xliff:g id="TYPE_2">%3$s</xliff:g> हो?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"सुरक्षित गर्नुहोस्"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"पर्दैन, धन्यवाद"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"अहिले होइन"</string>
     <string name="autofill_save_never" msgid="6821841919831402526">"कहिल्यै होइन"</string>
-    <string name="autofill_update_yes" msgid="4608662968996874445">"अद्यावधिक गर्नुहोस्"</string>
+    <string name="autofill_update_yes" msgid="4608662968996874445">"अपडेट गर्नुहोस्"</string>
     <string name="autofill_continue_yes" msgid="7914985605534510385">"जारी राख्नुहोस्"</string>
     <string name="autofill_save_type_password" msgid="5624528786144539944">"पासवर्ड"</string>
     <string name="autofill_save_type_address" msgid="3111006395818252885">"ठेगाना"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ee56eb2..6feb69f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -237,7 +237,7 @@
     <string name="global_actions" product="default" msgid="6410072189971495460">"Telefoonopties"</string>
     <string name="global_action_lock" msgid="6949357274257655383">"Schermvergrendeling"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Uitschakelen"</string>
-    <string name="global_action_power_options" msgid="1185286119330160073">"Voeding"</string>
+    <string name="global_action_power_options" msgid="1185286119330160073">"Aan/uit"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Opnieuw opstarten"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Noodgeval"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Bugrapport"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 6a729dc..873cdbb 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1307,7 +1307,7 @@
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ଆନାଲଗ୍‍ ଅଡିଓ ଆକ୍ସେସରୀ ଚିହ୍ନଟ ହେଲା"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ଏହି ଫୋନ୍‌ରେ କନେକ୍ଟ ଥିବା ଡିଭାଇସ୍‍ କମ୍ପାଟିବଲ୍‍ ନୁହେଁ। ଅଧିକ ଜାଣିବା ପାଇଁ ଟାପ୍‌ କରନ୍ତୁ।"</string>
     <string name="adb_active_notification_title" msgid="408390247354560331">"USB ଡିବଗିଂ ସଂଯୁକ୍ତ ହୋଇଛି"</string>
-    <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ଡିବଗିଂ ସୁବିଧାକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+    <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ଡିବଗିଂକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ଡିବଗିଙ୍ଗକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ୱାୟାରଲେସ୍ ଡିବଗିଂ ସଂଯୋଗ କରାଯାଇଛି"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ୱାୟାରଲେସ୍ ଡିବଗିଂକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8fc295d..254f1d0 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1171,7 +1171,7 @@
     <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otwieraj linki z <xliff:g id="HOST">%1$s</xliff:g> w"</string>
     <string name="whichOpenLinksWith" msgid="1120936181362907258">"Otwieraj linki w"</string>
     <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otwieraj linki w aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
-    <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otwieraj linki z: <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otwieraj linki z <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Udziel uprawnień"</string>
     <string name="whichEditApplication" msgid="6191568491456092812">"Edytuj w aplikacji"</string>
     <string name="whichEditApplicationNamed" msgid="8096494987978521514">"Edytuj w aplikacji %1$s"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 8173d07..bea5300 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1651,7 +1651,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Escolha um recurso a ser usado quando você toca no botão de acessibilidade:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Escolha um recurso para usar com o gesto de acessibilidade (deslizar de baixo para cima na tela com dois dedos):"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ada2be2..069dc64 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -237,7 +237,7 @@
     <string name="global_actions" product="default" msgid="6410072189971495460">"Opções do telefone"</string>
     <string name="global_action_lock" msgid="6949357274257655383">"Bloqueio de ecrã"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Desligar"</string>
-    <string name="global_action_power_options" msgid="1185286119330160073">"Ligar/desligar"</string>
+    <string name="global_action_power_options" msgid="1185286119330160073">"Ligar"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Reiniciar"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Emergência"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de erros"</string>
@@ -264,7 +264,7 @@
     <string name="global_action_settings" msgid="4671878836947494217">"Definições"</string>
     <string name="global_action_assist" msgid="2517047220311505805">"Assistência"</string>
     <string name="global_action_voice_assist" msgid="6655788068555086695">"Assist. de voz"</string>
-    <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueio"</string>
+    <string name="global_action_lockdown" msgid="2475471405907902963">"Bloquear"</string>
     <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
     <string name="notification_hidden_text" msgid="2835519769868187223">"Nova notificação"</string>
     <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 8173d07..bea5300 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1651,7 +1651,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Escolha um recurso a ser usado quando você toca no botão de acessibilidade:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Escolha um recurso para usar com o gesto de acessibilidade (deslizar de baixo para cima na tela com dois dedos):"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d5a6aee..38fcff1 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -242,7 +242,7 @@
     <string name="global_action_lock" msgid="6949357274257655383">"Блокировка экрана"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Выключить"</string>
     <string name="global_action_power_options" msgid="1185286119330160073">"Питание"</string>
-    <string name="global_action_restart" msgid="4678451019561687074">"Перезапуск"</string>
+    <string name="global_action_restart" msgid="4678451019561687074">"Перезапустить"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Экстренный вызов"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Отчет об ошибке"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"Закончить сеанс"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index fe392d4..2d3c685 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1622,8 +1622,8 @@
     <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"వాల్యూమ్‌ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్‌లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"యాక్సెస్ సామర్థ్యం షార్ట్‌కట్‌ను ఉపయోగించాలా?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"షార్ట్‌కట్ ఆన్ చేసి ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్‌లను 3 సెకన్ల పాటు నొక్కి ఉంచితే యాక్సెస్ సౌలభ్య ఫీచర్ ప్రారంభం అవుతుంది."</string>
-    <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"యాక్సెసిబిలిటీ‌లను ఆన్ చేయాలా?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"రెండు వాల్యూమ్ కీలను కొంత సేపు నొక్కి పట్టుకుంటే యాక్సెసిబిలిటీలు ఆన్ అవుతాయి. ఇది మీ పరికరం పనిచేసే విధానాన్ని మార్చవచ్చు.\n\nప్రస్తుత ఫీచర్లు:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nఎంపిక చేసిన ఫీచర్లను మీరు సెట్టింగ్‌లు&gt;యాక్సెసిబిలిటీలో మార్చవచ్చు."</string>
+    <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"యాక్సెసిబిలిటీ‌ ఫీచ‌ర్‌ల‌ను ఆన్ చేయాలా?"</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"రెండు వాల్యూమ్ కీలను కొంత సేపు నొక్కి పట్టుకుంటే యాక్సెసిబిలిటీ ఫీచ‌ర్‌లు ఆన్ అవుతాయి. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nప్రస్తుత ఫీచర్లు:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nఎంపిక చేసిన ఫీచర్లను మీరు సెట్టింగ్‌లు&gt;యాక్సెసిబిలిటీలో మార్చవచ్చు."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"<xliff:g id="SERVICE">%1$s</xliff:g> ఆన్ చేయాాలా?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"రెండు వాల్యూమ్ కీలను కొన్ని సెకన్ల పాటు నొక్కి పట్టుకోవడం ద్వారా యాక్సెసిబిలిటీ అయిన <xliff:g id="SERVICE">%1$s</xliff:g> ఆన్ అవుతుంది. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nసెట్టింగ్‌లు &gt; యాక్సెసిబిలిటీలో, వేరొక ఫీచర్‌ను ప్రారంభించేలా ఈ షార్ట్ కట్‌ను మీరు మార్చవచ్చు."</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f2ee404..4cea142 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1651,7 +1651,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Pag-invert ng Kulay"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Pagwawasto ng Kulay"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Mga volume key na pinipindot nang matagal. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pinindot nang matagal ang volume keys. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Pumili ng feature na gagana sa pamamagitan ng pag-tap mo sa button ng accessibility:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Pumili ng feature na gagana sa pamamagitan ng galaw ng accessibility (pag-swipe pataas mula sa ibaba ng screen gamit ang dalawang daliri):"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 8a2ead4..0b44c52 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1128,7 +1128,7 @@
     <string name="whichViewApplication" msgid="5733194231473132945">"اس کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationNamed" msgid="415164730629690105">"‏%1$s کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationLabel" msgid="7367556735684742409">"کھولیں"</string>
-    <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"‫<xliff:g id="HOST">%1$s</xliff:g> لنکس کے اس کے ساتھ کھولیں"</string>
+    <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"‫‫<xliff:g id="HOST">%1$s</xliff:g> لنکس اس کے ساتھ کھولیں"</string>
     <string name="whichOpenLinksWith" msgid="1120936181362907258">"اس کے ساتھ لنکس کھولیں"</string>
     <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"<xliff:g id="APPLICATION">%1$s</xliff:g> کے ذریعے لنکس کھولیں"</string>
     <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"<xliff:g id="HOST">%1$s</xliff:g> لنکس کو <xliff:g id="APPLICATION">%2$s</xliff:g> کے ذریعے کھولیں"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index a4d60e6..d04c618 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -92,7 +92,7 @@
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"紧急回拨模式"</string>
     <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"移动数据状态"</string>
     <string name="notification_channel_sms" msgid="1243384981025535724">"短信"</string>
-    <string name="notification_channel_voice_mail" msgid="8457433203106654172">"语音邮件"</string>
+    <string name="notification_channel_voice_mail" msgid="8457433203106654172">"语音信息"</string>
     <string name="notification_channel_wfc" msgid="9048240466765169038">"WLAN 通话"</string>
     <string name="notification_channel_sim" msgid="5098802350325677490">"SIM 卡状态"</string>
     <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"高优先顺序 SIM 卡状态"</string>
@@ -958,7 +958,7 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"允许该应用修改您手机上存储的浏览器历史记录或浏览器书签。此权限可让该应用清除或修改浏览器数据。请注意:此权限可能不适用于第三方浏览器或具备网页浏览功能的其他应用。"</string>
     <string name="permlab_setAlarm" msgid="1158001610254173567">"设置闹钟"</string>
     <string name="permdesc_setAlarm" msgid="2185033720060109640">"允许应用在已安装的闹钟应用中设置闹钟。有些闹钟应用可能无法实现此功能。"</string>
-    <string name="permlab_addVoicemail" msgid="4770245808840814471">"添加语音邮件"</string>
+    <string name="permlab_addVoicemail" msgid="4770245808840814471">"添加语音信息"</string>
     <string name="permdesc_addVoicemail" msgid="5470312139820074324">"允许应用在您的语音信箱中留言。"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"修改“浏览器”地理位置的权限"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"允许应用修改“浏览器”的地理位置权限。恶意应用可能借此向任意网站发送位置信息。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4abd440..4fe07806 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1309,7 +1309,7 @@
     <string name="adb_active_notification_title" msgid="408390247354560331">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"Thepha ukuze uvale ukulungisa amaphutha kwe-USB"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Khetha ukuvimbela ukulungisa iphutha le-USB."</string>
-    <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Ukulungisa amaphutha okungenantambo kuxhunyiwe"</string>
+    <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Ukulungisa amaphutha e-wireless kuxhunyiwe"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Thepha ukuze ucishe ukulungisa amaphutha okungenantambo"</string>
     <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Khetha ukukhubaza ukulungisa amaphutha okungenantambo."</string>
     <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Imodi yokuhlola i-harness inikwe amandla"</string>
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index bf7f339..1b327257 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -26,13 +26,11 @@
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
 
 import android.app.Instrumentation;
 import android.content.Context;
@@ -135,37 +133,29 @@
         InsetsSourceConsumer consumer = new InsetsSourceConsumer(
                 ITYPE_IME, state, null, controller);
 
-        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
-
         InsetsSource source = new InsetsSource(ITYPE_IME);
         source.setFrame(0, 1, 2, 3);
-        consumer.updateSource(new InsetsSource(source));
-
-        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_USER);
+        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_NONE);
 
         // While we're animating, updates are delayed
         source.setFrame(4, 5, 6, 7);
-        consumer.updateSource(new InsetsSource(source));
+        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_USER);
         assertEquals(new Rect(0, 1, 2, 3), state.peekSource(ITYPE_IME).getFrame());
 
         // Finish the animation, now the pending frame should be applied
-        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
         assertTrue(consumer.notifyAnimationFinished());
         assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
 
-        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_USER);
-
         // Animating again, updates are delayed
         source.setFrame(8, 9, 10, 11);
-        consumer.updateSource(new InsetsSource(source));
+        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_USER);
         assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
 
         // Updating with the current frame triggers a different code path, verify this clears
         // the pending 8, 9, 10, 11 frame:
         source.setFrame(4, 5, 6, 7);
-        consumer.updateSource(new InsetsSource(source));
+        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_USER);
 
-        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
         assertFalse(consumer.notifyAnimationFinished());
         assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
     }
diff --git a/location/java/android/location/AbstractListenerManager.java b/location/java/android/location/AbstractListenerManager.java
index 36b8689..f5595e8 100644
--- a/location/java/android/location/AbstractListenerManager.java
+++ b/location/java/android/location/AbstractListenerManager.java
@@ -29,6 +29,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -193,7 +195,7 @@
     protected abstract void unregisterService() throws RemoteException;
 
     @Nullable
-    protected TRequest merge(@NonNull TRequest[] requests) {
+    protected TRequest merge(@NonNull List<TRequest> requests) {
         for (TRequest request : requests) {
             Preconditions.checkArgument(request == null,
                     "merge() has to be overridden for non-null requests.");
@@ -221,9 +223,9 @@
             return mListeners.valueAt(0).getRequest();
         }
 
-        TRequest[] requests = (TRequest[]) new Object[mListeners.size()];
+        ArrayList<TRequest> requests = new ArrayList<>(mListeners.size());
         for (int index = 0; index < mListeners.size(); index++) {
-            requests[index] = mListeners.valueAt(index).getRequest();
+            requests.add(mListeners.valueAt(index).getRequest());
         }
         return merge(requests);
     }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 7d15bbd..f3c9e94 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -3030,14 +3030,14 @@
 
         @Override
         @Nullable
-        protected GnssRequest merge(@NonNull GnssRequest[] requests) {
-            Preconditions.checkArgument(requests.length > 0);
+        protected GnssRequest merge(@NonNull List<GnssRequest> requests) {
+            Preconditions.checkArgument(!requests.isEmpty());
             for (GnssRequest request : requests) {
                 if (request.isFullTracking()) {
                     return request;
                 }
             }
-            return requests[0];
+            return requests.get(0);
         }
 
         private class GnssMeasurementsListener extends IGnssMeasurementsListener.Stub {
diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl
index ca14052..fe15f0e 100644
--- a/media/java/android/media/IMediaRouter2.aidl
+++ b/media/java/android/media/IMediaRouter2.aidl
@@ -34,7 +34,8 @@
     void notifySessionReleased(in RoutingSessionInfo sessionInfo);
     /**
      * Gets hints of the new session for the given route.
-     * Call MediaRouterService#notifySessionHintsForCreatingSession to pass the result.
+     * Call MediaRouterService#requestCreateSessionWithRouter2 to pass the result.
      */
-    void getSessionHintsForCreatingSession(long uniqueRequestId, in MediaRoute2Info route);
+    void requestCreateSessionByManager(long uniqueRequestId, in RoutingSessionInfo oldSession,
+        in MediaRoute2Info route);
 }
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 52bac67..068f968 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -44,7 +44,7 @@
     void requestSetVolume(IMediaRouterClient client, String routeId, int volume);
     void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction);
 
-    // Note: When changing this file, match the order of methods below with 
+    // Note: When changing this file, match the order of methods below with
     // MediaRouterService.java for readability.
 
     // Methods for MediaRouter2
@@ -57,10 +57,9 @@
             in RouteDiscoveryPreference preference);
     void setRouteVolumeWithRouter2(IMediaRouter2 router, in MediaRoute2Info route, int volume);
 
-    void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
-            in MediaRoute2Info route, in @nullable Bundle sessionHints);
-    void notifySessionHintsForCreatingSession(IMediaRouter2 router, long uniqueRequestId,
-                in MediaRoute2Info route, in @nullable Bundle sessionHints);
+    void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, long managerRequestId,
+            in RoutingSessionInfo oldSession, in MediaRoute2Info route,
+            in @nullable Bundle sessionHints);
     void selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
     void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
     void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId,
@@ -76,7 +75,7 @@
             in MediaRoute2Info route, int volume);
 
     void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
-            String packageName, in @nullable MediaRoute2Info route);
+            in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route);
     void selectRouteWithManager(IMediaRouter2Manager manager, int requestId,
             String sessionId, in MediaRoute2Info route);
     void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId,
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 62d76c0..0780c68 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2762,7 +2762,7 @@
                 builder.append(hexdigits.charAt(key[i] & 0x0f));
             }
             builder.append("], iv [");
-            for (int i = 0; i < key.length; i++) {
+            for (int i = 0; i < iv.length; i++) {
                 builder.append(hexdigits.charAt((iv[i] & 0xf0) >> 4));
                 builder.append(hexdigits.charAt(iv[i] & 0x0f));
             }
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 8e95239..f22222d 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -36,7 +36,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -62,6 +61,11 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final Object sRouterLock = new Object();
 
+    // The maximum time for the old routing controller available after transfer.
+    private static final int TRANSFER_TIMEOUT_MS = 30_000;
+    // The manager request ID representing that no manager is involved.
+    private static final long MANAGER_REQUEST_ID_NONE = MediaRoute2ProviderService.REQUEST_ID_NONE;
+
     @GuardedBy("sRouterLock")
     private static MediaRouter2 sInstance;
 
@@ -80,7 +84,7 @@
 
     private final String mPackageName;
     @GuardedBy("sRouterLock")
-    final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
+    final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>();
 
     final RoutingController mSystemController;
 
@@ -94,7 +98,7 @@
     @GuardedBy("sRouterLock")
     private final Map<String, RoutingController> mNonSystemRoutingControllers = new ArrayMap<>();
 
-    private final AtomicInteger mControllerCreationRequestCnt = new AtomicInteger(1);
+    private final AtomicInteger mNextRequestId = new AtomicInteger(1);
 
     final Handler mHandler;
     @GuardedBy("sRouterLock")
@@ -412,9 +416,16 @@
             return;
         }
 
-        final int requestId = mControllerCreationRequestCnt.getAndIncrement();
+        requestCreateController(controller, route, MANAGER_REQUEST_ID_NONE);
+    }
 
-        ControllerCreationRequest request = new ControllerCreationRequest(requestId, route);
+    void requestCreateController(@NonNull RoutingController controller,
+            @NonNull MediaRoute2Info route, long managerRequestId) {
+
+        final int requestId = mNextRequestId.getAndIncrement();
+
+        ControllerCreationRequest request = new ControllerCreationRequest(requestId,
+                managerRequestId, route, controller);
         mControllerCreationRequests.add(request);
 
         OnGetControllerHintsListener listener = mOnGetControllerHintsListener;
@@ -433,11 +444,15 @@
         if (stub != null) {
             try {
                 mMediaRouterService.requestCreateSessionWithRouter2(
-                        stub, requestId, route, controllerHints);
+                        stub, requestId, managerRequestId,
+                        controller.getRoutingSessionInfo(), route, controllerHints);
             } catch (RemoteException ex) {
-                Log.e(TAG, "transfer: Unable to request to create controller.", ex);
-                mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
-                        MediaRouter2.this, requestId, null));
+                Log.e(TAG, "createControllerForTransfer: "
+                        + "Failed to request for creating a controller.", ex);
+                mControllerCreationRequests.remove(request);
+                if (managerRequestId == MANAGER_REQUEST_ID_NONE) {
+                    notifyTransferFailure(route);
+                }
             }
         }
     }
@@ -463,7 +478,8 @@
     }
 
     /**
-     * Gets the list of currently non-released {@link RoutingController routing controllers}.
+     * Gets the list of currently active {@link RoutingController routing controllers} on which
+     * media can be played.
      * <p>
      * Note: The list returned here will never be empty. The first element in the list is
      * always the {@link #getSystemController() system controller}.
@@ -554,13 +570,13 @@
             mShouldUpdateRoutes = true;
         }
 
-        if (addedRoutes.size() > 0) {
+        if (!addedRoutes.isEmpty()) {
             notifyRoutesAdded(addedRoutes);
         }
-        if (removedRoutes.size() > 0) {
+        if (!removedRoutes.isEmpty()) {
             notifyRoutesRemoved(removedRoutes);
         }
-        if (changedRoutes.size() > 0) {
+        if (!changedRoutes.isEmpty()) {
             notifyRoutesChanged(changedRoutes);
         }
 
@@ -582,7 +598,7 @@
             }
             mShouldUpdateRoutes = true;
         }
-        if (addedRoutes.size() > 0) {
+        if (!addedRoutes.isEmpty()) {
             notifyRoutesAdded(addedRoutes);
         }
     }
@@ -598,7 +614,7 @@
             }
             mShouldUpdateRoutes = true;
         }
-        if (removedRoutes.size() > 0) {
+        if (!removedRoutes.isEmpty()) {
             notifyRoutesRemoved(removedRoutes);
         }
     }
@@ -614,7 +630,7 @@
             }
             mShouldUpdateRoutes = true;
         }
-        if (changedRoutes.size() > 0) {
+        if (!changedRoutes.isEmpty()) {
             notifyRoutesChanged(changedRoutes);
         }
     }
@@ -635,44 +651,47 @@
             }
         }
 
-        if (matchingRequest != null) {
-            mControllerCreationRequests.remove(matchingRequest);
-
-            MediaRoute2Info requestedRoute = matchingRequest.mRoute;
-
-            if (sessionInfo == null) {
-                // TODO: We may need to distinguish between failure and rejection.
-                //       One way can be introducing 'reason'.
-                notifyTransferFailure(requestedRoute);
-                return;
-            } else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
-                Log.w(TAG, "The session does not contain the requested route. "
-                        + "(requestedRouteId=" + requestedRoute.getId()
-                        + ", actualRoutes=" + sessionInfo.getSelectedRoutes()
-                        + ")");
-                notifyTransferFailure(requestedRoute);
-                return;
-            } else if (!TextUtils.equals(requestedRoute.getProviderId(),
-                    sessionInfo.getProviderId())) {
-                Log.w(TAG, "The session's provider ID does not match the requested route's. "
-                        + "(requested route's providerId=" + requestedRoute.getProviderId()
-                        + ", actual providerId=" + sessionInfo.getProviderId()
-                        + ")");
-                notifyTransferFailure(requestedRoute);
-                return;
-            }
-        }
-
-        if (sessionInfo == null) {
+        if (matchingRequest == null) {
+            Log.w(TAG, "createControllerOnHandler: Ignoring an unknown request.");
             return;
         }
 
-        RoutingController oldController = getCurrentController();
-        if (!oldController.releaseInternal(
-                /* shouldReleaseSession= */ matchingRequest != null,
-                /* shouldNotifyStop= */ false)) {
-            // Could not release the controller since it was just released by other thread.
-            oldController = getSystemController();
+        mControllerCreationRequests.remove(matchingRequest);
+        MediaRoute2Info requestedRoute = matchingRequest.mRoute;
+
+        // TODO: Notify the reason for failure.
+        if (sessionInfo == null) {
+            notifyTransferFailure(requestedRoute);
+            return;
+        } else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
+            Log.w(TAG, "The session does not contain the requested route. "
+                    + "(requestedRouteId=" + requestedRoute.getId()
+                    + ", actualRoutes=" + sessionInfo.getSelectedRoutes()
+                    + ")");
+            notifyTransferFailure(requestedRoute);
+            return;
+        } else if (!TextUtils.equals(requestedRoute.getProviderId(),
+                sessionInfo.getProviderId())) {
+            Log.w(TAG, "The session's provider ID does not match the requested route's. "
+                    + "(requested route's providerId=" + requestedRoute.getProviderId()
+                    + ", actual providerId=" + sessionInfo.getProviderId()
+                    + ")");
+            notifyTransferFailure(requestedRoute);
+            return;
+        }
+
+        RoutingController oldController = matchingRequest.mOldController;
+        // When the old controller is released before transferred, treat it as a failure.
+        // This could also happen when transfer is requested twice or more.
+        if (!oldController.scheduleRelease()) {
+            Log.w(TAG, "createControllerOnHandler: "
+                    + "Ignoring controller creation for released old controller. "
+                    + "oldController=" + oldController);
+            if (!sessionInfo.isSystemSession()) {
+                new RoutingController(sessionInfo).release();
+            }
+            notifyTransferFailure(requestedRoute);
+            return;
         }
 
         RoutingController newController;
@@ -686,12 +705,7 @@
             }
         }
 
-        // Two controller can be same if stop() is called before the result of Cast -> Phone comes.
-        if (oldController != newController) {
-            notifyTransfer(oldController, newController);
-        } else if (matchingRequest != null) {
-            notifyTransferFailure(matchingRequest.mRoute);
-        }
+        notifyTransfer(oldController, newController);
     }
 
     void updateControllerOnHandler(RoutingSessionInfo sessionInfo) {
@@ -736,10 +750,9 @@
             return;
         }
 
-        final String uniqueSessionId = sessionInfo.getId();
         RoutingController matchingController;
         synchronized (sRouterLock) {
-            matchingController = mNonSystemRoutingControllers.get(uniqueSessionId);
+            matchingController = mNonSystemRoutingControllers.get(sessionInfo.getId());
         }
 
         if (matchingController == null) {
@@ -757,34 +770,23 @@
             return;
         }
 
-        matchingController.releaseInternal(
-                /* shouldReleaseSession= */ false, /* shouldNotifyStop= */ true);
+        matchingController.releaseInternal(/* shouldReleaseSession= */ false);
     }
 
-    void onGetControllerHintsForCreatingSessionOnHandler(long uniqueRequestId,
-            MediaRoute2Info route) {
-        OnGetControllerHintsListener listener = mOnGetControllerHintsListener;
-        Bundle controllerHints = null;
-        if (listener != null) {
-            controllerHints = listener.onGetControllerHints(route);
-            if (controllerHints != null) {
-                controllerHints = new Bundle(controllerHints);
+    void onRequestCreateControllerByManagerOnHandler(RoutingSessionInfo oldSession,
+            MediaRoute2Info route, long managerRequestId) {
+        RoutingController controller;
+        if (oldSession.isSystemSession()) {
+            controller = getSystemController();
+        } else {
+            synchronized (sRouterLock) {
+                controller = mNonSystemRoutingControllers.get(oldSession.getId());
             }
         }
-
-        MediaRouter2Stub stub;
-        synchronized (sRouterLock) {
-            stub = mStub;
+        if (controller == null) {
+            return;
         }
-        if (stub != null) {
-            try {
-                mMediaRouterService.notifySessionHintsForCreatingSession(
-                        stub, uniqueRequestId, route, controllerHints);
-            } catch (RemoteException ex) {
-                Log.e(TAG, "onGetControllerHintsForCreatingSessionOnHandler: Unable to notify "
-                        + " session hints for creating session.", ex);
-            }
-        }
+        requestCreateController(controller, route, managerRequestId);
     }
 
     private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
@@ -886,8 +888,13 @@
         /**
          * Called when a media is transferred between two different routing controllers.
          * This can happen by calling {@link #transferTo(MediaRoute2Info)}.
-         * The {@code oldController} is released before this method is called, except for the
-         * {@link #getSystemController() system controller}.
+         * <p> Override this to start playback with {@code newController}. You may want to get
+         * the status of the media that is being played with {@code oldController} and resume it
+         * continuously with {@code newController}.
+         * After this is called, any callbacks with {@code oldController} will not be invoked
+         * unless {@code oldController} is the {@link #getSystemController() system controller}.
+         * You need to {@link RoutingController#release() release} {@code oldController} before
+         * playing the media with {@code newController}.
          *
          * @param oldController the previous controller that controlled routing
          * @param newController the new controller to control routing
@@ -906,16 +913,15 @@
         /**
          * Called when a media routing stops. It can be stopped by a user or a provider.
          * App should not continue playing media locally when this method is called.
-         * The {@code oldController} is released before this method is called, except for the
-         * {@link #getSystemController() system controller}.
+         * The {@code controller} is released before this method is called.
          *
-         * @param controller the controller that controlled the stopped media routing.
+         * @param controller the controller that controlled the stopped media routing
          */
         public void onStop(@NonNull RoutingController controller) { }
     }
 
     /**
-     * A listener interface to send an optional app-specific hints when creating the
+     * A listener interface to send optional app-specific hints when creating a
      * {@link RoutingController}.
      */
     public interface OnGetControllerHintsListener {
@@ -929,9 +935,9 @@
          * The method will be called on the same thread that calls
          * {@link #transferTo(MediaRoute2Info)} or the main thread if it is requested by the system.
          *
-         * @param route The route to create controller with
+         * @param route the route to create a controller with
          * @return An optional bundle of app-specific arguments to send to the provider,
-         *         or null if none. The contents of this bundle may affect the result of
+         *         or {@code null} if none. The contents of this bundle may affect the result of
          *         controller creation.
          * @see MediaRoute2ProviderService#onCreateSession(long, String, String, Bundle)
          */
@@ -944,10 +950,11 @@
      */
     public abstract static class ControllerCallback {
         /**
-         * Called when a controller is updated. (e.g., the selected routes of the
-         * controller is changed or the volume of the controller is changed.)
+         * Called when a controller is updated. (e.g., when the selected routes of the
+         * controller is changed or when the volume of the controller is changed.)
          *
-         * @param controller the updated controller. Can be the system controller.
+         * @param controller the updated controller. It may be the
+         * {@link #getSystemController() system controller}.
          * @see #getSystemController()
          */
         public void onControllerUpdated(@NonNull RoutingController controller) { }
@@ -955,20 +962,28 @@
 
     /**
      * A class to control media routing session in media route provider.
-     * For example, selecting/deselecting/transferring routes to a session can be done through this
-     * class. Instances are created by {@link #transferTo(MediaRoute2Info)}.
+     * For example, selecting/deselecting/transferring to routes of a session can be done through
+     * this. Instances are created when
+     * {@link TransferCallback#onTransfer(RoutingController, RoutingController)} is called,
+     * which is invoked after {@link #transferTo(MediaRoute2Info)} is called.
      */
     public class RoutingController {
         private final Object mControllerLock = new Object();
 
+        private static final int CONTROLLER_STATE_UNKNOWN = 0;
+        private static final int CONTROLLER_STATE_ACTIVE = 1;
+        private static final int CONTROLLER_STATE_RELEASING = 2;
+        private static final int CONTROLLER_STATE_RELEASED = 3;
+
         @GuardedBy("mControllerLock")
         private RoutingSessionInfo mSessionInfo;
 
         @GuardedBy("mControllerLock")
-        private volatile boolean mIsReleased;
+        private int mState;
 
         RoutingController(@NonNull RoutingSessionInfo sessionInfo) {
             mSessionInfo = sessionInfo;
+            mState = CONTROLLER_STATE_ACTIVE;
         }
 
         /**
@@ -982,7 +997,7 @@
         }
 
         /**
-         * Gets the original session id set by
+         * Gets the original session ID set by
          * {@link RoutingSessionInfo.Builder#Builder(String, String)}.
          *
          * @hide
@@ -996,7 +1011,8 @@
         }
 
         /**
-         * @return the control hints used to control routing session if available.
+         * Gets the control hints used to control routing session if available.
+         * It is set by the media route provider.
          */
         @Nullable
         public Bundle getControlHints() {
@@ -1042,7 +1058,9 @@
         }
 
         /**
-         * Gets information about how volume is handled on the session.
+         * Gets the information about how volume is handled on the session.
+         * <p>Please note that you may not control the volume of the session even when
+         * you can control the volume of each selected route in the session.
          *
          * @return {@link MediaRoute2Info#PLAYBACK_VOLUME_FIXED} or
          * {@link MediaRoute2Info#PLAYBACK_VOLUME_VARIABLE}
@@ -1067,8 +1085,8 @@
          * Gets the current volume of the session.
          * <p>
          * When it's available, it represents the volume of routing session, which is a group
-         * of selected routes. To get the volume of a route,
-         * use {@link MediaRoute2Info#getVolume()}.
+         * of selected routes. Use {@link MediaRoute2Info#getVolume()}
+         * to get the volume of a route,
          * </p>
          * @see MediaRoute2Info#getVolume()
          */
@@ -1087,7 +1105,7 @@
          */
         public boolean isReleased() {
             synchronized (mControllerLock) {
-                return mIsReleased;
+                return mState == CONTROLLER_STATE_RELEASED;
             }
         }
 
@@ -1099,8 +1117,8 @@
          * <p>
          * The given route must satisfy all of the following conditions:
          * <ul>
-         * <li>ID should not be included in {@link #getSelectedRoutes()}</li>
-         * <li>ID should be included in {@link #getSelectableRoutes()}</li>
+         * <li>It should not be included in {@link #getSelectedRoutes()}</li>
+         * <li>It should be included in {@link #getSelectableRoutes()}</li>
          * </ul>
          * If the route doesn't meet any of above conditions, it will be ignored.
          *
@@ -1111,11 +1129,9 @@
          */
         public void selectRoute(@NonNull MediaRoute2Info route) {
             Objects.requireNonNull(route, "route must not be null");
-            synchronized (mControllerLock) {
-                if (mIsReleased) {
-                    Log.w(TAG, "selectRoute: Called on released controller. Ignoring.");
-                    return;
-                }
+            if (isReleased()) {
+                Log.w(TAG, "selectRoute: Called on released controller. Ignoring.");
+                return;
             }
 
             List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
@@ -1145,12 +1161,12 @@
 
         /**
          * Deselects a route from the remote session. After a route is deselected, the media is
-         * expected to be stopped on the deselected routes.
+         * expected to be stopped on the deselected route.
          * <p>
          * The given route must satisfy all of the following conditions:
          * <ul>
-         * <li>ID should be included in {@link #getSelectedRoutes()}</li>
-         * <li>ID should be included in {@link #getDeselectableRoutes()}</li>
+         * <li>It should be included in {@link #getSelectedRoutes()}</li>
+         * <li>It should be included in {@link #getDeselectableRoutes()}</li>
          * </ul>
          * If the route doesn't meet any of above conditions, it will be ignored.
          *
@@ -1160,11 +1176,9 @@
          */
         public void deselectRoute(@NonNull MediaRoute2Info route) {
             Objects.requireNonNull(route, "route must not be null");
-            synchronized (mControllerLock) {
-                if (mIsReleased) {
-                    Log.w(TAG, "deselectRoute: called on released controller. Ignoring.");
-                    return;
-                }
+            if (isReleased()) {
+                Log.w(TAG, "deselectRoute: called on released controller. Ignoring.");
+                return;
             }
 
             List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
@@ -1193,13 +1207,8 @@
         }
 
         /**
-         * Transfers to a given route for the remote session. The given route must satisfy
-         * all of the following conditions:
-         * <ul>
-         * <li>ID should not be included in {@link RoutingSessionInfo#getSelectedRoutes()}</li>
-         * <li>ID should be included in {@link RoutingSessionInfo#getTransferableRoutes()}</li>
-         * </ul>
-         * If the route doesn't meet any of above conditions, it will be ignored.
+         * Transfers to a given route for the remote session. The given route must be included
+         * in {@link RoutingSessionInfo#getTransferableRoutes()}.
          *
          * @see RoutingSessionInfo#getSelectedRoutes()
          * @see RoutingSessionInfo#getTransferableRoutes()
@@ -1208,19 +1217,13 @@
         void transferToRoute(@NonNull MediaRoute2Info route) {
             Objects.requireNonNull(route, "route must not be null");
             synchronized (mControllerLock) {
-                if (mIsReleased) {
+                if (isReleased()) {
                     Log.w(TAG, "transferToRoute: Called on released controller. Ignoring.");
                     return;
                 }
 
-                if (mSessionInfo.getSelectedRoutes().contains(route.getId())) {
-                    Log.w(TAG, "Ignoring transferring to a route that is already added. "
-                            + "route=" + route);
-                    return;
-                }
-
                 if (!mSessionInfo.getTransferableRoutes().contains(route.getId())) {
-                    Log.w(TAG, "Ignoring transferring to a non-transferrable route=" + route);
+                    Log.w(TAG, "Ignoring transferring to a non-transferable route=" + route);
                     return;
                 }
             }
@@ -1255,11 +1258,9 @@
                 return;
             }
 
-            synchronized (mControllerLock) {
-                if (mIsReleased) {
-                    Log.w(TAG, "setVolume: Called on released controller. Ignoring.");
-                    return;
-                }
+            if (isReleased()) {
+                Log.w(TAG, "setVolume: Called on released controller. Ignoring.");
+                return;
             }
             MediaRouter2Stub stub;
             synchronized (sRouterLock) {
@@ -1275,33 +1276,58 @@
         }
 
         /**
-         * Release this controller and corresponding session.
+         * Releases this controller and the corresponding session.
          * Any operations on this controller after calling this method will be ignored.
          * The devices that are playing media will stop playing it.
          */
-        // TODO(b/157872573): Add tests using {@link MediaRouter2Manager#getActiveSessions()}.
         public void release() {
-            releaseInternal(/* shouldReleaseSession= */ true, /* shouldNotifyStop= */ true);
+            releaseInternal(/* shouldReleaseSession= */ true);
         }
 
         /**
-         * Returns {@code true} when succeeded to release, {@code false} if the controller is
-         * already released.
+         * Schedules release of the controller.
+         * @return {@code true} if it's successfully scheduled, {@code false} if it's already
+         * scheduled to be released or released.
          */
-        boolean releaseInternal(boolean shouldReleaseSession, boolean shouldNotifyStop) {
+        boolean scheduleRelease() {
             synchronized (mControllerLock) {
-                if (mIsReleased) {
-                    Log.w(TAG, "releaseInternal: Called on released controller. Ignoring.");
+                if (mState != CONTROLLER_STATE_ACTIVE) {
                     return false;
                 }
-                mIsReleased = true;
+                mState = CONTROLLER_STATE_RELEASING;
             }
 
             synchronized (sRouterLock) {
+                // It could happen if the controller is released by the another thread
+                // in between two locks
                 if (!mNonSystemRoutingControllers.remove(getId(), this)) {
-                    Log.w(TAG, "releaseInternal: Ignoring unknown controller.");
-                    return false;
+                    // In that case, onStop isn't called so we return true to call onTransfer.
+                    // It's also consistent with that the another thread acquires the lock later.
+                    return true;
                 }
+            }
+
+            mHandler.postDelayed(this::release, TRANSFER_TIMEOUT_MS);
+
+            return true;
+        }
+
+        void releaseInternal(boolean shouldReleaseSession) {
+            boolean shouldNotifyStop;
+
+            synchronized (mControllerLock) {
+                if (mState == CONTROLLER_STATE_RELEASED) {
+                    if (DEBUG) {
+                        Log.d(TAG, "releaseInternal: Called on released controller. Ignoring.");
+                    }
+                    return;
+                }
+                shouldNotifyStop = (mState == CONTROLLER_STATE_ACTIVE);
+                mState = CONTROLLER_STATE_RELEASED;
+            }
+
+            synchronized (sRouterLock) {
+                mNonSystemRoutingControllers.remove(getId(), this);
 
                 if (shouldReleaseSession && mStub != null) {
                     try {
@@ -1326,7 +1352,6 @@
                     mStub = null;
                 }
             }
-            return true;
         }
 
         @Override
@@ -1389,9 +1414,14 @@
         }
 
         @Override
-        boolean releaseInternal(boolean shouldReleaseSession, boolean shouldNotifyStop) {
+        boolean scheduleRelease() {
+            // SystemRoutingController can be always transferred
+            return true;
+        }
+
+        @Override
+        void releaseInternal(boolean shouldReleaseSession) {
             // Do nothing. SystemRoutingController will never be released
-            return false;
         }
     }
 
@@ -1442,8 +1472,7 @@
             if (!(obj instanceof TransferCallbackRecord)) {
                 return false;
             }
-            return mTransferCallback
-                    == ((TransferCallbackRecord) obj).mTransferCallback;
+            return mTransferCallback == ((TransferCallbackRecord) obj).mTransferCallback;
         }
 
         @Override
@@ -1481,11 +1510,17 @@
 
     static final class ControllerCreationRequest {
         public final int mRequestId;
+        public final long mManagerRequestId;
         public final MediaRoute2Info mRoute;
+        public final RoutingController mOldController;
 
-        ControllerCreationRequest(int requestId, @NonNull MediaRoute2Info route) {
+        ControllerCreationRequest(int requestId, long managerRequestId,
+                @NonNull MediaRoute2Info route, @NonNull RoutingController oldController) {
             mRequestId = requestId;
-            mRoute = route;
+            mManagerRequestId = managerRequestId;
+            mRoute = Objects.requireNonNull(route, "route must not be null");
+            mOldController = Objects.requireNonNull(oldController,
+                    "oldController must not be null");
         }
     }
 
@@ -1534,11 +1569,11 @@
         }
 
         @Override
-        public void getSessionHintsForCreatingSession(long uniqueRequestId,
-                @NonNull MediaRoute2Info route) {
+        public void requestCreateSessionByManager(long managerRequestId,
+                RoutingSessionInfo oldSession, MediaRoute2Info route) {
             mHandler.sendMessage(obtainMessage(
-                    MediaRouter2::onGetControllerHintsForCreatingSessionOnHandler,
-                    MediaRouter2.this, uniqueRequestId, route));
+                    MediaRouter2::onRequestCreateControllerByManagerOnHandler,
+                    MediaRouter2.this, oldSession, route, managerRequestId));
         }
     }
 }
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index dad7859..4b09a5f 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -54,6 +54,12 @@
 public final class MediaRouter2Manager {
     private static final String TAG = "MR2Manager";
     private static final Object sLock = new Object();
+    /**
+     * The request ID for requests not asked by this instance.
+     * Shouldn't be used for a valid request.
+     * @hide
+     */
+    public static final int REQUEST_ID_NONE = 0;
     /** @hide */
     @VisibleForTesting
     public static final int TRANSFER_TIMEOUT_MS = 30_000;
@@ -480,7 +486,6 @@
             notifyTransferFailed(matchingRequest.mOldSessionInfo, requestedRoute);
             return;
         }
-        releaseSession(matchingRequest.mOldSessionInfo);
         notifyTransferred(matchingRequest.mOldSessionInfo, sessionInfo);
     }
 
@@ -777,7 +782,7 @@
         if (client != null) {
             try {
                 mMediaRouterService.requestCreateSessionWithManager(
-                        client, requestId, oldSession.getClientPackageName(), route);
+                        client, requestId, oldSession, route);
             } catch (RemoteException ex) {
                 Log.e(TAG, "requestCreateSession: Failed to send a request", ex);
             }
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index edf1fc5..a5d25e0 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -220,7 +220,7 @@
     }
 
     /**
-     * Gets information about how volume is handled on the session.
+     * Gets the information about how volume is handled on the session.
      *
      * @return {@link MediaRoute2Info#PLAYBACK_VOLUME_FIXED} or
      * {@link MediaRoute2Info#PLAYBACK_VOLUME_VARIABLE}.
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index e8f18a5..515d610 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -335,7 +335,7 @@
     if (mLinearBlockObj != NULL) {
         return mLinearBlockObj;
     }
-    mIonHandle = new C2HandleIon(mAvHandle->data[0], mDataLength);
+    mIonHandle = new C2HandleIon(dup(mAvHandle->data[0]), mDataLength);
     std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(mIonHandle);
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 0979627..ddefe26 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -126,6 +126,7 @@
         StubMediaRoute2ProviderService instance = StubMediaRoute2ProviderService.getInstance();
         if (instance != null) {
             instance.setProxy(null);
+            instance.setSpy(null);
         }
     }
 
@@ -425,6 +426,79 @@
 
     @Test
     @LargeTest
+    public void testTransferTwice() throws Exception {
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+        addRouterCallback(new RouteCallback() { });
+
+        CountDownLatch successLatch1 = new CountDownLatch(1);
+        CountDownLatch successLatch2 = new CountDownLatch(1);
+        CountDownLatch failureLatch = new CountDownLatch(1);
+        CountDownLatch managerOnSessionReleasedLatch = new CountDownLatch(1);
+        CountDownLatch serviceOnReleaseSessionLatch = new CountDownLatch(1);
+        List<RoutingSessionInfo> sessions = new ArrayList<>();
+
+        StubMediaRoute2ProviderService instance = StubMediaRoute2ProviderService.getInstance();
+        assertNotNull(instance);
+        instance.setSpy(new StubMediaRoute2ProviderService.Spy() {
+            @Override
+            public void onReleaseSession(long requestId, String sessionId) {
+                serviceOnReleaseSessionLatch.countDown();
+            }
+        });
+
+        addManagerCallback(new MediaRouter2Manager.Callback() {
+            @Override
+            public void onTransferred(RoutingSessionInfo oldSession,
+                    RoutingSessionInfo newSession) {
+                sessions.add(newSession);
+                if (successLatch1.getCount() > 0) {
+                    successLatch1.countDown();
+                } else {
+                    successLatch2.countDown();
+                }
+            }
+
+            @Override
+            public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) {
+                failureLatch.countDown();
+            }
+
+            @Override
+            public void onSessionReleased(RoutingSessionInfo session) {
+                managerOnSessionReleasedLatch.countDown();
+            }
+        });
+
+        MediaRoute2Info route1 = routes.get(ROUTE_ID1);
+        MediaRoute2Info route2 = routes.get(ROUTE_ID2);
+        assertNotNull(route1);
+        assertNotNull(route2);
+
+        mManager.selectRoute(mPackageName, route1);
+        assertTrue(successLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        mManager.selectRoute(mPackageName, route2);
+        assertTrue(successLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        // onTransferFailed/onSessionReleased should not be called.
+        assertFalse(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertFalse(managerOnSessionReleasedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+        assertEquals(2, sessions.size());
+        List<String> activeSessionIds = mManager.getActiveSessions().stream()
+                .map(RoutingSessionInfo::getId)
+                .collect(Collectors.toList());
+        // The old session shouldn't appear on the active session list.
+        assertFalse(activeSessionIds.contains(sessions.get(0).getId()));
+        assertTrue(activeSessionIds.contains(sessions.get(1).getId()));
+
+        assertFalse(serviceOnReleaseSessionLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        mManager.releaseSession(sessions.get(0));
+        assertTrue(serviceOnReleaseSessionLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertFalse(managerOnSessionReleasedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    @LargeTest
     public void testTransfer_ignored_fails() throws Exception {
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         addRouterCallback(new RouteCallback() {});
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
index 4551876..a51e371 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
@@ -79,6 +79,7 @@
     @GuardedBy("sLock")
     private static StubMediaRoute2ProviderService sInstance;
     private Proxy mProxy;
+    private Spy mSpy;
 
     private void initializeRoutes() {
         MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
@@ -256,6 +257,11 @@
 
     @Override
     public void onReleaseSession(long requestId, String sessionId) {
+        Spy spy = mSpy;
+        if (spy != null) {
+            spy.onReleaseSession(requestId, sessionId);
+        }
+
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         if (sessionInfo == null) {
             return;
@@ -375,7 +381,21 @@
         mProxy = proxy;
     }
 
+    public void setSpy(@Nullable Spy spy) {
+        mSpy = spy;
+    }
+
+    /**
+     * It overrides the original service
+     */
     public static class Proxy {
         public void onSetRouteVolume(String routeId, int volume, long requestId) {}
     }
+
+    /**
+     * It gets notified but doesn't prevent the original methods to be called.
+     */
+    public static class Spy {
+        public void onReleaseSession(long requestId, String sessionId) {}
+    }
 }
diff --git a/packages/SettingsLib/AdaptiveIcon/res/values-night/colors.xml b/packages/SettingsLib/AdaptiveIcon/res/values-night/colors.xml
new file mode 100644
index 0000000..f985c1e2
--- /dev/null
+++ b/packages/SettingsLib/AdaptiveIcon/res/values-night/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <color name="advanced_outline_color">#FFFFFFFF</color> <!-- icon outline color -->
+</resources>
diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index 46f79de..ae7f44d 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -69,7 +69,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:gravity="center_vertical"
-                android:text="See other apps"
+                android:text="@string/controls_favorite_see_other_apps"
                 style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
                 app:layout_constraintTop_toTopOf="parent"
                 app:layout_constraintBottom_toBottomOf="parent"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0e3fa1e..db45a60 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2744,6 +2744,9 @@
     <!-- Controls management favorites screen, See other apps with changes made [CHAR LIMIT=NONE] -->
     <string name="controls_favorite_toast_no_changes">Changes not saved</string>
 
+    <!-- Controls management favorites screen. See other apps button [CHAR LIMIT=30] -->
+    <string name="controls_favorite_see_other_apps">See other apps</string>
+
     <!-- Controls management controls screen error on load message [CHAR LIMIT=NONE] -->
     <string name="controls_favorite_load_error">Controls could not be loaded. Check the <xliff:g id="app" example="System UI">%s</xliff:g> app to make sure that the app settings haven\u2019t changed.</string>
     <!-- Controls management controls screen no controls found on load message [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index a8bbdf6..b615885 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -71,6 +71,7 @@
     // Items that are typically loaded later
     private String mAppName;
     private ShortcutInfo mShortcutInfo;
+    private String mMetadataShortcutId;
     private BadgedImageView mIconView;
     private BubbleExpandedView mExpandedView;
 
@@ -218,6 +219,14 @@
         return mTitle;
     }
 
+    String getMetadataShortcutId() {
+        return mMetadataShortcutId;
+    }
+
+    boolean hasMetadataShortcutId() {
+        return (mMetadataShortcutId != null && !mMetadataShortcutId.isEmpty());
+    }
+
     /**
      * Call when the views should be removed, ensure this is called to clean up ActivityView
      * content.
@@ -350,9 +359,9 @@
         mAppUid = entry.getSbn().getUid();
         mInstanceId = entry.getSbn().getInstanceId();
         mFlyoutMessage = BubbleViewInfoTask.extractFlyoutMessage(entry);
-        mShortcutInfo = (entry.getBubbleMetadata() != null
-                && entry.getBubbleMetadata().getShortcutId() != null
-                && entry.getRanking() != null) ? entry.getRanking().getShortcutInfo() : null;
+        mShortcutInfo = (entry.getRanking() != null ? entry.getRanking().getShortcutInfo() : null);
+        mMetadataShortcutId = (entry.getBubbleMetadata() != null
+                ? entry.getBubbleMetadata().getShortcutId() : null);
         if (entry.getRanking() != null) {
             mIsVisuallyInterruptive = entry.getRanking().visuallyInterruptive();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index aa41719..ccfbd8f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -483,12 +483,13 @@
     }
 
     /**
-     * Dispatches a back press into the expanded Bubble's ActivityView if its IME is visible,
-     * causing it to hide.
+     * Hides the current input method, wherever it may be focused, via InputMethodManagerInternal.
      */
-    public void hideImeFromExpandedBubble() {
-        if (mStackView != null) {
-            mStackView.hideImeFromExpandedBubble();
+    public void hideCurrentInputMethod() {
+        try {
+            mBarService.hideCurrentInputMethodForBubbles();
+        } catch (RemoteException e) {
+            e.printStackTrace();
         }
     }
 
@@ -693,8 +694,8 @@
         if (mStackView == null) {
             mStackView = new BubbleStackView(
                     mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
-                    mSysUiState, this::onAllBubblesAnimatedOut,
-                    this::onImeVisibilityChanged);
+                    mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
+                    this::hideCurrentInputMethod);
             mStackView.addView(mBubbleScrim);
             if (mExpandListener != null) {
                 mStackView.setExpandListener(mExpandListener);
@@ -1589,7 +1590,11 @@
         @Override
         public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
             if (mStackView != null && taskInfo.displayId == getExpandedDisplayId(mContext)) {
-                mBubbleData.setExpanded(false);
+                if (mImeVisible) {
+                    hideCurrentInputMethod();
+                } else {
+                    mBubbleData.setExpanded(false);
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 7020f1c..acbde9f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -366,11 +366,15 @@
             validShortcutIds.add(info.getId());
         }
 
-        final Predicate<Bubble> invalidBubblesFromPackage = bubble ->
-                packageName.equals(bubble.getPackageName())
-                        && (bubble.getShortcutInfo() == null
-                            || !bubble.getShortcutInfo().isEnabled()
-                            || !validShortcutIds.contains(bubble.getShortcutInfo().getId()));
+        final Predicate<Bubble> invalidBubblesFromPackage = bubble -> {
+            final boolean bubbleIsFromPackage = packageName.equals(bubble.getPackageName());
+            final boolean hasShortcutIdAndValidShortcut =
+                    bubble.hasMetadataShortcutId()
+                            && bubble.getShortcutInfo() != null
+                            && bubble.getShortcutInfo().isEnabled()
+                            && validShortcutIds.contains(bubble.getShortcutInfo().getId());
+            return bubbleIsFromPackage && !hasShortcutIdAndValidShortcut;
+        };
 
         final Consumer<Bubble> removeBubble = bubble ->
                 dismissBubbleWithKey(bubble.getKey(), reason);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
index 390f706..db64a13 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -77,7 +77,7 @@
             BubbleEntity(
                     userId,
                     b.packageName,
-                    b.shortcutInfo?.id ?: return@mapNotNull null,
+                    b.metadataShortcutId ?: return@mapNotNull null,
                     b.key,
                     b.rawDesiredHeight,
                     b.rawDesiredHeightResId,
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 7c3e027..b34312e2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -173,7 +173,8 @@
                             return;
                         }
                         try {
-                            if (!mIsOverflow && mBubble.getShortcutInfo() != null) {
+                            if (!mIsOverflow && mBubble.hasMetadataShortcutId()
+                                    && mBubble.getShortcutInfo() != null) {
                                 options.setApplyActivityFlagsForBubbles(true);
                                 mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
                                         options, null /* sourceBounds */);
@@ -465,7 +466,6 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        hideImeIfVisible();
         mKeyboardVisible = false;
         mNeedsNewHeight = false;
         if (mActivityView != null) {
@@ -616,7 +616,7 @@
 
             if (isNew) {
                 mPendingIntent = mBubble.getBubbleIntent();
-                if (mPendingIntent != null || mBubble.getShortcutInfo() != null) {
+                if (mPendingIntent != null || mBubble.hasMetadataShortcutId()) {
                     setContentVisibility(false);
                     mActivityView.setVisibility(VISIBLE);
                 }
@@ -788,7 +788,7 @@
     }
 
     private boolean usingActivityView() {
-        return (mPendingIntent != null || mBubble.getShortcutInfo() != null)
+        return (mPendingIntent != null || mBubble.hasMetadataShortcutId())
                 && mActivityView != null;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index a888bd5..ffb650d6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -70,9 +70,6 @@
 
     private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
 
-    private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow";
-    private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = true;
-
     /**
      * When true, if a notification has the information necessary to bubble (i.e. valid
      * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
@@ -87,15 +84,6 @@
     }
 
     /**
-     * When true, show a menu with dismissed and aged-out bubbles.
-     */
-    static boolean allowBubbleOverflow(Context context) {
-        return Settings.Secure.getInt(context.getContentResolver(),
-                ALLOW_BUBBLE_OVERFLOW,
-                ALLOW_BUBBLE_OVERFLOW_DEFAULT ? 1 : 0) != 0;
-    }
-
-    /**
      * Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that
      * are using {@link Notification.MessagingStyle} and have remote input.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 50828e8..09e8799 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -384,6 +384,11 @@
     public final Consumer<Boolean> mOnImeVisibilityChanged;
 
     /**
+     * Callback to run to ask BubbleController to hide the current IME.
+     */
+    private final Runnable mHideCurrentInputMethodCallback;
+
+    /**
      * The currently magnetized object, which is being dragged and will be attracted to the magnetic
      * dismiss target.
      *
@@ -560,7 +565,7 @@
                         mMagneticTarget,
                         mIndividualBubbleMagnetListener);
 
-                hideImeFromExpandedBubble();
+                hideCurrentInputMethod();
 
                 // Save the magnetized individual bubble so we can dispatch touch events to it.
                 mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
@@ -732,7 +737,8 @@
             FloatingContentCoordinator floatingContentCoordinator,
             SysUiState sysUiState,
             Runnable allBubblesAnimatedOutAction,
-            Consumer<Boolean> onImeVisibilityChanged) {
+            Consumer<Boolean> onImeVisibilityChanged,
+            Runnable hideCurrentInputMethodCallback) {
         super(context);
 
         mBubbleData = data;
@@ -868,6 +874,7 @@
         setUpOverflow();
 
         mOnImeVisibilityChanged = onImeVisibilityChanged;
+        mHideCurrentInputMethodCallback = hideCurrentInputMethodCallback;
 
         setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
             onImeVisibilityChanged.accept(insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
@@ -1145,9 +1152,6 @@
     }
 
     private void setUpOverflow() {
-        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
-            return;
-        }
         int overflowBtnIndex = 0;
         if (mBubbleOverflow == null) {
             mBubbleOverflow = new BubbleOverflow(getContext());
@@ -1513,8 +1517,7 @@
     }
 
     private void updateOverflowVisibility() {
-        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)
-                || mBubbleOverflow == null) {
+        if (mBubbleOverflow == null) {
             return;
         }
         mBubbleOverflow.setVisible(mIsExpanded ? VISIBLE : GONE);
@@ -1593,6 +1596,8 @@
         updatePointerPosition();
 
         if (mIsExpanded) {
+            hideCurrentInputMethod();
+
             // Make the container of the expanded view transparent before removing the expanded view
             // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
             // expanded view becomes visible on the screen. See b/126856255
@@ -1601,11 +1606,6 @@
                 if (previouslySelected != null) {
                     previouslySelected.setContentVisibility(false);
                 }
-                if (previouslySelected != null && previouslySelected.getExpandedView() != null) {
-                    // Hide the currently expanded bubble's IME if it's visible before switching
-                    // to a new bubble.
-                    previouslySelected.getExpandedView().hideImeIfVisible();
-                }
 
                 updateExpandedBubble();
                 requestUpdate();
@@ -1633,6 +1633,8 @@
             return;
         }
 
+        hideCurrentInputMethod();
+
         mSysUiState
                 .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
                 .commitUpdate(mContext.getDisplayId());
@@ -1816,12 +1818,12 @@
         }
     }
 
-    void hideImeFromExpandedBubble() {
-        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-            // Hide the currently expanded bubble's IME if it's visible before switching to a new
-            // bubble.
-            mExpandedBubble.getExpandedView().hideImeIfVisible();
-        }
+    /**
+     * Asks the BubbleController to hide the IME from anywhere, whether it's focused on Bubbles or
+     * not.
+     */
+    void hideCurrentInputMethod() {
+        mHideCurrentInputMethodCallback.run();
     }
 
     private void beforeExpandedViewAnimation() {
@@ -1898,7 +1900,7 @@
                             AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
                             mScaleInSpringConfig)
                     .addUpdateListener((target, values) -> {
-                        if (mExpandedBubble.getIconView() == null) {
+                        if (mExpandedBubble == null || mExpandedBubble.getIconView() == null) {
                             return;
                         }
                         mExpandedViewContainerMatrix.postTranslate(
@@ -1938,10 +1940,6 @@
         mAnimatingOutSurfaceContainer.setScaleX(0f);
         mAnimatingOutSurfaceContainer.setScaleY(0f);
 
-        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-            mExpandedBubble.getExpandedView().hideImeIfVisible();
-        }
-
         // Let the expanded animation controller know that it shouldn't animate child adds/reorders
         // since we're about to animate collapsed.
         mExpandedAnimationController.notifyPreparingToCollapse();
@@ -2776,11 +2774,8 @@
      * @return the number of bubbles in the stack view.
      */
     public int getBubbleCount() {
-        if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
-            // Subtract 1 for the overflow button that is always in the bubble container.
-            return mBubbleContainer.getChildCount() - 1;
-        }
-        return mBubbleContainer.getChildCount();
+        // Subtract 1 for the overflow button that is always in the bubble container.
+        return mBubbleContainer.getChildCount() - 1;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
index ae78336..07acb71 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
@@ -134,4 +134,11 @@
     public float getPivotY() {
         return mPivotY;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        // Use object equality to allow this matrix to be used as a map key (which is required for
+        // PhysicsAnimator's animator caching).
+        return obj == this;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 416c81a..5052386 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -432,12 +432,13 @@
             }
         }
 
-        val resumeAction: Runnable? = mediaEntries.get(key)?.resumeAction
-        val hasCheckedForResume = mediaEntries.get(key)?.hasCheckedForResume == true
         foregroundExecutor.execute {
+            val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
+            val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
+            val active = mediaEntries[key]?.active ?: true
             onMediaDataLoaded(key, oldKey, MediaData(true, bgColor, app, smallIconDrawable, artist,
                     song, artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
-                    notif.contentIntent, null, active = true, resumeAction = resumeAction,
+                    notif.contentIntent, null, active, resumeAction = resumeAction,
                     notificationKey = key, hasCheckedForResume = hasCheckedForResume))
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index cf8a636..9a134db 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -71,6 +71,7 @@
     ) : MediaController.Callback() {
 
         var timedOut = false
+        private var playing: Boolean? = null
 
         // Resume controls may have null token
         private val mediaController = if (data.token != null) {
@@ -94,7 +95,13 @@
                 Log.v(TAG, "onPlaybackStateChanged: $state")
             }
 
-            if (state == null || !isPlayingState(state.state)) {
+            val isPlaying = state != null && isPlayingState(state.state)
+            if (playing == isPlaying && playing != null) {
+                return
+            }
+            playing = isPlaying
+
+            if (!isPlaying) {
                 if (DEBUG) {
                     Log.v(TAG, "schedule timeout for $key")
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 87faacc..795d062 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -14,8 +14,8 @@
 
 package com.android.systemui.qs.tileimpl;
 
-import static androidx.lifecycle.Lifecycle.State.DESTROYED;
 import static androidx.lifecycle.Lifecycle.State.RESUMED;
+import static androidx.lifecycle.Lifecycle.State.STARTED;
 
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
@@ -432,17 +432,19 @@
     }
 
     private void handleSetListeningInternal(Object listener, boolean listening) {
+        // This should be used to go from resumed to paused. Listening for ON_RESUME and ON_PAUSE
+        // in this lifecycle will determine the listening window.
         if (listening) {
             if (mListeners.add(listener) && mListeners.size() == 1) {
                 if (DEBUG) Log.d(TAG, "handleSetListening true");
-                mLifecycle.markState(RESUMED);
+                mLifecycle.setCurrentState(RESUMED);
                 handleSetListening(listening);
                 refreshState(); // Ensure we get at least one refresh after listening.
             }
         } else {
             if (mListeners.remove(listener) && mListeners.size() == 0) {
                 if (DEBUG) Log.d(TAG, "handleSetListening false");
-                mLifecycle.markState(DESTROYED);
+                mLifecycle.setCurrentState(STARTED);
                 handleSetListening(listening);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index ad31220..8a38199 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -253,7 +253,9 @@
             mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
             mRotateSplitLayout = null;
         }
-        update(newConfig);
+        if (isSplitActive()) {
+            update(newConfig);
+        }
     }
 
     Handler getHandler() {
@@ -328,11 +330,6 @@
         mHandler.post(this::removeDivider);
     }
 
-    void onTasksReady() {
-        mHandler.post(() -> update(mDisplayController.getDisplayContext(
-                mContext.getDisplayId()).getResources().getConfiguration()));
-    }
-
     private void updateVisibility(final boolean visible) {
         if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
         if (mVisible != visible) {
@@ -534,7 +531,7 @@
 
     void ensureMinimizedSplit() {
         setHomeMinimized(true /* minimized */, mHomeStackResizable);
-        if (!isDividerVisible()) {
+        if (mView != null && !isDividerVisible()) {
             // Wasn't in split-mode yet, so enter now.
             if (DEBUG) {
                 Slog.d(TAG, " entering split mode with minimized=true");
@@ -545,7 +542,7 @@
 
     void ensureNormalSplit() {
         setHomeMinimized(false /* minimized */, mHomeStackResizable);
-        if (!isDividerVisible()) {
+        if (mView != null && !isDividerVisible()) {
             // Wasn't in split-mode, so enter now.
             if (DEBUG) {
                 Slog.d(TAG, " enter split mode unminimized ");
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 6751e8d..4a2cad7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -113,8 +113,6 @@
                 t.setColor(mSecondaryDim, new float[]{0f, 0f, 0f});
                 t.apply();
                 releaseTransaction(t);
-
-                mDivider.onTasksReady();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 5926a5b..304fe00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -121,6 +121,8 @@
 
     private final Context mContext;
     private final OverviewProxyService mOverviewProxyService;
+    private final Runnable mStateChangeCallback;
+
     private final PluginManager mPluginManager;
     // Activities which should not trigger Back gesture.
     private final List<ComponentName> mGestureBlockingActivities = new ArrayList<>();
@@ -196,13 +198,15 @@
             };
 
     public EdgeBackGestureHandler(Context context, OverviewProxyService overviewProxyService,
-            SysUiState sysUiFlagContainer, PluginManager pluginManager) {
+            SysUiState sysUiFlagContainer, PluginManager pluginManager,
+            Runnable stateChangeCallback) {
         super(Dependency.get(BroadcastDispatcher.class));
         mContext = context;
         mDisplayId = context.getDisplayId();
         mMainExecutor = context.getMainExecutor();
         mOverviewProxyService = overviewProxyService;
         mPluginManager = pluginManager;
+        mStateChangeCallback = stateChangeCallback;
         ComponentName recentsComponentName = ComponentName.unflattenFromString(
                 context.getString(com.android.internal.R.string.config_recentsComponentName));
         if (recentsComponentName != null) {
@@ -226,13 +230,13 @@
                 Log.e(TAG, "Failed to add gesture blocking activities", e);
             }
         }
-        Dependency.get(ProtoTracer.class).add(this);
 
+        Dependency.get(ProtoTracer.class).add(this);
         mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
                 ViewConfiguration.getLongPressTimeout());
 
         mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(
-                mContext.getMainThreadHandler(), mContext, this::updateCurrentUserResources);
+                mContext.getMainThreadHandler(), mContext, this::onNavigationSettingsChanged);
 
         updateCurrentUserResources();
         sysUiFlagContainer.addCallback(sysUiFlags -> mSysUiFlags = sysUiFlags);
@@ -263,6 +267,14 @@
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop() * backGestureSlop;
     }
 
+    private void onNavigationSettingsChanged() {
+        boolean wasBackAllowed = isHandlingGestures();
+        updateCurrentUserResources();
+        if (wasBackAllowed != isHandlingGestures()) {
+            mStateChangeCallback.run();
+        }
+    }
+
     @Override
     public void onUserSwitched(int newUserId) {
         updateIsEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 063305e..27daf86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -25,6 +25,7 @@
 import static android.view.InsetsState.containsType;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
@@ -219,12 +220,13 @@
      * original handle hidden and we'll flip the visibilities once the
      * {@link #mTasksFrozenListener} fires
      */
-    private VerticalNavigationHandle mOrientationHandle;
+    private QuickswitchOrientedNavHandle mOrientationHandle;
     private WindowManager.LayoutParams mOrientationParams;
     private int mStartingQuickSwitchRotation = -1;
     private int mCurrentRotation;
     private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener;
     private UiEventLogger mUiEventLogger;
+    private boolean mShowOrientedHandleForImmersiveMode;
 
     @com.android.internal.annotations.VisibleForTesting
     public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
@@ -296,6 +298,9 @@
         @Override
         public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
             mStartingQuickSwitchRotation = rotation;
+            if (rotation == -1) {
+                mShowOrientedHandleForImmersiveMode = false;
+            }
             orientSecondaryHomeHandle();
         }
 
@@ -585,7 +590,7 @@
         getContext().getSystemService(DisplayManager.class)
                 .registerDisplayListener(this, new Handler(Looper.getMainLooper()));
 
-        mOrientationHandle = new VerticalNavigationHandle(getContext());
+        mOrientationHandle = new QuickswitchOrientedNavHandle(getContext());
 
         getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener);
         mOrientationParams = new WindowManager.LayoutParams(0, 0,
@@ -596,8 +601,11 @@
                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                         | WindowManager.LayoutParams.FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
+        mOrientationParams.setTitle("SecondaryHomeHandle" + getContext().getDisplayId());
+        mOrientationParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
         mWindowManager.addView(mOrientationHandle, mOrientationParams);
         mOrientationHandle.setVisibility(View.GONE);
+        mOrientationParams.setFitInsetsTypes(0 /* types*/);
         mOrientationHandleGlobalLayoutListener =
                 () -> {
                     if (mStartingQuickSwitchRotation == -1) {
@@ -634,22 +642,28 @@
             int height = 0;
             int width = 0;
             Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
+            mOrientationHandle.setDeltaRotation(deltaRotation);
             switch (deltaRotation) {
                 case Surface.ROTATION_90:
                 case Surface.ROTATION_270:
                     height = dispSize.height();
-                    width = getResources()
-                            .getDimensionPixelSize(R.dimen.navigation_bar_height);
+                    width = mNavigationBarView.getHeight();
                     break;
                 case Surface.ROTATION_180:
                 case Surface.ROTATION_0:
                     // TODO(b/152683657): Need to determine best UX for this
-                    resetSecondaryHandle();
-                    return;
+                    if (!mShowOrientedHandleForImmersiveMode) {
+                        resetSecondaryHandle();
+                        return;
+                    }
+                    width = dispSize.width();
+                    height = mNavigationBarView.getHeight();
+                    break;
             }
 
             mOrientationParams.gravity =
-                    deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT;
+                    deltaRotation == Surface.ROTATION_0 ? Gravity.BOTTOM :
+                            (deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT);
             mOrientationParams.height = height;
             mOrientationParams.width = width;
             mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
@@ -743,6 +757,11 @@
                 && mNavigationBarWindowState != state) {
             mNavigationBarWindowState = state;
             updateSystemUiStateFlags(-1);
+            mShowOrientedHandleForImmersiveMode = state == WINDOW_STATE_HIDDEN;
+            if (mOrientationHandle != null
+                    && mStartingQuickSwitchRotation != -1) {
+                orientSecondaryHomeHandle();
+            }
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
 
             if (mNavigationBarView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index dbff643..1eab427 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -326,8 +326,8 @@
 
         mNavColorSampleMargin = getResources()
                         .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
-        mEdgeBackGestureHandler = new EdgeBackGestureHandler(
-                context, mOverviewProxyService, mSysUiFlagContainer, mPluginManager);
+        mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService,
+                mSysUiFlagContainer, mPluginManager, this::updateStates);
         mRegionSamplingHelper = new RegionSamplingHelper(this,
                 new RegionSamplingHelper.SamplingCallback() {
                     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java
new file mode 100644
index 0000000..fe74677
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.view.Surface;
+
+import com.android.systemui.R;
+
+/** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
+public class QuickswitchOrientedNavHandle extends NavigationHandle {
+    private final int mWidth;
+    private final RectF mTmpBoundsRectF = new RectF();
+    private @Surface.Rotation int mDeltaRotation;
+
+    public QuickswitchOrientedNavHandle(Context context) {
+        super(context);
+        mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width);
+    }
+
+    void setDeltaRotation(@Surface.Rotation int rotation) {
+        mDeltaRotation = rotation;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        canvas.drawRoundRect(computeHomeHandleBounds(), mRadius, mRadius, mPaint);
+    }
+
+    RectF computeHomeHandleBounds() {
+        int left;
+        int top;
+        int bottom;
+        int right;
+        int radiusOffset = mRadius * 2;
+        int topStart = getLocationOnScreen()[1];
+
+        switch (mDeltaRotation) {
+            default:
+            case Surface.ROTATION_0:
+            case Surface.ROTATION_180:
+                int height = mRadius * 2;
+                left = getWidth() / 2 - mWidth / 2;
+                top = (getHeight() - mBottom - height);
+                right = getWidth() / 2 + mWidth / 2;
+                bottom = top + height;
+                break;
+            case Surface.ROTATION_90:
+                left = mBottom;
+                right = left + radiusOffset;
+                top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
+                bottom = top + mWidth;
+                break;
+            case Surface.ROTATION_270:
+                right = getWidth() - mBottom;
+                left = right - radiusOffset;
+                top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
+                bottom = top + mWidth;
+                break;
+        }
+        mTmpBoundsRectF.set(left, top, right, bottom);
+        return mTmpBoundsRectF;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
deleted file mode 100644
index 0cdf1d3..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.RectF;
-
-import com.android.systemui.R;
-
-/** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
-public class VerticalNavigationHandle extends NavigationHandle {
-    private final int mWidth;
-    private final RectF mTmpBoundsRectF = new RectF();
-
-    public VerticalNavigationHandle(Context context) {
-        super(context);
-        mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        canvas.drawRoundRect(computeHomeHandleBounds(), mRadius, mRadius, mPaint);
-    }
-
-    RectF computeHomeHandleBounds() {
-        int left;
-        int top;
-        int bottom;
-        int right;
-        int topStart = getLocationOnScreen()[1];
-        int radiusOffset = mRadius * 2;
-        right = getWidth() - mBottom;
-        top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
-        left = getWidth() - mBottom - radiusOffset;
-        bottom = top + mWidth;
-        mTmpBoundsRectF.set(left, top, right, bottom);
-        return mTmpBoundsRectF;
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
index 8b254e3..58959c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
@@ -18,6 +18,7 @@
 
 import static android.view.WindowInsets.Type.ime;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -39,6 +40,7 @@
 
 import com.android.systemui.SysuiTestCase;
 
+import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -52,6 +54,11 @@
     public ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(
             TestActivity.class, false, false);
 
+    @After
+    public void tearDown() {
+        executeShellCommand("input keyevent HOME");
+    }
+
     /**
      * This test verifies that GlobalActions, which is frequently used to capture bugreports,
      * doesn't interfere with the IME, i.e. soft-keyboard state.
@@ -68,6 +75,9 @@
             waitUntil("Ime is not visible", activity::isImeVisible);
         }
 
+        // In some cases, IME is not controllable. e.g., floating IME or fullscreen IME.
+        final boolean activityControlledIme = activity.mControlsIme;
+
         executeShellCommand("input keyevent --longpress POWER");
 
         waitUntil("activity loses focus", () -> !activity.mHasFocus);
@@ -77,9 +87,9 @@
 
         runAssertionOnMainThread(() -> {
             assertTrue("IME should remain visible behind GlobalActions, but didn't",
-                    activity.mControlsIme);
-            assertTrue("App behind GlobalActions should remain in control of IME, but didn't",
                     activity.mImeVisible);
+            assertEquals("App behind GlobalActions should remain in control of IME, but didn't",
+                    activityControlledIme, activity.mControlsIme);
         });
     }
 
@@ -181,7 +191,7 @@
         }
 
         boolean isImeVisible() {
-            return mHasFocus && mControlsIme && mImeVisible;
+            return mHasFocus && mImeVisible;
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 20a6da5..e56bbabfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -15,6 +15,7 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.SbnBuilder
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
@@ -26,8 +27,8 @@
 import org.mockito.Mockito
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
 
 private const val KEY = "KEY"
 private const val PACKAGE_NAME = "com.android.systemui"
@@ -35,7 +36,6 @@
 private const val SESSION_ARTIST = "artist"
 private const val SESSION_TITLE = "title"
 
-private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
 private fun <T> anyObject(): T {
     return Mockito.anyObject<T>()
 }
@@ -104,6 +104,19 @@
     }
 
     @Test
+    fun testOnSwipeToDismiss_deactivatesMedia() {
+        val data = MediaData(initialized = true, backgroundColor = 0, app = null, appIcon = null,
+                artist = null, song = null, artwork = null, actions = emptyList(),
+                actionsToShowInCompact = emptyList(), packageName = "INVALID", token = null,
+                clickIntent = null, device = null, active = true, resumeAction = null)
+        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+        mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = data)
+
+        mediaDataManager.onSwipeToDismiss()
+        assertThat(data.active).isFalse()
+    }
+
+    @Test
     fun testLoadsMetadataOnBackground() {
         mediaDataManager.onNotificationAdded(KEY, mediaNotification)
         assertThat(backgroundExecutor.numPending()).isEqualTo(1)
@@ -119,6 +132,30 @@
     }
 
     @Test
+    fun testOnMetaDataLoaded_conservesActiveFlag() {
+        val listener = TestListener()
+        whenever(mediaControllerFactory.create(anyObject())).thenReturn(controller)
+        whenever(controller.metadata).thenReturn(metadataBuilder.build())
+        mediaDataManager.addListener(listener)
+        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+        assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+        assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+        assertThat(listener.data!!.active).isTrue()
+
+        // Swiping away makes the notification not active
+        mediaDataManager.onSwipeToDismiss()
+        assertThat(mediaDataManager.hasActiveMedia()).isFalse()
+
+        // And when a notification is updated
+        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+        assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+        assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+
+        // MediaData should still be inactive
+        assertThat(mediaDataManager.hasActiveMedia()).isFalse()
+    }
+
+    @Test
     fun testHasAnyMedia_whenAddingMedia() {
         assertThat(mediaDataManager.hasAnyMedia()).isFalse()
         val data = mock(MediaData::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 1c0d451..438de99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -14,6 +14,10 @@
 
 package com.android.systemui.qs.tileimpl;
 
+
+import static androidx.lifecycle.Lifecycle.State.DESTROYED;
+import static androidx.lifecycle.Lifecycle.State.RESUMED;
+
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
@@ -23,6 +27,9 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -267,6 +274,42 @@
         verify(mQsLogger).logTileChangeListening(SPEC, false);
     }
 
+    @Test
+    public void testListeningTrue_stateAtLeastResumed() {
+        mTile.setListening(new Object(), true); // Listen with some object
+
+        TestableLooper.get(this).processAllMessages();
+
+        assertTrue(mTile.getLifecycle().getCurrentState().isAtLeast(RESUMED));
+    }
+
+    @Test
+    public void testTileDoesntStartResumed() {
+        assertFalse(mTile.getLifecycle().getCurrentState().isAtLeast(RESUMED));
+    }
+
+    @Test
+    public void testListeningFalse_stateAtMostCreated() {
+        Object o = new Object();
+        mTile.setListening(o, true);
+
+        mTile.setListening(o, false);
+
+        TestableLooper.get(this).processAllMessages();
+        assertFalse(mTile.getLifecycle().getCurrentState().isAtLeast(RESUMED));
+    }
+
+    @Test
+    public void testListeningFalse_stateNotDestroyed() {
+        Object o = new Object();
+        mTile.setListening(o, true);
+
+        mTile.setListening(o, false);
+
+        TestableLooper.get(this).processAllMessages();
+        assertNotEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
+    }
+
     private void assertEvent(UiEventLogger.UiEventEnum eventType,
             UiEventLoggerFake.FakeUiEvent fakeEvent) {
         assertEquals(eventType.getId(), fakeEvent.eventId);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index cc095a0..4f053cb 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -171,6 +171,14 @@
      */
     public static final int TETHERING_ETHERNET = 5;
 
+    /**
+     * WIGIG tethering type. Use a separate type to prevent
+     * conflicts with TETHERING_WIFI
+     * This type is only used internally by the tethering module
+     * @hide
+     */
+    public static final int TETHERING_WIGIG = 6;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 9269c6f..9b9dcde 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -43,6 +43,13 @@
     </string-array>
 
     <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         WiGig interfaces.  If the device doesn't want to support tethering over WiGig this
+         should be empty.  An example would be "wigig\\d" -->
+    <string-array translatable="false" name="config_tether_wigig_regexs">
+        <item>"wigig\\d"</item>
+    </string-array>
+
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
          Wifi P2P interfaces.  If the device doesn't want to support tethering over Wifi P2p this
          should be empty.  An example would be "p2p-p2p\\d-.*" -->
     <string-array translatable="false" name="config_tether_wifi_p2p_regexs">
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index 4e2bb1e..6a33d55 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -20,6 +20,7 @@
             <item type="array" name="config_tether_usb_regexs"/>
             <item type="array" name="config_tether_ncm_regexs" />
             <item type="array" name="config_tether_wifi_regexs"/>
+            <item type="array" name="config_tether_wigig_regexs"/>
             <item type="array" name="config_tether_wifi_p2p_regexs"/>
             <item type="array" name="config_tether_bluetooth_regexs"/>
             <item type="array" name="config_tether_dhcp_range"/>
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 35c1563..8af1797 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -617,7 +617,8 @@
         final Boolean setIfaceUp;
         if (mInterfaceType == TetheringManager.TETHERING_WIFI
                 || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P
-                || mInterfaceType == TetheringManager.TETHERING_ETHERNET) {
+                || mInterfaceType == TetheringManager.TETHERING_ETHERNET
+                || mInterfaceType == TetheringManager.TETHERING_WIGIG) {
             // The WiFi and Ethernet stack has ownership of the interface up/down state.
             // It is unclear whether the Bluetooth or USB stacks will manage their own
             // state.
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index fe92204..33b9d00 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -16,8 +16,11 @@
 
 package com.android.networkstack.tethering;
 
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
 import static android.net.util.TetheringUtils.uint16;
 
+import android.annotation.NonNull;
 import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
 import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
 import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
@@ -25,6 +28,7 @@
 import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
 import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
 import android.net.netlink.NetlinkSocket;
+import android.net.netlink.StructNlMsgHdr;
 import android.net.util.SharedLog;
 import android.net.util.SocketUtils;
 import android.os.Handler;
@@ -37,9 +41,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
 import java.io.IOException;
 import java.net.SocketAddress;
 import java.net.SocketException;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.NoSuchElementException;
 
@@ -63,6 +69,11 @@
     private static final int NF_NETLINK_CONNTRACK_NEW = 1;
     private static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
     private static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
+    // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
+    public static final short NFNL_SUBSYS_CTNETLINK = 1;
+    public static final short IPCTNL_MSG_CT_GET = 1;
+
+    private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
 
     private final Handler mHandler;
     private final SharedLog mLog;
@@ -226,6 +237,9 @@
                 NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
         if (h1 == null) return false;
 
+        sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
+                           (short) (NLM_F_REQUEST | NLM_F_DUMP));
+
         final NativeHandle h2 = mDeps.createConntrackSocket(
                 NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
         if (h2 == null) {
@@ -252,6 +266,25 @@
         return results.mSuccess;
     }
 
+    @VisibleForTesting
+    public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) {
+        final int length = StructNlMsgHdr.STRUCT_SIZE;
+        final byte[] msg = new byte[length];
+        final StructNlMsgHdr nlh = new StructNlMsgHdr();
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
+        nlh.nlmsg_len = length;
+        nlh.nlmsg_type = type;
+        nlh.nlmsg_flags = flags;
+        nlh.nlmsg_seq = 1;
+        nlh.pack(byteBuffer);
+        try {
+            NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
+                                      NETLINK_MESSAGE_TIMEOUT_MS);
+        } catch (ErrnoException | InterruptedIOException e) {
+            mLog.e("Unable to send netfilter message, error: " + e);
+        }
+    }
+
     private void closeFdInNativeHandle(final NativeHandle h) {
         try {
             h.close();
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index c72ac52..3695ec6 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -40,6 +40,7 @@
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.TetheringManager.TETHERING_WIGIG;
 import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
@@ -495,7 +496,8 @@
             if (up) {
                 maybeTrackNewInterfaceLocked(iface);
             } else {
-                if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
+                if (ifaceNameToType(iface) == TETHERING_BLUETOOTH
+                        || ifaceNameToType(iface) == TETHERING_WIGIG) {
                     stopTrackingInterfaceLocked(iface);
                 } else {
                     // Ignore usb0 down after enabling RNDIS.
@@ -517,6 +519,8 @@
 
         if (cfg.isWifi(iface)) {
             return TETHERING_WIFI;
+        } else if (cfg.isWigig(iface)) {
+            return TETHERING_WIGIG;
         } else if (cfg.isWifiP2p(iface)) {
             return TETHERING_WIFI_P2P;
         } else if (cfg.isUsb(iface)) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index 18b2b78..e1771a5 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -92,6 +92,7 @@
 
     public final String[] tetherableUsbRegexs;
     public final String[] tetherableWifiRegexs;
+    public final String[] tetherableWigigRegexs;
     public final String[] tetherableWifiP2pRegexs;
     public final String[] tetherableBluetoothRegexs;
     public final String[] tetherableNcmRegexs;
@@ -125,6 +126,7 @@
         // us an interface name. Careful consideration needs to be given to
         // implications for Settings and for provisioning checks.
         tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs);
+        tetherableWigigRegexs = getResourceStringArray(res, R.array.config_tether_wigig_regexs);
         tetherableWifiP2pRegexs = getResourceStringArray(
                 res, R.array.config_tether_wifi_p2p_regexs);
         tetherableBluetoothRegexs = getResourceStringArray(
@@ -167,6 +169,11 @@
         return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
     }
 
+    /** Check whether input interface belong to wigig.*/
+    public boolean isWigig(String iface) {
+        return matchesDownstreamRegexs(iface, tetherableWigigRegexs);
+    }
+
     /** Check whether this interface is Wifi P2P interface. */
     public boolean isWifiP2p(String iface) {
         return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
index f8ff1cb..c543fad 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -17,13 +17,17 @@
 package com.android.networkstack.tethering;
 
 import static android.net.util.TetheringUtils.uint16;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.AF_UNIX;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
 import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
@@ -31,11 +35,14 @@
 import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
 import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
 import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
+import android.net.netlink.StructNlMsgHdr;
 import android.net.util.SharedLog;
 import android.os.Handler;
 import android.os.NativeHandle;
 import android.os.test.TestLooper;
+import android.system.ErrnoException;
 import android.system.OsConstants;
+import android.system.Os;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -47,6 +54,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.FileDescriptor;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
 @RunWith(AndroidJUnit4.class)
@@ -64,6 +74,10 @@
     @Mock private IOffloadControl mIOffloadControl;
     @Mock private NativeHandle mNativeHandle;
 
+    // Random values to test Netlink message.
+    private static final short TEST_TYPE = 184;
+    private static final short TEST_FLAGS = 263;
+
     class MyDependencies extends OffloadHardwareInterface.Dependencies {
         MyDependencies(SharedLog log) {
             super(log);
@@ -203,6 +217,31 @@
                 eq(uint16(udpParams.dst.port)));
     }
 
+    @Test
+    public void testNetlinkMessage() throws Exception {
+        FileDescriptor writeSocket = new FileDescriptor();
+        FileDescriptor readSocket = new FileDescriptor();
+        try {
+            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, writeSocket, readSocket);
+        } catch (ErrnoException e) {
+            fail();
+            return;
+        }
+        when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
+
+        mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS);
+
+        ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE);
+        int read = Os.read(readSocket, buffer);
+
+        buffer.flip();
+        assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
+        assertEquals(TEST_TYPE, buffer.getShort());
+        assertEquals(TEST_FLAGS, buffer.getShort());
+        assertEquals(1 /* seq */, buffer.getInt());
+        assertEquals(0 /* pid */, buffer.getInt());
+    }
+
     private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
         final NatTimeoutUpdate params = new NatTimeoutUpdate();
         params.proto = proto;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7f912a4..d2b1bd1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -56,6 +56,8 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.database.ContentObserver;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.fingerprint.IFingerprintService;
@@ -190,6 +192,9 @@
     private final SimpleStringSplitter mStringColonSplitter =
             new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
 
+    private final Rect mTempRect = new Rect();
+    private final Rect mTempRect1 = new Rect();
+
     private final PackageManager mPackageManager;
 
     private final PowerManager mPowerManager;
@@ -246,6 +251,7 @@
     //TODO: Remove this hack
     private boolean mInitialized;
 
+    private Point mTempPoint;
     private boolean mIsAccessibilityButtonShown;
 
     private AccessibilityUserState getCurrentUserStateLocked() {
@@ -1068,6 +1074,18 @@
     }
 
     /**
+     * Gets a point within the accessibility focused node where we can send down
+     * and up events to perform a click.
+     *
+     * @param outPoint The click point to populate.
+     * @return Whether accessibility a click point was found and set.
+     */
+    // TODO: (multi-display) Make sure this works for multiple displays.
+    public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
+        return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
+    }
+
+    /**
      * Perform an accessibility action on the view that currently has accessibility focus.
      * Has no effect if no item has accessibility focus, if the item with accessibility
      * focus does not expose the specified action, or if the action fails.
@@ -1081,6 +1099,32 @@
         return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action);
     }
 
+    /**
+     * Returns true if accessibility focus is confined to the active window.
+     */
+    public boolean accessibilityFocusOnlyInActiveWindow() {
+        synchronized (mLock) {
+            return mA11yWindowManager.isTrackingWindowsLocked();
+        }
+    }
+
+    /**
+     * Gets the bounds of a window.
+     *
+     * @param outBounds The output to which to write the bounds.
+     */
+    boolean getWindowBounds(int windowId, Rect outBounds) {
+        IBinder token;
+        synchronized (mLock) {
+            token = getWindowToken(windowId, mCurrentUserId);
+        }
+        mWindowManagerService.getWindowFrame(token, outBounds);
+        if (!outBounds.isEmpty()) {
+            return true;
+        }
+        return false;
+    }
+
     public int getActiveWindowId() {
         return mA11yWindowManager.getActiveWindowId(mCurrentUserId);
     }
@@ -1824,9 +1868,11 @@
         for (int i = 0; !observingWindows && (i < boundServiceCount); i++) {
             AccessibilityServiceConnection boundService = boundServices.get(i);
             if (boundService.canRetrieveInteractiveWindowsLocked()) {
+                userState.setAccessibilityFocusOnlyInActiveWindow(false);
                 observingWindows = true;
             }
         }
+        userState.setAccessibilityFocusOnlyInActiveWindow(true);
 
         // Gets all valid displays and start tracking windows of each display if there is at least
         // one bound service that can retrieve window content.
@@ -2930,6 +2976,19 @@
         }
 
         /**
+         * Gets a point within the accessibility focused node where we can send down and up events
+         * to perform a click.
+         *
+         * @param outPoint The click point to populate.
+         * @return Whether accessibility a click point was found and set.
+         */
+        // TODO: (multi-display) Make sure this works for multiple displays.
+        boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
+            return getInteractionBridge()
+                    .getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
+        }
+
+    /**
          * Perform an accessibility action on the view that currently has accessibility focus.
          * Has no effect if no item has accessibility focus, if the item with accessibility
          * focus does not expose the specified action, or if the action fails.
@@ -2947,6 +3006,43 @@
             return focus.performAction(action.getId());
         }
 
+        public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) {
+            AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
+            if (focus == null) {
+                return false;
+            }
+
+            synchronized (mLock) {
+                Rect boundsInScreen = mTempRect;
+                focus.getBoundsInScreen(boundsInScreen);
+
+                // Apply magnification if needed.
+                MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
+                if (spec != null && !spec.isNop()) {
+                    boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY);
+                    boundsInScreen.scale(1 / spec.scale);
+                }
+
+                // Clip to the window bounds.
+                Rect windowBounds = mTempRect1;
+                getWindowBounds(focus.getWindowId(), windowBounds);
+                if (!boundsInScreen.intersect(windowBounds)) {
+                    return false;
+                }
+
+                // Clip to the screen bounds.
+                Point screenSize = mTempPoint;
+                mDefaultDisplay.getRealSize(screenSize);
+                if (!boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y)) {
+                    return false;
+                }
+
+                outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY());
+            }
+
+            return true;
+        }
+
         private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
             final int focusedWindowId;
             synchronized (mLock) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 43bb4b3..0845d01 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -104,6 +104,7 @@
     private boolean mIsDisplayMagnificationEnabled;
     private boolean mIsFilterKeyEventsEnabled;
     private boolean mIsPerformGesturesEnabled;
+    private boolean mAccessibilityFocusOnlyInActiveWindow;
     private boolean mIsTextHighContrastEnabled;
     private boolean mIsTouchExplorationEnabled;
     private boolean mServiceHandlesDoubleTap;
@@ -685,6 +686,13 @@
         mIsPerformGesturesEnabled = enabled;
     }
 
+    public boolean isAccessibilityFocusOnlyInActiveWindow() {
+        return mAccessibilityFocusOnlyInActiveWindow;
+    }
+
+    public void setAccessibilityFocusOnlyInActiveWindow(boolean enabled) {
+        mAccessibilityFocusOnlyInActiveWindow = enabled;
+    }
     public ComponentName getServiceChangingSoftKeyboardModeLocked() {
         return mServiceChangingSoftKeyboardMode;
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java
index afe6238..b7f8e67 100644
--- a/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/FullScreenMagnificationGestureHandler.java
@@ -26,6 +26,7 @@
 
 import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logMagnificationTripleTap;
 import static com.android.server.accessibility.gestures.GestureUtils.distance;
+import static com.android.server.accessibility.gestures.GestureUtils.distanceClosestPointerToPoint;
 
 import static java.lang.Math.abs;
 import static java.util.Arrays.asList;
@@ -37,6 +38,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.PointF;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -615,6 +617,7 @@
 
         private static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1;
         private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2;
+        private static final int MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE = 3;
 
         final int mLongTapMinDelay;
         final int mSwipeMinDistance;
@@ -626,6 +629,7 @@
         private MotionEvent mPreLastDown;
         private MotionEvent mLastUp;
         private MotionEvent mPreLastUp;
+        private PointF mSecondPointerDownLocation = new PointF(Float.NaN, Float.NaN);
 
         private long mLastDetectingDownEventTime;
 
@@ -656,6 +660,10 @@
                     transitionToDelegatingStateAndClear();
                 }
                 break;
+                case MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE: {
+                    transitToPanningScalingStateAndClear();
+                }
+                break;
                 default: {
                     throw new IllegalArgumentException("Unknown message type: " + type);
                 }
@@ -702,14 +710,20 @@
                 }
                 break;
                 case ACTION_POINTER_DOWN: {
-                    if (mMagnificationController.isMagnifying(mDisplayId)) {
-                        transitionTo(mPanningScalingState);
-                        clear();
+                    if (mMagnificationController.isMagnifying(mDisplayId)
+                            && event.getPointerCount() == 2) {
+                        storeSecondPointerDownLocation(event);
+                        mHandler.sendEmptyMessageDelayed(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
+                                ViewConfiguration.getTapTimeout());
                     } else {
                         transitionToDelegatingStateAndClear();
                     }
                 }
                 break;
+                case ACTION_POINTER_UP: {
+                    transitionToDelegatingStateAndClear();
+                }
+                break;
                 case ACTION_MOVE: {
                     if (isFingerDown()
                             && distance(mLastDown, /* move */ event) > mSwipeMinDistance) {
@@ -719,11 +733,19 @@
                         // For convenience, viewport dragging takes precedence
                         // over insta-delegating on 3tap&swipe
                         // (which is a rare combo to be used aside from magnification)
-                        if (isMultiTapTriggered(2 /* taps */)) {
+                        if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
                             transitionToViewportDraggingStateAndClear(event);
+                        } else if (isMagnifying() && event.getPointerCount() == 2) {
+                            //Primary pointer is swiping, so transit to PanningScalingState
+                            transitToPanningScalingStateAndClear();
                         } else {
                             transitionToDelegatingStateAndClear();
                         }
+                    } else if (isMagnifying() && secondPointerDownValid()
+                            && distanceClosestPointerToPoint(
+                            mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) {
+                        //Second pointer is swiping, so transit to PanningScalingState
+                        transitToPanningScalingStateAndClear();
                     }
                 }
                 break;
@@ -755,6 +777,21 @@
             }
         }
 
+        private void storeSecondPointerDownLocation(MotionEvent event) {
+            final int index = event.getActionIndex();
+            mSecondPointerDownLocation.set(event.getX(index), event.getY(index));
+        }
+
+        private boolean secondPointerDownValid() {
+            return !(Float.isNaN(mSecondPointerDownLocation.x) && Float.isNaN(
+                    mSecondPointerDownLocation.y));
+        }
+
+        private void transitToPanningScalingStateAndClear() {
+            transitionTo(mPanningScalingState);
+            clear();
+        }
+
         public boolean isMultiTapTriggered(int numTaps) {
 
             // Shortcut acts as the 2 initial taps
@@ -822,11 +859,13 @@
             setShortcutTriggered(false);
             removePendingDelayedMessages();
             clearDelayedMotionEvents();
+            mSecondPointerDownLocation.set(Float.NaN, Float.NaN);
         }
 
         private void removePendingDelayedMessages() {
             mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
             mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+            mHandler.removeMessages(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE);
         }
 
         private void cacheDelayedMotionEvent(MotionEvent event, MotionEvent rawEvent,
@@ -890,6 +929,7 @@
             transitionTo(mDelegatingState);
             sendDelayedMotionEvents();
             removePendingDelayedMessages();
+            mSecondPointerDownLocation.set(Float.NaN, Float.NaN);
         }
 
         private void onTripleTap(MotionEvent up) {
@@ -907,6 +947,10 @@
             }
         }
 
+        private boolean isMagnifying() {
+            return mMagnificationController.isMagnifying(mDisplayId);
+        }
+
         void transitionToViewportDraggingStateAndClear(MotionEvent down) {
 
             if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index 667364c9..c8cee10 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -21,8 +21,11 @@
 import static com.android.server.accessibility.gestures.TouchState.MAX_POINTER_COUNT;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.util.Slog;
 import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
@@ -37,19 +40,27 @@
  */
 class EventDispatcher {
     private static final String LOG_TAG = "EventDispatcher";
+    private static final int CLICK_LOCATION_NONE = 0;
+    private static final int CLICK_LOCATION_ACCESSIBILITY_FOCUS = 1;
+    private static final int CLICK_LOCATION_LAST_TOUCH_EXPLORED = 2;
 
     private final AccessibilityManagerService mAms;
     private Context mContext;
     // The receiver of motion events.
     private EventStreamTransformation mReceiver;
-    // Keep track of which pointers sent to the system are down.
-    private int mInjectedPointersDown;
 
-    // The time of the last injected down.
-    private long mLastInjectedDownEventTime;
+    // The long pressing pointer id if coordinate remapping is needed for double tap and hold
+    private int mLongPressingPointerId = -1;
 
-    // The last injected hover event.
-    private MotionEvent mLastInjectedHoverEvent;
+    // The long pressing pointer X if coordinate remapping is needed for double tap and hold.
+    private int mLongPressingPointerDeltaX;
+
+    // The long pressing pointer Y if coordinate remapping is needed for double tap and hold.
+    private int mLongPressingPointerDeltaY;
+
+    // Temporary point to avoid instantiation.
+    private final Point mTempPoint = new Point();
+
     private TouchState mState;
 
     EventDispatcher(
@@ -98,8 +109,18 @@
         if (action == MotionEvent.ACTION_DOWN) {
             event.setDownTime(event.getEventTime());
         } else {
-            event.setDownTime(getLastInjectedDownEventTime());
+            event.setDownTime(mState.getLastInjectedDownEventTime());
         }
+        // If the user is long pressing but the long pressing pointer
+        // was not exactly over the accessibility focused item we need
+        // to remap the location of that pointer so the user does not
+        // have to explicitly touch explore something to be able to
+        // long press it, or even worse to avoid the user long pressing
+        // on the wrong item since click and long press behave differently.
+        if (mLongPressingPointerId >= 0) {
+            event = offsetEvent(event, -mLongPressingPointerDeltaX, -mLongPressingPointerDeltaY);
+        }
+
         if (DEBUG) {
             Slog.d(
                     LOG_TAG,
@@ -116,7 +137,7 @@
         } else {
             Slog.e(LOG_TAG, "Error sending event: no receiver specified.");
         }
-        updateState(event);
+        mState.onInjectedMotionEvent(event);
 
         if (event != prototype) {
             event.recycle();
@@ -145,87 +166,15 @@
         mState.onInjectedAccessibilityEvent(type);
     }
 
-    /**
-     * Processes an injected {@link MotionEvent} event.
-     *
-     * @param event The event to process.
-     */
-    void updateState(MotionEvent event) {
-        final int action = event.getActionMasked();
-        final int pointerId = event.getPointerId(event.getActionIndex());
-        final int pointerFlag = (1 << pointerId);
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-            case MotionEvent.ACTION_POINTER_DOWN:
-                mInjectedPointersDown |= pointerFlag;
-                mLastInjectedDownEventTime = event.getDownTime();
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_POINTER_UP:
-                mInjectedPointersDown &= ~pointerFlag;
-                if (mInjectedPointersDown == 0) {
-                    mLastInjectedDownEventTime = 0;
-                }
-                break;
-            case MotionEvent.ACTION_HOVER_ENTER:
-            case MotionEvent.ACTION_HOVER_MOVE:
-            case MotionEvent.ACTION_HOVER_EXIT:
-                if (mLastInjectedHoverEvent != null) {
-                    mLastInjectedHoverEvent.recycle();
-                }
-                mLastInjectedHoverEvent = MotionEvent.obtain(event);
-                break;
-        }
-        if (DEBUG) {
-            Slog.i(LOG_TAG, "Injected pointer:\n" + toString());
-        }
-    }
-
-    /** Clears the internals state. */
-    public void clear() {
-        mInjectedPointersDown = 0;
-    }
-
-    /** @return The time of the last injected down event. */
-    public long getLastInjectedDownEventTime() {
-        return mLastInjectedDownEventTime;
-    }
-
-    /** @return The number of down pointers injected to the view hierarchy. */
-    public int getInjectedPointerDownCount() {
-        return Integer.bitCount(mInjectedPointersDown);
-    }
-
-    /** @return The bits of the injected pointers that are down. */
-    public int getInjectedPointersDown() {
-        return mInjectedPointersDown;
-    }
-
-    /**
-     * Whether an injected pointer is down.
-     *
-     * @param pointerId The unique pointer id.
-     * @return True if the pointer is down.
-     */
-    public boolean isInjectedPointerDown(int pointerId) {
-        final int pointerFlag = (1 << pointerId);
-        return (mInjectedPointersDown & pointerFlag) != 0;
-    }
-
-    /** @return The the last injected hover event. */
-    public MotionEvent getLastInjectedHoverEvent() {
-        return mLastInjectedHoverEvent;
-    }
-
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("=========================");
         builder.append("\nDown pointers #");
-        builder.append(Integer.bitCount(mInjectedPointersDown));
+        builder.append(Integer.bitCount(mState.getInjectedPointersDown()));
         builder.append(" [ ");
         for (int i = 0; i < MAX_POINTER_COUNT; i++) {
-            if ((mInjectedPointersDown & i) != 0) {
+            if (mState.isInjectedPointerDown(i)) {
                 builder.append(i);
                 builder.append(" ");
             }
@@ -236,6 +185,48 @@
     }
 
     /**
+     * /** Offsets all pointers in the given event by adding the specified X and Y offsets.
+     *
+     * @param event The event to offset.
+     * @param offsetX The X offset.
+     * @param offsetY The Y offset.
+     * @return An event with the offset pointers or the original event if both offsets are zero.
+     */
+    private MotionEvent offsetEvent(MotionEvent event, int offsetX, int offsetY) {
+        if (offsetX == 0 && offsetY == 0) {
+            return event;
+        }
+        final int remappedIndex = event.findPointerIndex(mLongPressingPointerId);
+        final int pointerCount = event.getPointerCount();
+        PointerProperties[] props = PointerProperties.createArray(pointerCount);
+        PointerCoords[] coords = PointerCoords.createArray(pointerCount);
+        for (int i = 0; i < pointerCount; i++) {
+            event.getPointerProperties(i, props[i]);
+            event.getPointerCoords(i, coords[i]);
+            if (i == remappedIndex) {
+                coords[i].x += offsetX;
+                coords[i].y += offsetY;
+            }
+        }
+        return MotionEvent.obtain(
+                event.getDownTime(),
+                event.getEventTime(),
+                event.getAction(),
+                event.getPointerCount(),
+                props,
+                coords,
+                event.getMetaState(),
+                event.getButtonState(),
+                1.0f,
+                1.0f,
+                event.getDeviceId(),
+                event.getEdgeFlags(),
+                event.getSource(),
+                event.getDisplayId(),
+                event.getFlags());
+    }
+
+    /**
      * Computes the action for an injected event based on a masked action and a pointer index.
      *
      * @param actionMasked The masked action.
@@ -247,7 +238,7 @@
             case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_POINTER_DOWN:
                 // Compute the action based on how many down pointers are injected.
-                if (getInjectedPointerDownCount() == 0) {
+                if (mState.getInjectedPointerDownCount() == 0) {
                     return MotionEvent.ACTION_DOWN;
                 } else {
                     return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT)
@@ -255,7 +246,7 @@
                 }
             case MotionEvent.ACTION_POINTER_UP:
                 // Compute the action based on how many down pointers are injected.
-                if (getInjectedPointerDownCount() == 1) {
+                if (mState.getInjectedPointerDownCount() == 1) {
                     return MotionEvent.ACTION_UP;
                 } else {
                     return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT)
@@ -280,7 +271,7 @@
         for (int i = 0; i < pointerCount; i++) {
             final int pointerId = prototype.getPointerId(i);
             // Do not send event for already delivered pointers.
-            if (!isInjectedPointerDown(pointerId)) {
+            if (!mState.isInjectedPointerDown(pointerId)) {
                 pointerIdBits |= (1 << pointerId);
                 final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
                 sendMotionEvent(
@@ -306,7 +297,7 @@
         for (int i = 0; i < pointerCount; i++) {
             final int pointerId = prototype.getPointerId(i);
             // Skip non injected down pointers.
-            if (!isInjectedPointerDown(pointerId)) {
+            if (!mState.isInjectedPointerDown(pointerId)) {
                 continue;
             }
             final int action = computeInjectionAction(MotionEvent.ACTION_POINTER_UP, i);
@@ -315,4 +306,97 @@
             pointerIdBits &= ~(1 << pointerId);
         }
     }
+
+    public boolean longPressWithTouchEvents(MotionEvent event, int policyFlags) {
+        final int pointerIndex = event.getActionIndex();
+        final int pointerId = event.getPointerId(pointerIndex);
+        Point clickLocation = mTempPoint;
+        final int result = computeClickLocation(clickLocation);
+        if (result == CLICK_LOCATION_NONE) {
+            return false;
+        }
+        mLongPressingPointerId = pointerId;
+        mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x;
+        mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y;
+        sendDownForAllNotInjectedPointers(event, policyFlags);
+        return true;
+    }
+
+    public void clickWithTouchEvents(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        final int pointerIndex = event.getActionIndex();
+        final int pointerId = event.getPointerId(pointerIndex);
+        Point clickLocation = mTempPoint;
+        final int result = computeClickLocation(clickLocation);
+        if (result == CLICK_LOCATION_NONE) {
+            Slog.e(LOG_TAG, "Unable to compute click location.");
+            // We can't send a click to no location, but the gesture was still
+            // consumed.
+            return;
+        }
+        // Do the click.
+        PointerProperties[] properties = new PointerProperties[1];
+        properties[0] = new PointerProperties();
+        event.getPointerProperties(pointerIndex, properties[0]);
+        PointerCoords[] coords = new PointerCoords[1];
+        coords[0] = new PointerCoords();
+        coords[0].x = clickLocation.x;
+        coords[0].y = clickLocation.y;
+        MotionEvent clickEvent =
+                MotionEvent.obtain(
+                        event.getDownTime(),
+                        event.getEventTime(),
+                        MotionEvent.ACTION_DOWN,
+                        1,
+                        properties,
+                        coords,
+                        0,
+                        0,
+                        1.0f,
+                        1.0f,
+                        event.getDeviceId(),
+                        0,
+                        event.getSource(),
+                        event.getDisplayId(),
+                        event.getFlags());
+        final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
+        sendActionDownAndUp(clickEvent, rawEvent, policyFlags, targetAccessibilityFocus);
+        clickEvent.recycle();
+    }
+
+    private int computeClickLocation(Point outLocation) {
+        if (mState.getLastInjectedHoverEventForClick() != null) {
+            final int lastExplorePointerIndex =
+                    mState.getLastInjectedHoverEventForClick().getActionIndex();
+            outLocation.x =
+                    (int) mState.getLastInjectedHoverEventForClick().getX(lastExplorePointerIndex);
+            outLocation.y =
+                    (int) mState.getLastInjectedHoverEventForClick().getY(lastExplorePointerIndex);
+            if (!mAms.accessibilityFocusOnlyInActiveWindow()
+                    || mState.getLastTouchedWindowId() == mAms.getActiveWindowId()) {
+                if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) {
+                    return CLICK_LOCATION_ACCESSIBILITY_FOCUS;
+                } else {
+                    return CLICK_LOCATION_LAST_TOUCH_EXPLORED;
+                }
+            }
+        }
+        if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) {
+            return CLICK_LOCATION_ACCESSIBILITY_FOCUS;
+        }
+        return CLICK_LOCATION_NONE;
+    }
+
+    private void sendActionDownAndUp(
+            MotionEvent prototype,
+            MotionEvent rawEvent,
+            int policyFlags,
+            boolean targetAccessibilityFocus) {
+        // Tap with the pointer that last explored.
+        final int pointerId = prototype.getPointerId(prototype.getActionIndex());
+        final int pointerIdBits = (1 << pointerId);
+        prototype.setTargetAccessibilityFocus(targetAccessibilityFocus);
+        sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+        prototype.setTargetAccessibilityFocus(targetAccessibilityFocus);
+        sendMotionEvent(prototype, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags);
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index 6d0f069..e9c70c6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -104,6 +104,7 @@
         mHandler = new Handler(context.getMainLooper());
         mListener = listener;
         mState = state;
+        mMultiFingerGesturesEnabled = false;
         // Set up gestures.
         // Start with double tap.
         mGestures.add(new MultiTap(context, 2, GESTURE_DOUBLE_TAP, this));
@@ -247,7 +248,7 @@
          * and hold is dispatched via onGestureCompleted. Otherwise, this method is called when the
          * user has performed a double tap and then held down the second tap.
          */
-        void onDoubleTapAndHold();
+        void onDoubleTapAndHold(MotionEvent event, MotionEvent rawEvent, int policyFlags);
 
         /**
          * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap is
@@ -256,7 +257,7 @@
          *
          * @return true if the event is consumed, else false
          */
-        boolean onDoubleTap();
+        boolean onDoubleTap(MotionEvent event, MotionEvent rawEvent, int policyFlags);
 
         /**
          * Called when the system has decided the event stream is a potential gesture.
@@ -322,7 +323,7 @@
                             new AccessibilityGestureEvent(gestureId, event.getDisplayId());
                     mListener.onGestureCompleted(gestureEvent);
                 } else {
-                    mListener.onDoubleTap();
+                    mListener.onDoubleTap(event, rawEvent, policyFlags);
                 }
                 clear();
                 break;
@@ -332,7 +333,7 @@
                             new AccessibilityGestureEvent(gestureId, event.getDisplayId());
                     mListener.onGestureCompleted(gestureEvent);
                 } else {
-                    mListener.onDoubleTapAndHold();
+                    mListener.onDoubleTapAndHold(event, rawEvent, policyFlags);
                 }
                 clear();
                 break;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
index ac67480..ec30418 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
@@ -1,5 +1,6 @@
 package com.android.server.accessibility.gestures;
 
+import android.graphics.PointF;
 import android.util.MathUtils;
 import android.view.MotionEvent;
 
@@ -38,6 +39,27 @@
         return MathUtils.dist(first.getX(), first.getY(), second.getX(), second.getY());
     }
 
+    /**
+     * Returns the minimum distance between {@code pointerDown} and each pointer of
+     * {@link MotionEvent}.
+     *
+     * @param pointerDown The action pointer location of the {@link MotionEvent} with
+     *     {@link MotionEvent#ACTION_DOWN} or {@link MotionEvent#ACTION_POINTER_DOWN}
+     * @param moveEvent The {@link MotionEvent} with {@link MotionEvent#ACTION_MOVE}
+     * @return the movement of the pointer.
+     */
+    public static double distanceClosestPointerToPoint(PointF pointerDown, MotionEvent moveEvent) {
+        float movement = Float.MAX_VALUE;
+        for (int i = 0; i < moveEvent.getPointerCount(); i++) {
+            final float moveDelta = MathUtils.dist(pointerDown.x, pointerDown.y, moveEvent.getX(i),
+                    moveEvent.getY(i));
+            if (movement > moveDelta) {
+                movement = moveDelta;
+            }
+        }
+        return movement;
+    }
+
     public static boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) {
         final long deltaTime = secondUp.getEventTime() - firstUp.getEventTime();
         return (deltaTime >= timeout);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 4fee672..373d47e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -22,7 +22,6 @@
 
 import android.accessibilityservice.AccessibilityGestureEvent;
 import android.content.Context;
-import android.graphics.Point;
 import android.graphics.Region;
 import android.os.Handler;
 import android.util.Slog;
@@ -86,6 +85,7 @@
     // The ID of the pointer used for dragging.
     private int mDraggingPointerId;
 
+
     // Handler for performing asynchronous operations.
     private final Handler mHandler;
 
@@ -115,8 +115,6 @@
     // Handle to the accessibility manager service.
     private final AccessibilityManagerService mAms;
 
-    // Temporary point to avoid instantiation.
-    private final Point mTempPoint = new Point();
 
     // Context in which this explorer operates.
     private final Context mContext;
@@ -277,6 +275,7 @@
         if (eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
             sendsPendingA11yEventsIfNeed();
         }
+        mState.onReceivedAccessibilityEvent(event);
         super.onAccessibilityEvent(event);
     }
 
@@ -309,16 +308,20 @@
     }
 
     @Override
-    public void onDoubleTapAndHold() {
+    public void onDoubleTapAndHold(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         // Try to use the standard accessibility API to long click
         if (!mAms.performActionOnAccessibilityFocusedItem(
                 AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK)) {
             Slog.e(LOG_TAG, "ACTION_LONG_CLICK failed.");
+            if (mDispatcher.longPressWithTouchEvents(event, policyFlags)) {
+                sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+                mState.startDelegating();
+            }
         }
     }
 
     @Override
-    public boolean onDoubleTap() {
+    public boolean onDoubleTap(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         mAms.onTouchInteractionEnd();
         // Remove pending event deliveries.
         mSendHoverEnterAndMoveDelayed.cancel();
@@ -334,7 +337,10 @@
         // Try to use the standard accessibility API to click
         if (!mAms.performActionOnAccessibilityFocusedItem(
                 AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)) {
-            Slog.e(LOG_TAG, "ACTION_CLICK failed.");
+            Slog.e(LOG_TAG, "ACTION_CLICK failed. Dispatching motion events to simulate click.");
+
+            mDispatcher.clickWithTouchEvents(event, rawEvent, policyFlags);
+            return true;
         }
         return true;
     }
@@ -840,7 +846,7 @@
      * @param policyFlags The policy flags associated with the event.
      */
     private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) {
-        MotionEvent event = mDispatcher.getLastInjectedHoverEvent();
+        MotionEvent event = mState.getLastInjectedHoverEvent();
         if (event != null && event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
             final int pointerIdBits = event.getPointerIdBits();
             if (!mSendTouchExplorationEndDelayed.isPending()) {
@@ -862,7 +868,7 @@
      * @param policyFlags The policy flags associated with the event.
      */
     private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded(int policyFlags) {
-        MotionEvent event = mDispatcher.getLastInjectedHoverEvent();
+        MotionEvent event = mState.getLastInjectedHoverEvent();
         if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
             final int pointerIdBits = event.getPointerIdBits();
             mDispatcher.sendMotionEvent(
@@ -1188,7 +1194,6 @@
                 + ", mDetermineUserIntentTimeout: " + mDetermineUserIntentTimeout
                 + ", mDoubleTapSlop: " + mDoubleTapSlop
                 + ", mDraggingPointerId: " + mDraggingPointerId
-                + ", mTempPoint: " + mTempPoint
                 + " }";
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index d23dbbe..7a39bc2 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -75,6 +75,16 @@
     private MotionEvent mLastReceivedEvent;
     // The accompanying raw event without any transformations.
     private MotionEvent mLastReceivedRawEvent;
+    // The id of the last touch explored window.
+    private int mLastTouchedWindowId;
+    // The last injected hover event.
+    private MotionEvent mLastInjectedHoverEvent;
+    // The last injected hover event used for performing clicks.
+    private MotionEvent mLastInjectedHoverEventForClick;
+    // The time of the last injected down.
+    private long mLastInjectedDownEventTime;
+    // Keep track of which pointers sent to the system are down.
+    private int mInjectedPointersDown;
 
     public TouchState() {
         mReceivedPointerTracker = new ReceivedPointerTracker();
@@ -88,7 +98,9 @@
             mLastReceivedEvent.recycle();
             mLastReceivedEvent = null;
         }
+        mLastTouchedWindowId = -1;
         mReceivedPointerTracker.clear();
+        mInjectedPointersDown = 0;
     }
 
     /**
@@ -107,6 +119,71 @@
         mReceivedPointerTracker.onMotionEvent(rawEvent);
     }
 
+    /**
+     * Processes an injected {@link MotionEvent} event.
+     *
+     * @param event The event to process.
+     */
+    void onInjectedMotionEvent(MotionEvent event) {
+        final int action = event.getActionMasked();
+        final int pointerId = event.getPointerId(event.getActionIndex());
+        final int pointerFlag = (1 << pointerId);
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_POINTER_DOWN:
+                mInjectedPointersDown |= pointerFlag;
+                mLastInjectedDownEventTime = event.getDownTime();
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_POINTER_UP:
+                mInjectedPointersDown &= ~pointerFlag;
+                if (mInjectedPointersDown == 0) {
+                    mLastInjectedDownEventTime = 0;
+                }
+                break;
+            case MotionEvent.ACTION_HOVER_ENTER:
+            case MotionEvent.ACTION_HOVER_MOVE:
+                if (mLastInjectedHoverEvent != null) {
+                    mLastInjectedHoverEvent.recycle();
+                }
+                mLastInjectedHoverEvent = MotionEvent.obtain(event);
+                break;
+            case MotionEvent.ACTION_HOVER_EXIT:
+                if (mLastInjectedHoverEvent != null) {
+                    mLastInjectedHoverEvent.recycle();
+                }
+                mLastInjectedHoverEvent = MotionEvent.obtain(event);
+                if (mLastInjectedHoverEventForClick != null) {
+                    mLastInjectedHoverEventForClick.recycle();
+                }
+                mLastInjectedHoverEventForClick = MotionEvent.obtain(event);
+                break;
+        }
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "Injected pointer:\n" + toString());
+        }
+    }
+
+    /** Updates state in response to an accessibility event received from the outside. */
+    public void onReceivedAccessibilityEvent(AccessibilityEvent event) {
+        // If a new window opens or the accessibility focus moves we no longer
+        // want to click/long press on the last touch explored location.
+        switch (event.getEventType()) {
+            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
+            case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
+                if (mLastInjectedHoverEventForClick != null) {
+                    mLastInjectedHoverEventForClick.recycle();
+                    mLastInjectedHoverEventForClick = null;
+                }
+                mLastTouchedWindowId = -1;
+                break;
+            case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
+            case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
+                mLastTouchedWindowId = event.getWindowId();
+                break;
+        }
+    }
+
     public void onInjectedAccessibilityEvent(int type) {
         // The below state transitions go here because the related events are often sent on a
         // delay.
@@ -236,6 +313,46 @@
         return mLastReceivedEvent;
     }
 
+    /** @return The the last injected hover event. */
+    public MotionEvent getLastInjectedHoverEvent() {
+        return mLastInjectedHoverEvent;
+    }
+
+    /** @return The time of the last injected down event. */
+    public long getLastInjectedDownEventTime() {
+        return mLastInjectedDownEventTime;
+    }
+
+    public int getLastTouchedWindowId() {
+        return mLastTouchedWindowId;
+    }
+
+    /** @return The number of down pointers injected to the view hierarchy. */
+    public int getInjectedPointerDownCount() {
+        return Integer.bitCount(mInjectedPointersDown);
+    }
+
+    /** @return The bits of the injected pointers that are down. */
+    public int getInjectedPointersDown() {
+        return mInjectedPointersDown;
+    }
+
+    /**
+     * Whether an injected pointer is down.
+     *
+     * @param pointerId The unique pointer id.
+     * @return True if the pointer is down.
+     */
+    public boolean isInjectedPointerDown(int pointerId) {
+        final int pointerFlag = (1 << pointerId);
+        return (mInjectedPointersDown & pointerFlag) != 0;
+    }
+
+    /** @return The the last injected hover event used for a click. */
+    public MotionEvent getLastInjectedHoverEventForClick() {
+        return mLastInjectedHoverEventForClick;
+    }
+
     /** This class tracks where and when a pointer went down. It does not track its movement. */
     class ReceivedPointerTracker {
         private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker";
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 11f9015..533bbe6 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -149,7 +149,7 @@
             @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
             @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
             @NonNull Runnable onErrorCallback,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService, int userId) {
         long requestTime = SystemClock.elapsedRealtime();
         AtomicReference<ICancellationSignal> cancellationRef = new AtomicReference<>();
 
@@ -173,7 +173,7 @@
                                             inlineSuggestionsRequest, inlineSuggestionsData,
                                             clientState, focusedId, focusedValue,
                                             inlineSuggestionsCallback,
-                                            client, onErrorCallback, remoteRenderService);
+                                            client, onErrorCallback, remoteRenderService, userId);
                                     if (!showingFillWindow) {
                                         requestAutofill.complete(null);
                                     }
@@ -243,7 +243,8 @@
             @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue,
             @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
             @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId) {
         if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty()
                 || inlineSuggestionsCallback == null || request == null
                 || remoteRenderService == null) {
@@ -312,7 +313,7 @@
                                     Slog.w(TAG, "RemoteException starting intent sender");
                                 }
                             }
-                        }, onErrorCallback, remoteRenderService);
+                        }, onErrorCallback, remoteRenderService, userId, sessionId);
 
         if (inlineSuggestionsCallback.apply(inlineFillUi)) {
             mCallbacks.logAugmentedAutofillShown(sessionId, clientState);
diff --git a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
index 617c111..80b8583 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
@@ -88,9 +88,9 @@
      */
     public void renderSuggestion(@NonNull IInlineSuggestionUiCallback callback,
             @NonNull InlinePresentation presentation, int width, int height,
-            @Nullable IBinder hostInputToken, int displayId) {
+            @Nullable IBinder hostInputToken, int displayId, int userId, int sessionId) {
         scheduleAsyncRequest((s) -> s.renderSuggestion(callback, presentation, width, height,
-                hostInputToken, displayId));
+                hostInputToken, displayId, userId, sessionId));
     }
 
     /**
@@ -100,6 +100,13 @@
         scheduleAsyncRequest((s) -> s.getInlineSuggestionsRendererInfo(callback));
     }
 
+    /**
+     * Destroys the remote inline suggestion views associated with the given user id and session id.
+     */
+    public void destroySuggestionViews(int userId, int sessionId) {
+        scheduleAsyncRequest((s) -> s.destroySuggestionViews(userId, sessionId));
+    }
+
     @Nullable
     private static ServiceInfo getServiceInfo(Context context, int userId) {
         final String packageName =
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2b9ce2f..9b3d075 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -155,6 +155,9 @@
      */
     public final int id;
 
+    /** userId the session belongs to */
+    public final int userId;
+
     /** uid the session is for */
     public final int uid;
 
@@ -823,6 +826,7 @@
         }
         id = sessionId;
         mFlags = flags;
+        this.userId = userId;
         this.taskId = taskId;
         this.uid = uid;
         mStartTime = SystemClock.elapsedRealtime();
@@ -2986,7 +2990,7 @@
                         mInlineSessionController.setInlineFillUiLocked(
                                 InlineFillUi.emptyUi(focusedId));
                     }
-                }, remoteRenderService);
+                }, remoteRenderService, userId, id);
         return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
     }
 
@@ -3296,7 +3300,7 @@
                                         mInlineSessionController.setInlineFillUiLocked(
                                                 InlineFillUi.emptyUi(mCurrentViewId));
                                     }
-                                }, mService.getRemoteInlineSuggestionRenderServiceLocked());
+                                }, mService.getRemoteInlineSuggestionRenderServiceLocked(), userId);
                     }
                 };
 
@@ -3796,6 +3800,12 @@
         if (mCurrentViewId != null) {
             mInlineSessionController.destroyLocked(mCurrentViewId);
         }
+        final RemoteInlineSuggestionRenderService remoteRenderService =
+                mService.getRemoteInlineSuggestionRenderServiceLocked();
+        if (remoteRenderService != null) {
+            remoteRenderService.destroySuggestionViews(userId, id);
+        }
+
         mDestroyed = true;
 
         // Log metrics
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
index 627c073..25e9d5c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
@@ -105,19 +105,20 @@
             @NonNull AutofillId focusedViewId, @Nullable String filterText,
             @NonNull AutoFillUI.AutoFillUiCallback uiCallback,
             @NonNull Runnable onErrorCallback,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId) {
 
         if (InlineSuggestionFactory.responseNeedAuthentication(response)) {
             InlineSuggestion inlineAuthentication =
                     InlineSuggestionFactory.createInlineAuthentication(request, response,
-                            focusedViewId, uiCallback, onErrorCallback, remoteRenderService);
+                            uiCallback, onErrorCallback, remoteRenderService, userId, sessionId);
             return new InlineFillUi(focusedViewId, inlineAuthentication, filterText);
         } else if (response.getDatasets() != null) {
             SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
                     InlineSuggestionFactory.createAutofillInlineSuggestions(request,
                             response.getRequestId(),
                             response.getDatasets(), focusedViewId, uiCallback, onErrorCallback,
-                            remoteRenderService);
+                            remoteRenderService, userId, sessionId);
             return new InlineFillUi(focusedViewId, inlineSuggestions, filterText);
         }
         return new InlineFillUi(focusedViewId, new SparseArray<>(), filterText);
@@ -132,11 +133,12 @@
             @NonNull AutofillId focusedViewId, @Nullable String filterText,
             @NonNull InlineSuggestionUiCallback uiCallback,
             @NonNull Runnable onErrorCallback,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId) {
         SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
                 InlineSuggestionFactory.createAugmentedAutofillInlineSuggestions(request, datasets,
                         focusedViewId,
-                        uiCallback, onErrorCallback, remoteRenderService);
+                        uiCallback, onErrorCallback, remoteRenderService, userId, sessionId);
         return new InlineFillUi(focusedViewId, inlineSuggestions, filterText);
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 462ffd6..8fcb8aa 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -53,9 +53,9 @@
 
     public static InlineSuggestion createInlineAuthentication(
             @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
-            @NonNull AutofillId autofillId,
             @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService, int userId,
+            int sessionId) {
         final BiConsumer<Dataset, Integer> onClickFactory = (dataset, datasetIndex) -> {
             client.authenticate(response.getRequestId(),
                     datasetIndex, response.getAuthentication(), response.getClientState(),
@@ -66,7 +66,8 @@
         InlinePresentation inlineAuthentication = response.getInlinePresentation();
         return createInlineAuthSuggestion(
                 mergedInlinePresentation(request, 0, inlineAuthentication),
-                remoteRenderService, onClickFactory, onErrorCallback, intentSenderConsumer,
+                remoteRenderService, userId, sessionId,
+                onClickFactory, onErrorCallback, intentSenderConsumer,
                 request.getHostInputToken(), request.getHostDisplayId());
     }
 
@@ -80,7 +81,8 @@
             @NonNull List<Dataset> datasets,
             @NonNull AutofillId autofillId,
             @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId) {
         if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
         final Consumer<IntentSender> intentSenderConsumer = (intentSender) ->
                 client.startIntentSender(intentSender, new Intent());
@@ -90,7 +92,8 @@
 
         return createInlineSuggestionsInternal(/* isAugmented= */ false, request,
                 datasets, autofillId,
-                onErrorCallback, onClickFactory, intentSenderConsumer, remoteRenderService);
+                onErrorCallback, onClickFactory, intentSenderConsumer, remoteRenderService, userId,
+                sessionId);
     }
 
     /**
@@ -104,7 +107,8 @@
             @NonNull AutofillId autofillId,
             @NonNull InlineFillUi.InlineSuggestionUiCallback inlineSuggestionUiCallback,
             @NonNull Runnable onErrorCallback,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId) {
         if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
         return createInlineSuggestionsInternal(/* isAugmented= */ true, request,
                 datasets, autofillId, onErrorCallback,
@@ -112,7 +116,7 @@
                         inlineSuggestionUiCallback.autofill(dataset, datasetIndex),
                 (intentSender) ->
                         inlineSuggestionUiCallback.startIntentSender(intentSender, new Intent()),
-                remoteRenderService);
+                remoteRenderService, userId, sessionId);
     }
 
     @Nullable
@@ -121,7 +125,8 @@
             @NonNull List<Dataset> datasets, @NonNull AutofillId autofillId,
             @NonNull Runnable onErrorCallback, @NonNull BiConsumer<Dataset, Integer> onClickFactory,
             @NonNull Consumer<IntentSender> intentSenderConsumer,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+            @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId) {
         SparseArray<Pair<Dataset, InlineSuggestion>> response = new SparseArray<>(datasets.size());
         for (int datasetIndex = 0; datasetIndex < datasets.size(); datasetIndex++) {
             final Dataset dataset = datasets.get(datasetIndex);
@@ -139,7 +144,8 @@
             InlineSuggestion inlineSuggestion = createInlineSuggestion(isAugmented, dataset,
                     datasetIndex,
                     mergedInlinePresentation(request, datasetIndex, inlinePresentation),
-                    onClickFactory, remoteRenderService, onErrorCallback, intentSenderConsumer,
+                    onClickFactory, remoteRenderService, userId, sessionId,
+                    onErrorCallback, intentSenderConsumer,
                     request.getHostInputToken(), request.getHostDisplayId());
             response.append(datasetIndex, Pair.create(dataset, inlineSuggestion));
         }
@@ -151,6 +157,7 @@
             @NonNull InlinePresentation inlinePresentation,
             @NonNull BiConsumer<Dataset, Integer> onClickFactory,
             @NonNull RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId,
             @NonNull Runnable onErrorCallback, @NonNull Consumer<IntentSender> intentSenderConsumer,
             @Nullable IBinder hostInputToken,
             int displayId) {
@@ -167,7 +174,8 @@
         final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
                 createInlineContentProvider(inlinePresentation,
                         () -> onClickFactory.accept(dataset, datasetIndex), onErrorCallback,
-                        intentSenderConsumer, remoteRenderService, hostInputToken, displayId));
+                        intentSenderConsumer, remoteRenderService, userId, sessionId,
+                        hostInputToken, displayId));
 
         return inlineSuggestion;
     }
@@ -175,6 +183,7 @@
     private static InlineSuggestion createInlineAuthSuggestion(
             @NonNull InlinePresentation inlinePresentation,
             @NonNull RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId,
             @NonNull BiConsumer<Dataset, Integer> onClickFactory, @NonNull Runnable onErrorCallback,
             @NonNull Consumer<IntentSender> intentSenderConsumer,
             @Nullable IBinder hostInputToken, int displayId) {
@@ -187,8 +196,8 @@
                 createInlineContentProvider(inlinePresentation,
                         () -> onClickFactory.accept(null,
                                 AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED),
-                        onErrorCallback, intentSenderConsumer, remoteRenderService, hostInputToken,
-                        displayId));
+                        onErrorCallback, intentSenderConsumer, remoteRenderService, userId,
+                        sessionId, hostInputToken, displayId));
     }
 
     /**
@@ -216,12 +225,13 @@
             @NonNull Runnable onErrorCallback,
             @NonNull Consumer<IntentSender> intentSenderConsumer,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId,
             @Nullable IBinder hostInputToken,
             int displayId) {
         RemoteInlineSuggestionViewConnector
                 remoteInlineSuggestionViewConnector = new RemoteInlineSuggestionViewConnector(
-                remoteRenderService, inlinePresentation, hostInputToken, displayId, onClickAction,
-                onErrorCallback, intentSenderConsumer);
+                remoteRenderService, userId, sessionId, inlinePresentation, hostInputToken,
+                displayId, onClickAction, onErrorCallback, intentSenderConsumer);
         InlineContentProviderImpl inlineContentProvider = new InlineContentProviderImpl(
                 remoteInlineSuggestionViewConnector, null);
         return inlineContentProvider;
diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
index 9d23c17..7257255 100644
--- a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
+++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
@@ -46,6 +46,8 @@
     @Nullable
     private final IBinder mHostInputToken;
     private final int mDisplayId;
+    private final int mUserId;
+    private final int mSessionId;
 
     @NonNull
     private final Runnable mOnAutofillCallback;
@@ -56,6 +58,7 @@
 
     RemoteInlineSuggestionViewConnector(
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+            int userId, int sessionId,
             @NonNull InlinePresentation inlinePresentation,
             @Nullable IBinder hostInputToken,
             int displayId,
@@ -66,6 +69,8 @@
         mInlinePresentation = inlinePresentation;
         mHostInputToken = hostInputToken;
         mDisplayId = displayId;
+        mUserId = userId;
+        mSessionId = sessionId;
 
         mOnAutofillCallback = onAutofillCallback;
         mOnErrorCallback = onErrorCallback;
@@ -82,7 +87,7 @@
         if (mRemoteRenderService != null) {
             if (sDebug) Slog.d(TAG, "Request to recreate the UI");
             mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
-                    mHostInputToken, mDisplayId);
+                    mHostInputToken, mDisplayId, mUserId, mSessionId);
             return true;
         }
         return false;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 65e98ac..4bba0d8 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -95,7 +95,6 @@
         "android.hardware.light-V2.0-java",
         "android.hardware.power-java",
         "android.hardware.power-V1.0-java",
-        "android.hardware.tv.cec-V1.0-java",
         "android.hardware.vibrator-java",
         "android.net.ipsec.ike.stubs.module_lib",
         "app-compat-annotations",
@@ -117,6 +116,7 @@
         "android.hardware.health-V2.0-java",
         "android.hardware.health-V2.1-java",
         "android.hardware.light-java",
+        "android.hardware.tv.cec-V1.0-java",
         "android.hardware.weaver-V1.0-java",
         "android.hardware.biometrics.face-V1.0-java",
         "android.hardware.biometrics.fingerprint-V2.2-java",
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 4ff421e..135ac9a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -87,6 +87,7 @@
     static final String KEY_PROCESS_START_ASYNC = "process_start_async";
     static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
     static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
+    static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -119,6 +120,7 @@
     private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
     private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
     private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
+    private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
 
     // Flag stored in the DeviceConfig API.
     /**
@@ -328,6 +330,12 @@
      */
     public ArraySet<Integer> IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES = new ArraySet<Integer>();
 
+    /**
+     * The threshold for the amount of PendingIntent for each UID, there will be
+     * warning logs if the number goes beyond this threshold.
+     */
+    public int PENDINGINTENT_WARNING_THRESHOLD =  DEFAULT_PENDINGINTENT_WARNING_THRESHOLD;
+
     private List<String> mDefaultImperceptibleKillExemptPackages;
     private List<Integer> mDefaultImperceptibleKillExemptProcStates;
 
@@ -562,6 +570,8 @@
                     DEFAULT_MEMORY_INFO_THROTTLE_TIME);
             TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
                     DEFAULT_TOP_TO_FGS_GRACE_DURATION);
+            PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
+                    DEFAULT_PENDINGINTENT_WARNING_THRESHOLD);
 
             // For new flags that are intended for server-side experiments, please use the new
             // DeviceConfig package.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 157feb3..be85906 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2543,7 +2543,8 @@
         mUiHandler = injector.getUiHandler(null /* service */);
         mUserController = hasHandlerThread ? new UserController(this) : null;
         mPendingIntentController = hasHandlerThread
-                ? new PendingIntentController(handlerThread.getLooper(), mUserController) : null;
+                ? new PendingIntentController(handlerThread.getLooper(), mUserController,
+                        mConstants) : null;
         mProcStartHandlerThread = null;
         mProcStartHandler = null;
         mHiddenApiBlacklist = null;
@@ -2640,7 +2641,7 @@
         mUserController = new UserController(this);
 
         mPendingIntentController = new PendingIntentController(
-                mHandlerThread.getLooper(), mUserController);
+                mHandlerThread.getLooper(), mUserController, mConstants);
 
         if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) {
             mUseFifoUiScheduling = true;
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index eacf088..c62df56 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -41,8 +41,12 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.RingBuffer;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AlarmManagerInternal;
 import com.android.server.LocalServices;
@@ -52,6 +56,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 
@@ -66,6 +71,9 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM;
     private static final String TAG_MU = TAG + POSTFIX_MU;
 
+    /** @see {@link #mRecentIntentsPerUid}.  */
+    private static final int RECENT_N = 10;
+
     /** Lock for internal state. */
     final Object mLock = new Object();
     final Handler mH;
@@ -77,10 +85,22 @@
     final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
             = new HashMap<>();
 
-    PendingIntentController(Looper looper, UserController userController) {
+    /** The number of PendingIntentRecord per uid */
+    @GuardedBy("mLock")
+    private final SparseIntArray mIntentsPerUid = new SparseIntArray();
+
+    /** The recent PendingIntentRecord, up to {@link #RECENT_N} per uid */
+    @GuardedBy("mLock")
+    private final SparseArray<RingBuffer<String>> mRecentIntentsPerUid = new SparseArray<>();
+
+    private final ActivityManagerConstants mConstants;
+
+    PendingIntentController(Looper looper, UserController userController,
+            ActivityManagerConstants constants) {
         mH = new Handler(looper);
         mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
         mUserController = userController;
+        mConstants = constants;
     }
 
     void onActivityManagerInternalAdded() {
@@ -136,12 +156,14 @@
                 }
                 makeIntentSenderCanceled(rec);
                 mIntentSenderRecords.remove(key);
+                decrementUidStatLocked(rec);
             }
             if (noCreate) {
                 return rec;
             }
             rec = new PendingIntentRecord(this, key, callingUid);
             mIntentSenderRecords.put(key, rec.ref);
+            incrementUidStatLocked(rec);
             return rec;
         }
     }
@@ -198,6 +220,7 @@
                 didSomething = true;
                 it.remove();
                 makeIntentSenderCanceled(pir);
+                decrementUidStatLocked(pir);
                 if (pir.key.activity != null) {
                     final Message m = PooledLambda.obtainMessage(
                             PendingIntentController::clearPendingResultForActivity, this,
@@ -237,6 +260,7 @@
         synchronized (mLock) {
             makeIntentSenderCanceled(rec);
             mIntentSenderRecords.remove(rec.key);
+            decrementUidStatLocked(rec);
             if (cleanActivity && rec.key.activity != null) {
                 final Message m = PooledLambda.obtainMessage(
                         PendingIntentController::clearPendingResultForActivity, this,
@@ -369,9 +393,81 @@
                 }
             }
 
+            final int sizeOfIntentsPerUid = mIntentsPerUid.size();
+            if (sizeOfIntentsPerUid > 0) {
+                for (int i = 0; i < sizeOfIntentsPerUid; i++) {
+                    pw.print("  * UID: ");
+                    pw.print(mIntentsPerUid.keyAt(i));
+                    pw.print(" total: ");
+                    pw.println(mIntentsPerUid.valueAt(i));
+                }
+            }
+
             if (!printed) {
                 pw.println("  (nothing)");
             }
         }
     }
+
+    /**
+     * Increment the number of the PendingIntentRecord for the given uid, log a warning
+     * if there are too many for this uid already.
+     */
+    @GuardedBy("mLock")
+    void incrementUidStatLocked(final PendingIntentRecord pir) {
+        final int uid = pir.uid;
+        final int idx = mIntentsPerUid.indexOfKey(uid);
+        int newCount = 1;
+        if (idx >= 0) {
+            newCount = mIntentsPerUid.valueAt(idx) + 1;
+            mIntentsPerUid.setValueAt(idx, newCount);
+        } else {
+            mIntentsPerUid.put(uid, newCount);
+        }
+
+        // If the number is within the range [threshold - N + 1, threshold], log it into buffer
+        final int lowBound = mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N + 1;
+        RingBuffer<String> recentHistory = null;
+        if (newCount == lowBound) {
+            recentHistory = new RingBuffer(String.class, RECENT_N);
+            mRecentIntentsPerUid.put(uid, recentHistory);
+        } else if (newCount > lowBound && newCount <= mConstants.PENDINGINTENT_WARNING_THRESHOLD) {
+            recentHistory = mRecentIntentsPerUid.get(uid);
+        }
+        if (recentHistory == null) {
+            return;
+        }
+
+        recentHistory.append(pir.key.toString());
+
+        // Output the log if we are hitting the threshold
+        if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD) {
+            Slog.wtf(TAG, "Too many PendingIntent created for uid " + uid
+                    + ", recent " + RECENT_N + ": " + Arrays.toString(recentHistory.toArray()));
+            // Clear the buffer, as we don't want to spam the log when the numbers
+            // are jumping up and down around the threshold.
+            mRecentIntentsPerUid.remove(uid);
+        }
+    }
+
+    /**
+     * Decrement the number of the PendingIntentRecord for the given uid.
+     */
+    @GuardedBy("mLock")
+    void decrementUidStatLocked(final PendingIntentRecord pir) {
+        final int uid = pir.uid;
+        final int idx = mIntentsPerUid.indexOfKey(uid);
+        if (idx >= 0) {
+            final int newCount = mIntentsPerUid.valueAt(idx) - 1;
+            // If we are going below the low threshold, no need to keep logs.
+            if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N) {
+                mRecentIntentsPerUid.delete(uid);
+            }
+            if (newCount == 0) {
+                mIntentsPerUid.removeAt(idx);
+            } else {
+                mIntentsPerUid.setValueAt(idx, newCount);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index d54d2d7..1997dbd 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -187,7 +187,8 @@
                 + " intent="
                 + (requestIntent != null
                         ? requestIntent.toShortString(false, true, false, false) : "<null>")
-                + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}";
+                + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}"
+                + " requestCode=" + requestCode;
         }
 
         String typeName() {
@@ -499,6 +500,7 @@
             WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key);
             if (current == ref) {
                 controller.mIntentSenderRecords.remove(key);
+                controller.decrementUidStatLocked(this);
             }
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index b84d322..75ab33d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -17,11 +17,18 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.tv.cec.V1_0.CecMessage;
+import android.hardware.tv.cec.V1_0.HotplugEvent;
+import android.hardware.tv.cec.V1_0.IHdmiCec;
+import android.hardware.tv.cec.V1_0.IHdmiCec.getPhysicalAddressCallback;
+import android.hardware.tv.cec.V1_0.IHdmiCecCallback;
 import android.hardware.tv.cec.V1_0.Result;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Handler;
+import android.os.IHwBinder;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -79,6 +86,11 @@
 
     private static final int MAX_HDMI_MESSAGE_HISTORY = 250;
 
+    private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+    /** Cookie for matching the right end point. */
+    protected static final int HDMI_CEC_HAL_DEATH_COOKIE = 353;
+
     // Predicate for whether the given logical address is remote device's one or not.
     private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
         @Override
@@ -102,10 +114,6 @@
     // device or issued by internal state change.
     private Handler mControlHandler;
 
-    // Stores the pointer to the native implementation of the service that
-    // interacts with HAL.
-    private volatile long mNativePtr;
-
     private final HdmiControlService mService;
 
     // Stores the local CEC devices in the system. Device type is used for key.
@@ -149,23 +157,21 @@
      * A factory method with injection of native methods for testing.
      */
     static HdmiCecController createWithNativeWrapper(
-        HdmiControlService service, NativeWrapper nativeWrapper) {
-            HdmiCecController controller = new HdmiCecController(service, nativeWrapper);
-            long nativePtr = nativeWrapper
-                .nativeInit(controller, service.getServiceLooper().getQueue());
-            if (nativePtr == 0L) {
-                controller = null;
-                return null;
-            }
-
-            controller.init(nativePtr);
-            return controller;
+            HdmiControlService service, NativeWrapper nativeWrapper) {
+        HdmiCecController controller = new HdmiCecController(service, nativeWrapper);
+        String nativePtr = nativeWrapper.nativeInit();
+        if (nativePtr == null) {
+            HdmiLogger.warning("Couldn't get tv.cec service.");
+            return null;
+        }
+        controller.init(nativeWrapper);
+        return controller;
     }
 
-    private void init(long nativePtr) {
+    private void init(NativeWrapper nativeWrapper) {
         mIoHandler = new Handler(mService.getIoLooper());
         mControlHandler = new Handler(mService.getServiceLooper());
-        mNativePtr = nativePtr;
+        nativeWrapper.setCallback(new HdmiCecCallback());
     }
 
     @ServiceThreadOnly
@@ -261,7 +267,7 @@
 
 
     HdmiPortInfo[] getPortInfos() {
-        return mNativeWrapperImpl.nativeGetPortInfos(mNativePtr);
+        return mNativeWrapperImpl.nativeGetPortInfos();
     }
 
     /**
@@ -289,7 +295,7 @@
     int addLogicalAddress(int newLogicalAddress) {
         assertRunOnServiceThread();
         if (HdmiUtils.isValidAddress(newLogicalAddress)) {
-            return mNativeWrapperImpl.nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
+            return mNativeWrapperImpl.nativeAddLogicalAddress(newLogicalAddress);
         } else {
             return Result.FAILURE_INVALID_ARGS;
         }
@@ -306,7 +312,7 @@
         for (int i = 0; i < mLocalDevices.size(); ++i) {
             mLocalDevices.valueAt(i).clearAddress();
         }
-        mNativeWrapperImpl.nativeClearLogicalAddress(mNativePtr);
+        mNativeWrapperImpl.nativeClearLogicalAddress();
     }
 
     @ServiceThreadOnly
@@ -326,7 +332,7 @@
     @ServiceThreadOnly
     int getPhysicalAddress() {
         assertRunOnServiceThread();
-        return mNativeWrapperImpl.nativeGetPhysicalAddress(mNativePtr);
+        return mNativeWrapperImpl.nativeGetPhysicalAddress();
     }
 
     /**
@@ -337,7 +343,7 @@
     @ServiceThreadOnly
     int getVersion() {
         assertRunOnServiceThread();
-        return mNativeWrapperImpl.nativeGetVersion(mNativePtr);
+        return mNativeWrapperImpl.nativeGetVersion();
     }
 
     /**
@@ -348,7 +354,7 @@
     @ServiceThreadOnly
     int getVendorId() {
         assertRunOnServiceThread();
-        return mNativeWrapperImpl.nativeGetVendorId(mNativePtr);
+        return mNativeWrapperImpl.nativeGetVendorId();
     }
 
     /**
@@ -361,7 +367,7 @@
     void setOption(int flag, boolean enabled) {
         assertRunOnServiceThread();
         HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled);
-        mNativeWrapperImpl.nativeSetOption(mNativePtr, flag, enabled);
+        mNativeWrapperImpl.nativeSetOption(flag, enabled);
     }
 
     /**
@@ -375,7 +381,7 @@
         if (!LanguageTag.isLanguage(language)) {
             return;
         }
-        mNativeWrapperImpl.nativeSetLanguage(mNativePtr, language);
+        mNativeWrapperImpl.nativeSetLanguage(language);
     }
 
     /**
@@ -387,7 +393,7 @@
     @ServiceThreadOnly
     void enableAudioReturnChannel(int port, boolean enabled) {
         assertRunOnServiceThread();
-        mNativeWrapperImpl.nativeEnableAudioReturnChannel(mNativePtr, port, enabled);
+        mNativeWrapperImpl.nativeEnableAudioReturnChannel(port, enabled);
     }
 
     /**
@@ -399,7 +405,7 @@
     @ServiceThreadOnly
     boolean isConnected(int port) {
         assertRunOnServiceThread();
-        return mNativeWrapperImpl.nativeIsConnected(mNativePtr, port);
+        return mNativeWrapperImpl.nativeIsConnected(port);
     }
 
     /**
@@ -521,7 +527,7 @@
             // <Polling Message> is a message which has empty body.
             int ret =
                     mNativeWrapperImpl.nativeSendCecCommand(
-                        mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY);
+                        sourceAddress, destinationAddress, EMPTY_BODY);
             if (ret == SendMessageResult.SUCCESS) {
                 return true;
             } else if (ret != SendMessageResult.NACK) {
@@ -627,7 +633,7 @@
                 int i = 0;
                 int errorCode = SendMessageResult.SUCCESS;
                 do {
-                    errorCode = mNativeWrapperImpl.nativeSendCecCommand(mNativePtr,
+                    errorCode = mNativeWrapperImpl.nativeSendCecCommand(
                         cecMessage.getSource(), cecMessage.getDestination(), body);
                     if (errorCode == SendMessageResult.SUCCESS) {
                         break;
@@ -651,7 +657,7 @@
     }
 
     /**
-     * Called by native when incoming CEC message arrived.
+     * Called when incoming CEC message arrived.
      */
     @ServiceThreadOnly
     private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
@@ -663,7 +669,7 @@
     }
 
     /**
-     * Called by native when a hotplug event issues.
+     * Called when a hotplug event issues.
      */
     @ServiceThreadOnly
     private void handleHotplug(int port, boolean connected) {
@@ -710,18 +716,19 @@
     }
 
     protected interface NativeWrapper {
-        long nativeInit(HdmiCecController handler, MessageQueue messageQueue);
-        int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body);
-        int nativeAddLogicalAddress(long controllerPtr, int logicalAddress);
-        void nativeClearLogicalAddress(long controllerPtr);
-        int nativeGetPhysicalAddress(long controllerPtr);
-        int nativeGetVersion(long controllerPtr);
-        int nativeGetVendorId(long controllerPtr);
-        HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
-        void nativeSetOption(long controllerPtr, int flag, boolean enabled);
-        void nativeSetLanguage(long controllerPtr, String language);
-        void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag);
-        boolean nativeIsConnected(long controllerPtr, int port);
+        String nativeInit();
+        void setCallback(HdmiCecCallback callback);
+        int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body);
+        int nativeAddLogicalAddress(int logicalAddress);
+        void nativeClearLogicalAddress();
+        int nativeGetPhysicalAddress();
+        int nativeGetVersion();
+        int nativeGetVendorId();
+        HdmiPortInfo[] nativeGetPortInfos();
+        void nativeSetOption(int flag, boolean enabled);
+        void nativeSetLanguage(String language);
+        void nativeEnableAudioReturnChannel(int port, boolean flag);
+        boolean nativeIsConnected(int port);
     }
 
     private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue);
@@ -739,67 +746,200 @@
         int port, boolean flag);
     private static native boolean nativeIsConnected(long controllerPtr, int port);
 
-    private static final class NativeWrapperImpl implements NativeWrapper {
+    private static final class NativeWrapperImpl implements NativeWrapper,
+            IHwBinder.DeathRecipient, getPhysicalAddressCallback {
+        private IHdmiCec mHdmiCec;
+        private final Object mLock = new Object();
+        private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
 
         @Override
-        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
-            return HdmiCecController.nativeInit(handler, messageQueue);
+        public String nativeInit() {
+            return (connectToHal() ? mHdmiCec.toString() : null);
+        }
+
+        boolean connectToHal() {
+            try {
+                mHdmiCec = IHdmiCec.getService();
+                try {
+                    mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE);
+                } catch (RemoteException e) {
+                    HdmiLogger.error("Couldn't link to death : ", e);
+                }
+            } catch (RemoteException e) {
+                HdmiLogger.error("Couldn't get tv.cec service : ", e);
+                return false;
+            }
+            return true;
         }
 
         @Override
-        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
-            byte[] body) {
-            return HdmiCecController.nativeSendCecCommand(controllerPtr, srcAddress, dstAddress, body);
+        public void setCallback(HdmiCecCallback callback) {
+            try {
+                mHdmiCec.setCallback(callback);
+            } catch (RemoteException e) {
+                HdmiLogger.error("Couldn't initialise tv.cec callback : ", e);
+            }
         }
 
         @Override
-        public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
-            return HdmiCecController.nativeAddLogicalAddress(controllerPtr, logicalAddress);
+        public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) {
+            CecMessage message = new CecMessage();
+            message.initiator = srcAddress;
+            message.destination = dstAddress;
+            message.body = new ArrayList<>(body.length);
+            for (byte b : body) {
+                message.body.add(b);
+            }
+            try {
+                return mHdmiCec.sendMessage(message);
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to send CEC message : ", e);
+                return SendMessageResult.FAIL;
+            }
         }
 
         @Override
-        public void nativeClearLogicalAddress(long controllerPtr) {
-            HdmiCecController.nativeClearLogicalAddress(controllerPtr);
+        public int nativeAddLogicalAddress(int logicalAddress) {
+            try {
+                return mHdmiCec.addLogicalAddress(logicalAddress);
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to add a logical address : ", e);
+                return Result.FAILURE_INVALID_ARGS;
+            }
         }
 
         @Override
-        public int nativeGetPhysicalAddress(long controllerPtr) {
-            return HdmiCecController.nativeGetPhysicalAddress(controllerPtr);
+        public void nativeClearLogicalAddress() {
+            try {
+                mHdmiCec.clearLogicalAddress();
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to clear logical address : ", e);
+            }
         }
 
         @Override
-        public int nativeGetVersion(long controllerPtr) {
-            return HdmiCecController.nativeGetVersion(controllerPtr);
+        public int nativeGetPhysicalAddress() {
+            try {
+                mHdmiCec.getPhysicalAddress(this);
+                return mPhysicalAddress;
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to get physical address : ", e);
+                return INVALID_PHYSICAL_ADDRESS;
+            }
         }
 
         @Override
-        public int nativeGetVendorId(long controllerPtr) {
-            return HdmiCecController.nativeGetVendorId(controllerPtr);
+        public int nativeGetVersion() {
+            try {
+                return mHdmiCec.getCecVersion();
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to get cec version : ", e);
+                return Result.FAILURE_UNKNOWN;
+            }
         }
 
         @Override
-        public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
-            return HdmiCecController.nativeGetPortInfos(controllerPtr);
+        public int nativeGetVendorId() {
+            try {
+                return mHdmiCec.getVendorId();
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to get vendor id : ", e);
+                return Result.FAILURE_UNKNOWN;
+            }
         }
 
         @Override
-        public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {
-            HdmiCecController.nativeSetOption(controllerPtr, flag, enabled);
+        public HdmiPortInfo[] nativeGetPortInfos() {
+            try {
+                ArrayList<android.hardware.tv.cec.V1_0.HdmiPortInfo> hdmiPortInfos =
+                        mHdmiCec.getPortInfo();
+                HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.size()];
+                int i = 0;
+                for (android.hardware.tv.cec.V1_0.HdmiPortInfo portInfo : hdmiPortInfos) {
+                    hdmiPortInfo[i] = new HdmiPortInfo(portInfo.portId,
+                            portInfo.type,
+                            portInfo.physicalAddress,
+                            portInfo.cecSupported,
+                            false,
+                            portInfo.arcSupported);
+                    i++;
+                }
+                return hdmiPortInfo;
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to get port information : ", e);
+                return null;
+            }
         }
 
         @Override
-        public void nativeSetLanguage(long controllerPtr, String language) {
-            HdmiCecController.nativeSetLanguage(controllerPtr, language);
+        public void nativeSetOption(int flag, boolean enabled) {
+            try {
+                mHdmiCec.setOption(flag, enabled);
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to set option : ", e);
+            }
         }
 
         @Override
-        public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {
-            HdmiCecController.nativeEnableAudioReturnChannel(controllerPtr, port, flag);
+        public void nativeSetLanguage(String language) {
+            try {
+                mHdmiCec.setLanguage(language);
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to set language : ", e);
+            }
         }
 
         @Override
-        public boolean nativeIsConnected(long controllerPtr, int port) {
-            return HdmiCecController.nativeIsConnected(controllerPtr, port);
+        public void nativeEnableAudioReturnChannel(int port, boolean flag) {
+            try {
+                mHdmiCec.enableAudioReturnChannel(port, flag);
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to enable/disable ARC : ", e);
+            }
+        }
+
+        @Override
+        public boolean nativeIsConnected(int port) {
+            try {
+                return mHdmiCec.isConnected(port);
+            } catch (RemoteException e) {
+                HdmiLogger.error("Failed to get connection info : ", e);
+                return false;
+            }
+        }
+
+        @Override
+        public void serviceDied(long cookie) {
+            if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
+                HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting");
+                connectToHal();
+            }
+        }
+
+        @Override
+        public void onValues(int result, short addr) {
+            if (result == Result.SUCCESS) {
+                synchronized (mLock) {
+                    mPhysicalAddress = new Short(addr).intValue();
+                }
+            }
+        }
+    }
+
+    final class HdmiCecCallback extends IHdmiCecCallback.Stub {
+        @Override
+        public void onCecMessage(CecMessage message) throws RemoteException {
+            byte[] body = new byte[message.body.size()];
+            for (int i = 0; i < message.body.size(); i++) {
+                body[i] = message.body.get(i);
+            }
+            runOnServiceThread(
+                    () -> handleIncomingCecCommand(message.initiator, message.destination, body));
+        }
+
+        @Override
+        public void onHotplugEvent(HotplugEvent event) throws RemoteException {
+            runOnServiceThread(() -> handleHotplug(event.portId, event.connected));
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
index 2309293..8da3c93 100644
--- a/services/core/java/com/android/server/hdmi/HdmiLogger.java
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -18,9 +18,9 @@
 
 import android.annotation.Nullable;
 import android.os.SystemClock;
+import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
-import android.util.Log;
 
 import java.util.HashMap;
 
@@ -71,6 +71,10 @@
         getLogger().errorInternal(toLogString(logMessage, objs));
     }
 
+    static void error(String logMessage, Exception e, Object... objs) {
+        getLogger().errorInternal(toLogString(logMessage + e, objs));
+    }
+
     private void errorInternal(String logMessage) {
         String log = updateLog(mErrorTimingCache, logMessage);
         if (!log.isEmpty()) {
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index d8acf0e..85544d0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -678,8 +678,6 @@
         mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
                 GnssLocationProvider.this::onNetworkAvailable, mLooper, mNIHandler);
 
-        sendMessage(INITIALIZE_HANDLER, 0, null);
-
         mGnssStatusListenerHelper = new GnssStatusListenerHelper(mContext, mHandler) {
             @Override
             protected boolean isAvailableInPlatform() {
@@ -746,6 +744,8 @@
 
         setProperties(PROPERTIES);
         setAllowed(true);
+
+        sendMessage(INITIALIZE_HANDLER, 0, null);
     }
 
     /**
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 2721678..f882c57 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -62,6 +62,7 @@
 
     public abstract void setRouteVolume(long requestId, String routeId, int volume);
     public abstract void setSessionVolume(long requestId, String sessionId, int volume);
+    public abstract void prepareReleaseSession(@NonNull String sessionId);
 
     @NonNull
     public String getUniqueId() {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index d6b98e2..85af346 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -34,11 +34,16 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -61,6 +66,9 @@
 
     private RouteDiscoveryPreference mLastDiscoveryPreference = null;
 
+    @GuardedBy("mLock")
+    final List<RoutingSessionInfo> mReleasingSessions = new ArrayList<>();
+
     MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
             int userId) {
         super(componentName);
@@ -141,6 +149,19 @@
         }
     }
 
+    @Override
+    public void prepareReleaseSession(@NonNull String sessionId) {
+        synchronized (mLock) {
+            for (RoutingSessionInfo session : mSessionInfos) {
+                if (TextUtils.equals(session.getId(), sessionId)) {
+                    mSessionInfos.remove(session);
+                    mReleasingSessions.add(session);
+                    break;
+                }
+            }
+        }
+    }
+
     public boolean hasComponentName(String packageName, String className) {
         return mComponentName.getPackageName().equals(packageName)
                 && mComponentName.getClassName().equals(className);
@@ -300,88 +321,97 @@
     }
 
     private void onSessionCreated(Connection connection, long requestId,
-            RoutingSessionInfo sessionInfo) {
+            RoutingSessionInfo newSession) {
         if (mActiveConnection != connection) {
             return;
         }
 
-        if (sessionInfo == null) {
-            Slog.w(TAG, "onSessionCreated: Ignoring null sessionInfo sent from " + mComponentName);
+        if (newSession == null) {
+            Slog.w(TAG, "onSessionCreated: Ignoring null session sent from " + mComponentName);
             return;
         }
 
-        sessionInfo = updateSessionInfo(sessionInfo);
+        newSession = assignProviderIdForSession(newSession);
+        String newSessionId = newSession.getId();
 
-        boolean duplicateSessionAlreadyExists = false;
         synchronized (mLock) {
-            for (int i = 0; i < mSessionInfos.size(); i++) {
-                if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) {
-                    duplicateSessionAlreadyExists = true;
-                    break;
-                }
+            if (mSessionInfos.stream()
+                    .anyMatch(session -> TextUtils.equals(session.getId(), newSessionId))
+                    || mReleasingSessions.stream()
+                    .anyMatch(session -> TextUtils.equals(session.getId(), newSessionId))) {
+                Slog.w(TAG, "onSessionCreated: Duplicate session already exists. Ignoring.");
+                return;
             }
-            mSessionInfos.add(sessionInfo);
+            mSessionInfos.add(newSession);
         }
 
-        if (duplicateSessionAlreadyExists) {
-            Slog.w(TAG, "onSessionCreated: Duplicate session already exists. Ignoring.");
-            return;
-        }
-
-        mCallback.onSessionCreated(this, requestId, sessionInfo);
+        mCallback.onSessionCreated(this, requestId, newSession);
     }
 
-    private void onSessionUpdated(Connection connection, RoutingSessionInfo sessionInfo) {
+    private void onSessionUpdated(Connection connection, RoutingSessionInfo updatedSession) {
         if (mActiveConnection != connection) {
             return;
         }
-        if (sessionInfo == null) {
-            Slog.w(TAG, "onSessionUpdated: Ignoring null sessionInfo sent from "
+        if (updatedSession == null) {
+            Slog.w(TAG, "onSessionUpdated: Ignoring null session sent from "
                     + mComponentName);
             return;
         }
 
-        sessionInfo = updateSessionInfo(sessionInfo);
+        updatedSession = assignProviderIdForSession(updatedSession);
 
         boolean found = false;
         synchronized (mLock) {
             for (int i = 0; i < mSessionInfos.size(); i++) {
-                if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) {
-                    mSessionInfos.set(i, sessionInfo);
+                if (mSessionInfos.get(i).getId().equals(updatedSession.getId())) {
+                    mSessionInfos.set(i, updatedSession);
                     found = true;
                     break;
                 }
             }
+
+            if (!found) {
+                for (RoutingSessionInfo releasingSession : mReleasingSessions) {
+                    if (TextUtils.equals(releasingSession.getId(), updatedSession.getId())) {
+                        return;
+                    }
+                }
+                Slog.w(TAG, "onSessionUpdated: Matching session info not found");
+                return;
+            }
         }
 
-        if (!found) {
-            Slog.w(TAG, "onSessionUpdated: Matching session info not found");
-            return;
-        }
-
-        mCallback.onSessionUpdated(this, sessionInfo);
+        mCallback.onSessionUpdated(this, updatedSession);
     }
 
-    private void onSessionReleased(Connection connection, RoutingSessionInfo sessionInfo) {
+    private void onSessionReleased(Connection connection, RoutingSessionInfo releaedSession) {
         if (mActiveConnection != connection) {
             return;
         }
-        if (sessionInfo == null) {
-            Slog.w(TAG, "onSessionReleased: Ignoring null sessionInfo sent from " + mComponentName);
+        if (releaedSession == null) {
+            Slog.w(TAG, "onSessionReleased: Ignoring null session sent from " + mComponentName);
             return;
         }
 
-        sessionInfo = updateSessionInfo(sessionInfo);
+        releaedSession = assignProviderIdForSession(releaedSession);
 
         boolean found = false;
         synchronized (mLock) {
-            for (int i = 0; i < mSessionInfos.size(); i++) {
-                if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) {
-                    mSessionInfos.remove(i);
+            for (RoutingSessionInfo session : mSessionInfos) {
+                if (TextUtils.equals(session.getId(), releaedSession.getId())) {
+                    mSessionInfos.remove(session);
                     found = true;
                     break;
                 }
             }
+            if (!found) {
+                for (RoutingSessionInfo session : mReleasingSessions) {
+                    if (TextUtils.equals(session.getId(), releaedSession.getId())) {
+                        mReleasingSessions.remove(session);
+                        return;
+                    }
+                }
+            }
         }
 
         if (!found) {
@@ -389,10 +419,10 @@
             return;
         }
 
-        mCallback.onSessionReleased(this, sessionInfo);
+        mCallback.onSessionReleased(this, releaedSession);
     }
 
-    private RoutingSessionInfo updateSessionInfo(RoutingSessionInfo sessionInfo) {
+    private RoutingSessionInfo assignProviderIdForSession(RoutingSessionInfo sessionInfo) {
         return new RoutingSessionInfo.Builder(sessionInfo)
                 .setOwnerPackageName(mComponentName.getPackageName())
                 .setProviderId(getUniqueId())
@@ -423,6 +453,7 @@
                     mCallback.onSessionReleased(this, sessionInfo);
                 }
                 mSessionInfos.clear();
+                mReleasingSessions.clear();
             }
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 72d296f..cc95039 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,9 +16,7 @@
 
 package com.android.server.media;
 
-import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
 import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
-import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
 import static android.media.MediaRouter2Utils.getOriginalId;
 import static android.media.MediaRouter2Utils.getProviderId;
 
@@ -33,6 +31,8 @@
 import android.media.IMediaRouter2Manager;
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2ProviderService;
+import android.media.MediaRouter2Manager;
 import android.media.RouteDiscoveryPreference;
 import android.media.RoutingSessionInfo;
 import android.os.Binder;
@@ -235,30 +235,17 @@
     }
 
     public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
+            long managerRequestId, RoutingSessionInfo oldSession,
             MediaRoute2Info route, Bundle sessionHints) {
         Objects.requireNonNull(router, "router must not be null");
+        Objects.requireNonNull(oldSession, "oldSession must not be null");
         Objects.requireNonNull(route, "route must not be null");
 
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                requestCreateSessionWithRouter2Locked(requestId, router, route, sessionHints);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    public void notifySessionHintsForCreatingSession(IMediaRouter2 router,
-            long uniqueRequestId, MediaRoute2Info route, Bundle sessionHints) {
-        Objects.requireNonNull(router, "router must not be null");
-        Objects.requireNonNull(route, "route must not be null");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                notifySessionHintsForCreatingSessionLocked(uniqueRequestId,
-                        router, route, sessionHints);
+                requestCreateSessionWithRouter2Locked(requestId, managerRequestId,
+                        router, oldSession, route, sessionHints);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -417,16 +404,14 @@
     }
 
     public void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
-            String packageName, MediaRoute2Info route) {
+            RoutingSessionInfo oldSession, MediaRoute2Info route) {
         Objects.requireNonNull(manager, "manager must not be null");
-        if (TextUtils.isEmpty(packageName)) {
-            throw new IllegalArgumentException("packageName must not be empty");
-        }
+        Objects.requireNonNull(oldSession, "oldSession must not be null");
 
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                requestCreateSessionWithManagerLocked(requestId, manager, packageName, route);
+                requestCreateSessionWithManagerLocked(requestId, manager, oldSession, route);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -638,7 +623,8 @@
         }
     }
 
-    private void requestCreateSessionWithRouter2Locked(int requestId, @NonNull IMediaRouter2 router,
+    private void requestCreateSessionWithRouter2Locked(int requestId, long managerRequestId,
+            @NonNull IMediaRouter2 router, @NonNull RoutingSessionInfo oldSession,
             @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
         final IBinder binder = router.asBinder();
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
@@ -647,41 +633,60 @@
             return;
         }
 
-        if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
-                && !TextUtils.equals(route.getId(),
-                routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId())) {
-            Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
-                    + route);
-            routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
-                    routerRecord, requestId);
-            return;
+        if (managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE) {
+            ManagerRecord manager = routerRecord.mUserRecord.mHandler.findManagerWithId(
+                    toRequesterId(managerRequestId));
+            if (manager == null || manager.mLastSessionCreationRequest == null) {
+                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+                        + "Ignoring unknown request.");
+                routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
+                        routerRecord, requestId);
+                return;
+            }
+            if (!TextUtils.equals(manager.mLastSessionCreationRequest.mOldSession.getId(),
+                    oldSession.getId())) {
+                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+                        + "Ignoring unmatched routing session.");
+                routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
+                        routerRecord, requestId);
+                return;
+            }
+            if (!TextUtils.equals(manager.mLastSessionCreationRequest.mRoute.getId(),
+                    route.getId())) {
+                // When media router has no permission
+                if (!routerRecord.mHasModifyAudioRoutingPermission
+                        && manager.mLastSessionCreationRequest.mRoute.isSystemRoute()
+                        && route.isSystemRoute()) {
+                    route = manager.mLastSessionCreationRequest.mRoute;
+                } else {
+                    Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
+                            + "Ignoring unmatched route.");
+                    routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
+                            routerRecord, requestId);
+                    return;
+                }
+            }
+            manager.mLastSessionCreationRequest = null;
+        } else {
+            if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
+                    && !TextUtils.equals(route.getId(),
+                    routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId())) {
+                Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
+                        + route);
+                routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
+                        routerRecord, requestId);
+                return;
+            }
         }
 
         long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        uniqueRequestId, routerRecord, route,
+                        uniqueRequestId, managerRequestId, routerRecord, oldSession, route,
                         sessionHints));
     }
 
-    private void notifySessionHintsForCreatingSessionLocked(long uniqueRequestId,
-            @NonNull IMediaRouter2 router,
-            @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
-        final IBinder binder = router.asBinder();
-        final RouterRecord routerRecord = mAllRouterRecords.get(binder);
-
-        if (routerRecord == null) {
-            Slog.w(TAG, "notifySessionHintsForCreatingSessionLocked: Ignoring unknown router.");
-            return;
-        }
-
-        routerRecord.mUserRecord.mHandler.sendMessage(
-                obtainMessage(UserHandler::requestCreateSessionWithManagerOnHandler,
-                        routerRecord.mUserRecord.mHandler,
-                        uniqueRequestId, routerRecord, route, sessionHints));
-    }
-
     private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
             @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
         final IBinder binder = router.asBinder();
@@ -853,27 +858,46 @@
 
     private void requestCreateSessionWithManagerLocked(int requestId,
             @NonNull IMediaRouter2Manager manager,
-            @NonNull String packageName, @NonNull MediaRoute2Info route) {
+            @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) {
         ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
         if (managerRecord == null) {
             return;
         }
 
+        String packageName = oldSession.getClientPackageName();
+
         RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName);
         if (routerRecord == null) {
             Slog.w(TAG, "requestCreateSessionWithManagerLocked: Ignoring session creation for "
                     + "unknown router.");
+            try {
+                managerRecord.mManager.notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "requestCreateSessionWithManagerLocked: Failed to notify failure. "
+                        + "Manager probably died.");
+            }
             return;
         }
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
+        if (managerRecord.mLastSessionCreationRequest != null) {
+            managerRecord.mUserRecord.mHandler.notifyRequestFailedToManager(
+                    managerRecord.mManager,
+                    toOriginalRequestId(managerRecord.mLastSessionCreationRequest
+                            .mManagerRequestId),
+                    REASON_UNKNOWN_ERROR);
+            managerRecord.mLastSessionCreationRequest = null;
+        }
+        managerRecord.mLastSessionCreationRequest = new SessionCreationRequest(routerRecord,
+                MediaRoute2ProviderService.REQUEST_ID_NONE, uniqueRequestId,
+                oldSession, route);
 
         // Before requesting to the provider, get session hints from the media router.
         // As a return, media router will request to create a session.
         routerRecord.mUserRecord.mHandler.sendMessage(
-                obtainMessage(UserHandler::getSessionHintsForCreatingSessionOnHandler,
+                obtainMessage(UserHandler::requestRouterCreateSessionOnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        uniqueRequestId, routerRecord, managerRecord, route));
+                        uniqueRequestId, routerRecord, managerRecord, oldSession, route));
     }
 
     private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
@@ -887,7 +911,7 @@
 
         // Can be null if the session is system's or RCN.
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
-                .findRouterforSessionLocked(uniqueSessionId);
+                .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
@@ -908,7 +932,7 @@
 
         // Can be null if the session is system's or RCN.
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
-                .findRouterforSessionLocked(uniqueSessionId);
+                .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
@@ -929,7 +953,7 @@
 
         // Can be null if the session is system's or RCN.
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
-                .findRouterforSessionLocked(uniqueSessionId);
+                .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
@@ -966,7 +990,7 @@
         }
 
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
-                .findRouterforSessionLocked(uniqueSessionId);
+                .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
@@ -1097,6 +1121,7 @@
         public final int mPid;
         public final String mPackageName;
         public final int mManagerId;
+        public SessionCreationRequest mLastSessionCreationRequest;
 
         ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
                 int uid, int pid, String packageName) {
@@ -1222,10 +1247,20 @@
         }
 
         @Nullable
-        public RouterRecord findRouterforSessionLocked(@NonNull String uniqueSessionId) {
+        public RouterRecord findRouterWithSessionLocked(@NonNull String uniqueSessionId) {
             return mSessionToRouterMap.get(uniqueSessionId);
         }
 
+        @Nullable
+        public ManagerRecord findManagerWithId(int managerId) {
+            for (ManagerRecord manager : getManagerRecords()) {
+                if (manager.mManagerId == managerId) {
+                    return manager;
+                }
+            }
+            return null;
+        }
+
         private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
             int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
             MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
@@ -1318,26 +1353,28 @@
             return -1;
         }
 
-        private void getSessionHintsForCreatingSessionOnHandler(long uniqueRequestId,
+        private void requestRouterCreateSessionOnHandler(long uniqueRequestId,
                 @NonNull RouterRecord routerRecord, @NonNull ManagerRecord managerRecord,
-                @NonNull MediaRoute2Info route) {
-            SessionCreationRequest request =
-                    new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord);
-            mSessionCreationRequests.add(request);
-
+                @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) {
             try {
-                routerRecord.mRouter.getSessionHintsForCreatingSession(uniqueRequestId, route);
+                if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission) {
+                    routerRecord.mRouter.requestCreateSessionByManager(uniqueRequestId,
+                            oldSession, mSystemProvider.getDefaultRoute());
+                } else {
+                    routerRecord.mRouter.requestCreateSessionByManager(uniqueRequestId,
+                            oldSession, route);
+                }
             } catch (RemoteException ex) {
                 Slog.w(TAG, "getSessionHintsForCreatingSessionOnHandler: "
                         + "Failed to request. Router probably died.", ex);
-                mSessionCreationRequests.remove(request);
                 notifyRequestFailedToManager(managerRecord.mManager,
                         toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
             }
         }
 
         private void requestCreateSessionWithRouter2OnHandler(long uniqueRequestId,
-                @NonNull RouterRecord routerRecord,
+                long managerRequestId, @NonNull RouterRecord routerRecord,
+                @NonNull RoutingSessionInfo oldSession,
                 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
 
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
@@ -1350,49 +1387,14 @@
             }
 
             SessionCreationRequest request =
-                    new SessionCreationRequest(routerRecord, uniqueRequestId, route, null);
+                    new SessionCreationRequest(routerRecord, uniqueRequestId,
+                            managerRequestId, oldSession, route);
             mSessionCreationRequests.add(request);
 
             provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
                     route.getOriginalId(), sessionHints);
         }
 
-        private void requestCreateSessionWithManagerOnHandler(long uniqueRequestId,
-                @NonNull RouterRecord routerRecord,
-                @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
-            SessionCreationRequest matchingRequest = null;
-            for (SessionCreationRequest request : mSessionCreationRequests) {
-                if (request.mUniqueRequestId == uniqueRequestId) {
-                    matchingRequest = request;
-                    break;
-                }
-            }
-            if (matchingRequest == null) {
-                Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: "
-                        + "Ignoring an unknown session creation request.");
-                return;
-            }
-
-            if (!TextUtils.equals(matchingRequest.mRoute.getId(), route.getId())) {
-                Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: "
-                        + "The given route is different from the requested route.");
-                return;
-            }
-
-            final MediaRoute2Provider provider = findProvider(route.getProviderId());
-            if (provider == null) {
-                Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: Ignoring session "
-                        + "creation request since no provider found for given route=" + route);
-                mSessionCreationRequests.remove(matchingRequest);
-                notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
-                        toOriginalRequestId(uniqueRequestId), REASON_ROUTE_NOT_AVAILABLE);
-                return;
-            }
-
-            provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
-                    route.getOriginalId(), sessionHints);
-        }
-
         // routerRecord can be null if the session is system's or RCN.
         private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
                 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
@@ -1539,25 +1541,23 @@
 
         private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
                 long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
-            notifySessionCreatedToManagers(getManagers(),
-                    toOriginalRequestId(uniqueRequestId), sessionInfo);
-
-            if (uniqueRequestId == REQUEST_ID_NONE) {
-                // The session is created without any matching request.
-                return;
-            }
-
             SessionCreationRequest matchingRequest = null;
 
             for (SessionCreationRequest request : mSessionCreationRequests) {
                 if (request.mUniqueRequestId == uniqueRequestId
                         && TextUtils.equals(
-                                request.mRoute.getProviderId(), provider.getUniqueId())) {
+                        request.mRoute.getProviderId(), provider.getUniqueId())) {
                     matchingRequest = request;
                     break;
                 }
             }
 
+            long managerRequestId = (matchingRequest == null)
+                    ? MediaRoute2ProviderService.REQUEST_ID_NONE
+                    : matchingRequest.mManagerRequestId;
+            // Managers should know created session even if it's not requested.
+            notifySessionCreatedToManagers(managerRequestId, sessionInfo);
+
             if (matchingRequest == null) {
                 Slog.w(TAG, "Ignoring session creation result for unknown request. "
                         + "uniqueRequestId=" + uniqueRequestId + ", sessionInfo=" + sessionInfo);
@@ -1565,12 +1565,14 @@
             }
 
             mSessionCreationRequests.remove(matchingRequest);
-
-            if (sessionInfo == null) {
-                // Failed
-                notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
-                        toOriginalRequestId(uniqueRequestId));
-                return;
+            // Not to show old session
+            MediaRoute2Provider oldProvider =
+                    findProvider(matchingRequest.mOldSession.getProviderId());
+            if (oldProvider != null) {
+                oldProvider.prepareReleaseSession(matchingRequest.mOldSession.getId());
+            } else {
+                Slog.w(TAG, "onSessionCreatedOnHandler: Can't find provider for an old session. "
+                        + "session=" + matchingRequest.mOldSession);
             }
 
             String originalRouteId = matchingRequest.mRoute.getId();
@@ -1645,23 +1647,17 @@
             }
 
             final int requesterId = toRequesterId(uniqueRequestId);
-            for (ManagerRecord manager : getManagerRecords()) {
-                if (manager.mManagerId == requesterId) {
-                    notifyRequestFailedToManager(
-                            manager.mManager, toOriginalRequestId(uniqueRequestId), reason);
-                    return;
-                }
+            ManagerRecord manager = findManagerWithId(requesterId);
+            if (manager != null) {
+                notifyRequestFailedToManager(
+                        manager.mManager, toOriginalRequestId(uniqueRequestId), reason);
+                return;
             }
 
             // Currently, only the manager can get notified of failures.
             // TODO: Notify router too when the related callback is introduced.
         }
 
-        // TODO(b/157873556): Find a way to prevent providers from notifying error on random reqID.
-        //       Possible solutions can be:
-        //       1) Record the other type of requests too (not only session creation request)
-        //       2) Throw exception on providers when they try to notify error on
-        //          random uniqueRequestId.
         private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
                 long uniqueRequestId, int reason) {
             // Check whether the failure is about creating a session
@@ -1683,12 +1679,16 @@
 
             // Notify the requester about the failure.
             // The call should be made by either MediaRouter2 or MediaRouter2Manager.
-            if (matchingRequest.mRequestedManagerRecord == null) {
+            if (matchingRequest.mManagerRequestId == MediaRouter2Manager.REQUEST_ID_NONE) {
                 notifySessionCreationFailedToRouter(
                         matchingRequest.mRouterRecord, toOriginalRequestId(uniqueRequestId));
             } else {
-                notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
-                        toOriginalRequestId(uniqueRequestId), reason);
+                final int requesterId = toRequesterId(matchingRequest.mManagerRequestId);
+                ManagerRecord manager = findManagerWithId(requesterId);
+                if (manager != null) {
+                    notifyRequestFailedToManager(manager.mManager,
+                            toOriginalRequestId(matchingRequest.mManagerRequestId), reason);
+                }
             }
             return true;
         }
@@ -1921,14 +1921,19 @@
             }
         }
 
-        private void notifySessionCreatedToManagers(@NonNull List<IMediaRouter2Manager> managers,
-                int requestId, @NonNull RoutingSessionInfo sessionInfo) {
-            for (IMediaRouter2Manager manager : managers) {
+        private void notifySessionCreatedToManagers(long managerRequestId,
+                @NonNull RoutingSessionInfo session) {
+            int requesterId = toRequesterId(managerRequestId);
+            int originalRequestId = toOriginalRequestId(managerRequestId);
+
+            for (ManagerRecord manager : getManagerRecords()) {
                 try {
-                    manager.notifySessionCreated(requestId, sessionInfo);
+                    manager.mManager.notifySessionCreated(
+                            ((manager.mManagerId == requesterId) ? originalRequestId :
+                                    MediaRouter2Manager.REQUEST_ID_NONE), session);
                 } catch (RemoteException ex) {
                     Slog.w(TAG, "notifySessionCreatedToManagers: "
-                            + "failed to notify. Manager probably died.", ex);
+                            + "Failed to notify. Manager probably died.", ex);
                 }
             }
         }
@@ -2014,7 +2019,7 @@
                 }
                 mUserRecord.mCompositeDiscoveryPreference =
                         new RouteDiscoveryPreference.Builder(discoveryPreferences)
-                        .build();
+                                .build();
             }
             for (MediaRoute2Provider provider : mRouteProviders) {
                 provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
@@ -2030,21 +2035,22 @@
             return null;
         }
 
-        final class SessionCreationRequest {
-            public final RouterRecord mRouterRecord;
-            public final long mUniqueRequestId;
-            public final MediaRoute2Info mRoute;
-            public final ManagerRecord mRequestedManagerRecord;
+    }
+    static final class SessionCreationRequest {
+        public final RouterRecord mRouterRecord;
+        public final long mUniqueRequestId;
+        public final long mManagerRequestId;
+        public final RoutingSessionInfo mOldSession;
+        public final MediaRoute2Info mRoute;
 
-            // requestedManagerRecord is not null only when the request is made by manager.
-            SessionCreationRequest(@NonNull RouterRecord routerRecord, long uniqueRequestId,
-                    @NonNull MediaRoute2Info route,
-                    @Nullable ManagerRecord requestedManagerRecord) {
-                mRouterRecord = routerRecord;
-                mUniqueRequestId = uniqueRequestId;
-                mRoute = route;
-                mRequestedManagerRecord = requestedManagerRecord;
-            }
+        SessionCreationRequest(@NonNull RouterRecord routerRecord, long uniqueRequestId,
+                long managerRequestId, @NonNull RoutingSessionInfo oldSession,
+                @NonNull MediaRoute2Info route) {
+            mRouterRecord = routerRecord;
+            mUniqueRequestId = uniqueRequestId;
+            mManagerRequestId = managerRequestId;
+            mOldSession = oldSession;
+            mRoute = route;
         }
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 3337b48..0e52a67 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -481,16 +481,10 @@
     // Binder call
     @Override
     public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
+            long managerRequestId, RoutingSessionInfo oldSession,
             MediaRoute2Info route, Bundle sessionHints) {
-        mService2.requestCreateSessionWithRouter2(router, requestId, route, sessionHints);
-    }
-
-    // Binder call
-    @Override
-    public void notifySessionHintsForCreatingSession(IMediaRouter2 router,
-            long uniqueRequestId, MediaRoute2Info route, Bundle sessionHints) {
-        mService2.notifySessionHintsForCreatingSession(router,
-                uniqueRequestId, route, sessionHints);
+        mService2.requestCreateSessionWithRouter2(router, requestId, managerRequestId,
+                oldSession, route, sessionHints);
     }
 
     // Binder call
@@ -558,8 +552,8 @@
     // Binder call
     @Override
     public void requestCreateSessionWithManager(IMediaRouter2Manager manager,
-            int requestId, String packageName, MediaRoute2Info route) {
-        mService2.requestCreateSessionWithManager(manager, requestId, packageName, route);
+            int requestId, RoutingSessionInfo oldSession, MediaRoute2Info route) {
+        mService2.requestCreateSessionWithManager(manager, requestId, oldSession, route);
     }
 
     // Binder call
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 42d4c88..2c089ca 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -222,6 +222,11 @@
         // Do nothing since we don't support grouping volume yet.
     }
 
+    @Override
+    public void prepareReleaseSession(String sessionId) {
+        // Do nothing since the system session persists.
+    }
+
     public MediaRoute2Info getDefaultRoute() {
         return mDefaultRoute;
     }
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 8a7702e..b219e26 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -495,10 +495,15 @@
      * Adds a package that should be considered when filtering visibility between apps.
      *
      * @param newPkgSetting the new setting being added
+     * @param isReplace if the package is being replaced and may need extra cleanup.
      */
-    public void addPackage(PackageSetting newPkgSetting) {
+    public void addPackage(PackageSetting newPkgSetting, boolean isReplace) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
         try {
+            if (isReplace) {
+                // let's first remove any prior rules for this package
+                removePackage(newPkgSetting);
+            }
             mStateProvider.runWithState((settings, users) -> {
                 addPackageInternal(newPkgSetting, settings);
                 if (mShouldFilterCache != null) {
@@ -777,12 +782,20 @@
     }
 
     /**
+     * Equivalent to calling {@link #addPackage(PackageSetting, boolean)} with {@code isReplace}
+     * equal to {@code false}.
+     * @see AppsFilter#addPackage(PackageSetting, boolean)
+     */
+    public void addPackage(PackageSetting newPkgSetting) {
+        addPackage(newPkgSetting, false /* isReplace */);
+    }
+
+    /**
      * Removes a package for consideration when filtering visibility between apps.
      *
      * @param setting the setting of the package being removed.
      */
     public void removePackage(PackageSetting setting) {
-        removeAppIdFromVisibilityCache(setting.appId);
         mStateProvider.runWithState((settings, users) -> {
             final int userCount = users.length;
             for (int u = 0; u < userCount; u++) {
@@ -805,17 +818,7 @@
                 mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId);
             }
 
-            // re-add other shared user members to re-establish visibility between them and other
-            // packages
-            if (setting.sharedUser != null) {
-                for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
-                    if (setting.sharedUser.packages.valueAt(i) == setting) {
-                        continue;
-                    }
-                    addPackageInternal(
-                            setting.sharedUser.packages.valueAt(i), settings);
-                }
-            }
+            mForceQueryable.remove(setting.appId);
 
             if (setting.pkg != null && !setting.pkg.getProtectedBroadcasts().isEmpty()) {
                 final String removingPackageName = setting.pkg.getPackageName();
@@ -829,6 +832,21 @@
             mOverlayReferenceMapper.removePkg(setting.name);
             mFeatureConfig.updatePackageState(setting, true /*removed*/);
 
+            // After removing all traces of the package, if it's part of a shared user, re-add other
+            // shared user members to re-establish visibility between them and other packages.
+            // NOTE: this must come after all removals from data structures but before we update the
+            //       cache
+            if (setting.sharedUser != null) {
+                for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
+                    if (setting.sharedUser.packages.valueAt(i) == setting) {
+                        continue;
+                    }
+                    addPackageInternal(
+                            setting.sharedUser.packages.valueAt(i), settings);
+                }
+            }
+
+            removeAppIdFromVisibilityCache(setting.appId);
             if (mShouldFilterCache != null && setting.sharedUser != null) {
                 for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
                     PackageSetting siblingSetting = setting.sharedUser.packages.valueAt(i);
@@ -840,9 +858,6 @@
                 }
             }
         });
-        mForceQueryable.remove(setting.appId);
-
-
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dc7ed34..a9d3a07 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12368,7 +12368,9 @@
             ksms.addScannedPackageLPw(pkg);
 
             mComponentResolver.addAllComponents(pkg, chatty);
-            mAppsFilter.addPackage(pkgSetting);
+            final boolean isReplace =
+                    reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;
+            mAppsFilter.addPackage(pkgSetting, isReplace);
 
             // Don't allow ephemeral applications to define new permissions groups.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 3ee5f50..37f088b 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -825,7 +825,15 @@
                 return;
             }
 
-            if (pkgInfo == null || pkg == null || pkgInfo.requestedPermissions == null) {
+            if (pkgInfo == null || pkg == null || pkgInfo.applicationInfo == null
+                    || pkgInfo.requestedPermissions == null) {
+                return;
+            }
+
+            final int uid = pkgInfo.applicationInfo.uid;
+            if (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID) {
+                // Root and system server always pass permission checks, so don't touch their app
+                // ops to keep compatibility.
                 return;
             }
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 4ba58bd..39e839d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -52,6 +52,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -61,6 +62,7 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.notification.NotificationDelegate;
 import com.android.server.policy.GlobalActionsProvider;
 import com.android.server.power.ShutdownThread;
@@ -1402,6 +1404,17 @@
     }
 
     @Override
+    public void hideCurrentInputMethodForBubbles() {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            InputMethodManagerInternal.get().hideCurrentInputMethod(
+                    SoftInputShowHideReason.HIDE_BUBBLES);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
     public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
             String packageName) {
         enforceStatusBarService();
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 8fa8119..dd1d55b 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -83,7 +83,8 @@
                 if (task == null) {
                     throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                 }
-                return mService.getRecentTasks().createRecentTaskInfo(task);
+                return mService.getRecentTasks().createRecentTaskInfo(task,
+                        false /* stripExtras */);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9b5d94e..afe40b8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1185,6 +1185,9 @@
         }
 
         activity.onRemovedFromDisplay();
+        if (activity == mFixedRotationLaunchingApp) {
+            setFixedRotationLaunchingAppUnchecked(null);
+        }
     }
 
     @Override
@@ -1468,6 +1471,12 @@
             // It has been set and not yet finished.
             return true;
         }
+        if (!r.occludesParent() || r.isVisible()) {
+            // While entering or leaving a translucent or floating activity (e.g. dialog style),
+            // there is a visible activity in the background. Then it still needs rotation animation
+            // to cover the activity configuration change.
+            return false;
+        }
         if (checkOpening) {
             if (!mAppTransition.isTransitionSet() || !mOpeningApps.contains(r)) {
                 // Apply normal rotation animation in case of the activity set different requested
@@ -5636,6 +5645,12 @@
          */
         void onStartRecentsAnimation(@NonNull ActivityRecord r) {
             mAnimatingRecents = r;
+            if (r.isVisible() && mFocusedApp != null && !mFocusedApp.occludesParent()) {
+                // The recents activity has shown with the orientation determined by the top
+                // activity, keep its current orientation to avoid flicking by the configuration
+                // change of visible activity.
+                return;
+            }
             rotateInDifferentOrientationIfNeeded(r);
             if (r.hasFixedRotationTransform()) {
                 // Set the record so we can recognize it to continue to update display orientation
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index c8d9fe0..1762b62 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -351,9 +351,13 @@
     }
 
     private void updateVisibility() {
+        // TODO(b/159699383): remove the client controlled check when the insets visibility can be
+        //                    driven by the system UI.
         final boolean isClientControlled = mControlTarget != null
                 && mControlTarget.isClientControlled();
-        mSource.setVisible(mServerVisible && (!isClientControlled || mClientVisible));
+        mSource.setVisible(mServerVisible
+                && ((!isClientControlled && mDisplayContent.inMultiWindowMode())
+                    || mClientVisible));
         ProtoLog.d(WM_DEBUG_IME,
                 "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
                 mServerVisible, mClientVisible);
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 24bb7c8..1b58fc1 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -961,7 +961,7 @@
                 continue;
             }
 
-            res.add(createRecentTaskInfo(task));
+            res.add(createRecentTaskInfo(task, true /* stripExtras */));
         }
         return res;
     }
@@ -1832,9 +1832,9 @@
     /**
      * Creates a new RecentTaskInfo from a Task.
      */
-    ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr) {
+    ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
         ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
-        tr.fillTaskInfo(rti);
+        tr.fillTaskInfo(rti, stripExtras);
         // Fill in some deprecated values
         rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
         rti.persistentId = rti.taskId;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9735783..a7b1209 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3551,11 +3551,19 @@
         }
     }
 
+
     /**
      * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the
      * task info will not include any extras or clip data.
      */
     void fillTaskInfo(TaskInfo info) {
+        fillTaskInfo(info, true /* stripExtras */);
+    }
+
+    /**
+     * Fills in a {@link TaskInfo} with information from this task.
+     */
+    void fillTaskInfo(TaskInfo info, boolean stripExtras) {
         getNumRunningActivities(mReuseActivitiesReport);
         info.userId = mUserId;
         info.stackId = getRootTaskId();
@@ -3566,7 +3574,9 @@
         // Make a copy of base intent because this is like a snapshot info.
         // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it.
         final int baseIntentFlags = baseIntent == null ? 0 : baseIntent.getFlags();
-        info.baseIntent = baseIntent == null ? new Intent() : baseIntent.cloneFilter();
+        info.baseIntent = baseIntent == null
+                ? new Intent()
+                : stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent);
         info.baseIntent.setFlags(baseIntentFlags);
         info.baseActivity = mReuseActivitiesReport.base != null
                 ? mReuseActivitiesReport.base.intent.getComponent()
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
index e3453a0..b2847ce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
@@ -81,8 +82,10 @@
         doReturn(mIPackageManager).when(() -> AppGlobals.getPackageManager());
         when(mIPackageManager.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt(), anyInt())).thenReturn(
                 TEST_CALLING_UID);
+        ActivityManagerConstants constants = mock(ActivityManagerConstants.class);
+        constants.PENDINGINTENT_WARNING_THRESHOLD = 2000;
         mPendingIntentController = new PendingIntentController(Looper.getMainLooper(),
-                mUserController);
+                mUserController, constants);
         mPendingIntentController.onActivityManagerInternalAdded();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FullScreenMagnificationGestureHandlerTest.java
index 2007d4f..1cbee12 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FullScreenMagnificationGestureHandlerTest.java
@@ -20,6 +20,7 @@
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
 import static android.view.MotionEvent.ACTION_POINTER_UP;
+import static android.view.MotionEvent.ACTION_UP;
 
 import static com.android.server.testutils.TestUtils.strictMock;
 
@@ -38,11 +39,13 @@
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.content.Context;
+import android.graphics.PointF;
 import android.os.Handler;
 import android.os.Message;
 import android.util.DebugUtils;
 import android.view.InputDevice;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -56,6 +59,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.IntConsumer;
 
 /**
@@ -106,6 +112,7 @@
     // Co-prime x and y, to potentially catch x-y-swapped errors
     public static final float DEFAULT_X = 301;
     public static final float DEFAULT_Y = 299;
+    public static final PointF DEFAULT_POINT = new PointF(DEFAULT_X, DEFAULT_Y);
 
     private static final int DISPLAY_0 = 0;
 
@@ -327,6 +334,107 @@
         });
     }
 
+    @Test
+    public void testTwoFingersOneTap_zoomedState_dispatchMotionEvents() {
+        goFromStateIdleTo(STATE_ZOOMED);
+        final EventCaptor eventCaptor = new EventCaptor();
+        mMgh.setNext(eventCaptor);
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+        send(pointerEvent(ACTION_POINTER_UP, DEFAULT_X * 2, DEFAULT_Y));
+        send(upEvent());
+
+        assertIn(STATE_ZOOMED);
+        final List<Integer> expectedActions = new ArrayList();
+        expectedActions.add(Integer.valueOf(ACTION_DOWN));
+        expectedActions.add(Integer.valueOf(ACTION_POINTER_DOWN));
+        expectedActions.add(Integer.valueOf(ACTION_POINTER_UP));
+        expectedActions.add(Integer.valueOf(ACTION_UP));
+        assertActionsInOrder(eventCaptor.mEvents, expectedActions);
+
+        returnToNormalFrom(STATE_ZOOMED);
+    }
+
+    @Test
+    public void testThreeFingersOneTap_zoomedState_dispatchMotionEvents() {
+        goFromStateIdleTo(STATE_ZOOMED);
+        final EventCaptor eventCaptor = new EventCaptor();
+        mMgh.setNext(eventCaptor);
+        PointF pointer1 = DEFAULT_POINT;
+        PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+        PointF pointer3 = new PointF(DEFAULT_X * 2, DEFAULT_Y);
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2, pointer3}));
+        send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}));
+        send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}));
+        send(upEvent());
+
+        assertIn(STATE_ZOOMED);
+        final List<Integer> expectedActions = new ArrayList();
+        expectedActions.add(Integer.valueOf(ACTION_DOWN));
+        expectedActions.add(Integer.valueOf(ACTION_POINTER_DOWN));
+        expectedActions.add(Integer.valueOf(ACTION_POINTER_DOWN));
+        expectedActions.add(Integer.valueOf(ACTION_POINTER_UP));
+        expectedActions.add(Integer.valueOf(ACTION_POINTER_UP));
+        expectedActions.add(Integer.valueOf(ACTION_UP));
+        assertActionsInOrder(eventCaptor.mEvents, expectedActions);
+
+        returnToNormalFrom(STATE_ZOOMED);
+    }
+
+    @Test
+    public void testFirstFingerSwipe_TwoPinterDownAndZoomedState_panningState() {
+        goFromStateIdleTo(STATE_ZOOMED);
+        PointF pointer1 = DEFAULT_POINT;
+        PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
+        //The minimum movement to transit to panningState.
+        final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        pointer1.offset(sWipeMinDistance + 1, 0);
+        send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}));
+        assertIn(STATE_PANNING);
+
+        assertIn(STATE_PANNING);
+        returnToNormalFrom(STATE_PANNING);
+    }
+
+    @Test
+    public void testSecondFingerSwipe_TwoPinterDownAndZoomedState_panningState() {
+        goFromStateIdleTo(STATE_ZOOMED);
+        PointF pointer1 = DEFAULT_POINT;
+        PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
+        //The minimum movement to transit to panningState.
+        final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        pointer2.offset(sWipeMinDistance + 1, 0);
+        send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}));
+        assertIn(STATE_PANNING);
+
+        assertIn(STATE_PANNING);
+        returnToNormalFrom(STATE_PANNING);
+    }
+
+    private void assertActionsInOrder(List<MotionEvent> actualEvents,
+            List<Integer> expectedActions) {
+        assertTrue(actualEvents.size() == expectedActions.size());
+        final int size = actualEvents.size();
+        for (int i = 0; i < size; i++) {
+            final int expectedAction = expectedActions.get(i);
+            final int actualAction = actualEvents.get(i).getActionMasked();
+            assertTrue(String.format(
+                    "%dth action %s is not matched, actual events : %s, ", i,
+                    MotionEvent.actionToString(expectedAction), actualEvents),
+                    actualAction == expectedAction);
+        }
+    }
+
     private void assertZoomsImmediatelyOnSwipeFrom(int state) {
         goFromStateIdleTo(state);
         swipeAndHold();
@@ -467,6 +575,7 @@
                     goFromStateIdleTo(STATE_ZOOMED);
                     send(downEvent());
                     send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+                    fastForward(ViewConfiguration.getTapTimeout());
                 } break;
                 case STATE_SCALING_AND_PANNING: {
                     goFromStateIdleTo(STATE_PANNING);
@@ -619,40 +728,67 @@
                 MotionEvent.ACTION_UP, x, y, 0));
     }
 
-    private MotionEvent pointerEvent(int action, float x, float y) {
-        MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
-        defPointerProperties.id = 0;
-        defPointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
-        MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
-        pointerProperties.id = 1;
-        pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
 
-        MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
-        defPointerCoords.x = DEFAULT_X;
-        defPointerCoords.y = DEFAULT_Y;
-        MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
-        pointerCoords.x = x;
-        pointerCoords.y = y;
+    private MotionEvent pointerEvent(int action, float x, float y) {
+        return pointerEvent(action, new PointF[] {DEFAULT_POINT, new PointF(x, y)});
+    }
+
+    private MotionEvent pointerEvent(int action, PointF[] pointersPosition) {
+        final MotionEvent.PointerProperties[] PointerPropertiesArray =
+                new MotionEvent.PointerProperties[pointersPosition.length];
+        for (int i = 0; i < pointersPosition.length; i++) {
+            MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
+            pointerProperties.id = i;
+            pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+            PointerPropertiesArray[i] = pointerProperties;
+        }
+
+        final MotionEvent.PointerCoords[] pointerCoordsArray =
+                new MotionEvent.PointerCoords[pointersPosition.length];
+        for (int i = 0; i < pointersPosition.length; i++) {
+            MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
+            pointerCoords.x = pointersPosition[i].x;
+            pointerCoords.y = pointersPosition[i].y;
+            pointerCoordsArray[i] = pointerCoords;
+        }
 
         return MotionEvent.obtain(
-            /* downTime */ mClock.now(),
-            /* eventTime */ mClock.now(),
-            /* action */ action,
-            /* pointerCount */ 2,
-            /* pointerProperties */ new MotionEvent.PointerProperties[] {
-                    defPointerProperties, pointerProperties},
-            /* pointerCoords */ new MotionEvent.PointerCoords[] { defPointerCoords, pointerCoords },
-            /* metaState */ 0,
-            /* buttonState */ 0,
-            /* xPrecision */ 1.0f,
-            /* yPrecision */ 1.0f,
-            /* deviceId */ 0,
-            /* edgeFlags */ 0,
-            /* source */ InputDevice.SOURCE_TOUCHSCREEN,
-            /* flags */ 0);
+                /* downTime */ mClock.now(),
+                /* eventTime */ mClock.now(),
+                /* action */ action,
+                /* pointerCount */ pointersPosition.length,
+                /* pointerProperties */ PointerPropertiesArray,
+                /* pointerCoords */ pointerCoordsArray,
+                /* metaState */ 0,
+                /* buttonState */ 0,
+                /* xPrecision */ 1.0f,
+                /* yPrecision */ 1.0f,
+                /* deviceId */ 0,
+                /* edgeFlags */ 0,
+                /* source */ InputDevice.SOURCE_TOUCHSCREEN,
+                /* flags */ 0);
     }
 
+
     private String stateDump() {
         return "\nCurrent state dump:\n" + mMgh + "\n" + mHandler.getPendingMessages();
     }
+
+    private class EventCaptor implements EventStreamTransformation {
+        List<MotionEvent> mEvents = new ArrayList<>();
+
+        @Override
+        public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+            mEvents.add(event.copy());
+        }
+
+        @Override
+        public void setNext(EventStreamTransformation next) {
+        }
+
+        @Override
+        public EventStreamTransformation getNext() {
+            return null;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index 8607ec6..7538468 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -17,7 +17,6 @@
 
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
-import android.os.MessageQueue;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.hdmi.HdmiCecController.NativeWrapper;
@@ -53,13 +52,16 @@
     private HdmiPortInfo[] mHdmiPortInfo = null;
 
     @Override
-    public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
-        return 1L;
+    public String nativeInit() {
+        return "[class or subclass of IHdmiCec]@Proxy";
     }
 
     @Override
+    public void setCallback(HdmiCecController.HdmiCecCallback callback) {}
+
+    @Override
     public int nativeSendCecCommand(
-            long controllerPtr, int srcAddress, int dstAddress, byte[] body) {
+            int srcAddress, int dstAddress, byte[] body) {
         if (body.length == 0) {
             return mPollAddressResponse[dstAddress];
         } else {
@@ -69,30 +71,30 @@
     }
 
     @Override
-    public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
+    public int nativeAddLogicalAddress(int logicalAddress) {
         return 0;
     }
 
     @Override
-    public void nativeClearLogicalAddress(long controllerPtr) {}
+    public void nativeClearLogicalAddress() {}
 
     @Override
-    public int nativeGetPhysicalAddress(long controllerPtr) {
+    public int nativeGetPhysicalAddress() {
         return mMyPhysicalAddress;
     }
 
     @Override
-    public int nativeGetVersion(long controllerPtr) {
+    public int nativeGetVersion() {
         return 0;
     }
 
     @Override
-    public int nativeGetVendorId(long controllerPtr) {
+    public int nativeGetVendorId() {
         return 0;
     }
 
     @Override
-    public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
+    public HdmiPortInfo[] nativeGetPortInfos() {
         if (mHdmiPortInfo == null) {
             mHdmiPortInfo = new HdmiPortInfo[1];
             mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true);
@@ -101,16 +103,16 @@
     }
 
     @Override
-    public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {}
+    public void nativeSetOption(int flag, boolean enabled) {}
 
     @Override
-    public void nativeSetLanguage(long controllerPtr, String language) {}
+    public void nativeSetLanguage(String language) {}
 
     @Override
-    public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {}
+    public void nativeEnableAudioReturnChannel(int port, boolean flag) {}
 
     @Override
-    public boolean nativeIsConnected(long controllerPtr, int port) {
+    public boolean nativeIsConnected(int port) {
         return false;
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 2171d75..668f047 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1506,6 +1506,7 @@
                 .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
                 .build();
         setRotatedScreenOrientationSilently(mActivity);
+        mActivity.setVisible(false);
 
         final IWindowSession session = WindowManagerGlobal.getWindowSession();
         spyOn(session);
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 4dbf79a..1d13788 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -456,6 +456,7 @@
     @Test
     public void testTransferStartingWindowSetFixedRotation() {
         final ActivityRecord topActivity = createTestActivityRecordForGivenTask(mTask);
+        topActivity.setVisible(false);
         mTask.positionChildAt(topActivity, POSITION_TOP);
         mActivity.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 6896740..105af4f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1081,6 +1081,7 @@
         mDisplayContent.onRequestedOverrideConfigurationChanged(config);
 
         final ActivityRecord app = mAppWindow.mActivityRecord;
+        app.setVisible(false);
         mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_OPEN,
                 false /* alwaysKeepCurrent */);
         mDisplayContent.mOpeningApps.add(app);
@@ -1135,6 +1136,7 @@
         // Launch another activity before the transition is finished.
         final ActivityRecord app2 = new ActivityTestsBase.StackBuilder(mWm.mRoot)
                 .setDisplay(mDisplayContent).build().getTopMostActivity();
+        app2.setVisible(false);
         mDisplayContent.mOpeningApps.add(app2);
         app2.setRequestedOrientation(newOrientation);
 
@@ -1277,6 +1279,14 @@
         mDisplayContent.setFixedRotationLaunchingAppUnchecked(mAppWindow.mActivityRecord);
         displayRotation.setRotation((displayRotation.getRotation() + 1) % 4);
         assertTrue(displayRotation.updateRotationUnchecked(false));
+
+        // The recents activity should not apply fixed rotation if the top activity is not opaque.
+        mDisplayContent.mFocusedApp = mAppWindow.mActivityRecord;
+        doReturn(false).when(mDisplayContent.mFocusedApp).occludesParent();
+        doReturn(ROTATION_90).when(mDisplayContent).rotationForActivityInDifferentOrientation(
+                eq(recentsActivity));
+        mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
+        assertFalse(recentsActivity.hasFixedRotationTransform());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 130e555..3c98272 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -517,6 +517,7 @@
         setUpApp(new TestDisplayContent.Builder(mService, dw, dh).setNotch(notchHeight).build());
         addStatusBar(mActivity.mDisplayContent);
 
+        mActivity.setVisible(false);
         mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_OPEN,
                 false /* alwaysKeepCurrent */);
         mActivity.mDisplayContent.mOpeningApps.add(mActivity);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ee14608..8ae1ee9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -38,6 +38,7 @@
 import android.annotation.TestApi;
 import android.annotation.WorkerThread;
 import android.app.PendingIntent;
+import android.app.role.RoleManager;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
@@ -1885,12 +1886,23 @@
      * Returns the unique device ID, for example, the IMEI for GSM and the MEID
      * or ESN for CDMA phones. Return null if device ID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
-     * is an app that owns a managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) on any
+     *     active subscription.
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -1927,12 +1939,23 @@
      * Returns the unique device ID of a subscription, for example, the IMEI for
      * GSM and the MEID for CDMA phones. Return null if device ID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
-     * is an app that owns a managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) on any
+     *     active subscription.
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -1985,18 +2008,23 @@
      * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
      * available.
      *
-     * <p>This API requires one of the following:
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
      * <ul>
-     *     <li>The caller holds the READ_PRIVILEGED_PHONE_STATE permission.</li>
-     *     <li>If the caller is the device or profile owner, the caller holds the
-     *     {@link Manifest.permission#READ_PHONE_STATE} permission.</li>
-     *     <li>The caller has carrier privileges (see {@link #hasCarrierPrivileges()} on any
-     *     active subscription.</li>
-     *     <li>The caller is the default SMS app for the device.</li>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) on any
+     *     active subscription.
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
      * </ul>
-     * <p>The profile owner is an app that owns a managed profile on the device; for more details
-     * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
-     * Access by profile owners is deprecated and will be removed in a future release.
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -2058,12 +2086,23 @@
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
-     * is an app that owns a managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) on any
+     *     active subscription.
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -2085,12 +2124,23 @@
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
-     * is an app that owns a managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) on any
+     *     active subscription.
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -2158,12 +2208,25 @@
     /**
      * Returns the Network Access Identifier (NAI). Return null if NAI is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
+     *
+     * <p>If the calling app does not meet one of these requirements then this method will behave
+     * as follows:
      *
      * <ul>
      *     <li>If the calling app's target SDK is API level 28 or lower and the app has the
@@ -2182,12 +2245,25 @@
     /**
      * Returns the NAI. Return null if NAI is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
+     *
+     * <p>If the calling app does not meet one of these requirements then this method will behave
+     * as follows:
      *
      * <ul>
      *     <li>If the calling app's target SDK is API level 28 or lower and the app has the
@@ -3775,12 +3851,22 @@
      * Returns the serial number of the SIM, if applicable. Return null if it is
      * unavailable.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -3803,12 +3889,22 @@
      * Returns the serial number for the given subscription, if applicable. Return null if it is
      * unavailable.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -4047,12 +4143,22 @@
      * Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
      * Return null if it is unavailable.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
@@ -4076,12 +4182,22 @@
      * for a subscription.
      * Return null if it is unavailable.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
-     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
-     * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
-     * access is deprecated and will be removed in a future release.
+     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
+     * restrictions, and apps are recommended to use resettable identifiers (see <a
+     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
+     * the following requirements is met:
+     * <ul>
+     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+     *     is a privileged permission that can only be granted to apps preloaded on the device.
+     *     <li>If the calling app is the device or profile owner and has been granted the
+     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
+     *     owns a managed profile on the device; for more details see <a
+     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+     *     Profile owner access is deprecated and will be removed in a future release.
+     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     <li>If the calling app is the default SMS role holder (see {@link
+     *     RoleManager#isRoleHeld(String)}).
+     * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
      * as follows:
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 2bcd4f4..a5e76e6 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -885,7 +885,8 @@
 
         /**
          * Configure the Soft AP to require manual user control of client association.
-         * If disabled (the default) then any client can associate to this Soft AP using the
+         * If disabled (the default) then any client which isn't in the blocked list
+         * {@link #getBlockedClientList()} can associate to this Soft AP using the
          * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier,
          * or user limited - using {@link #setMaxNumberOfClients(int)}).
          *
@@ -945,21 +946,19 @@
         }
 
         /**
-         * This method together with {@link setClientControlByUserEnabled(boolean)} control client
-         * connections to the AP. If client control by user is disabled using the above method then
-         * this API has no effect and clients are allowed to associate to the AP (within limit of
-         * max number of clients).
+         * This API configures the list of clients which are blocked and cannot associate
+         * to the Soft AP.
          *
-         * If client control by user is enabled then this API this API configures the list of
-         * clients which are blocked. These are rejected.
+         * <p>
+         * This method requires hardware support. Hardware support can be determined using
+         * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+         * {@link SoftApCapability#areFeaturesSupported(int)}
+         * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
          *
-         * All other clients which attempt to associate, whose MAC addresses are on neither list,
-         * are:
-         * <ul>
-         * <li>Rejected</li>
-         * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)}
-         * is issued (which allows the user to add them to the allowed client list if desired).<li>
-         * </ul>
+         * <p>
+         * If the method is called on a device without hardware support then starting the soft AP
+         * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
+         * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
          *
          * @param blockedClientList list of clients which are not allowed to associate to the AP.
          * @return Builder for chaining.
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index d35ce3c..77fa673 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -93,6 +93,8 @@
     public static final String OPP_KEY_CACHING     = "proactive_key_caching";
     /** @hide */
     public static final String EAP_ERP             = "eap_erp";
+    /** @hide */
+    public static final String OCSP                = "ocsp";
 
     /**
      * String representing the keystore OpenSSL ENGINE's ID.