Merge "[gallery] SearchScaffoldPageProvider" into main
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index f40efc8..218d4bb 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -186,6 +186,8 @@
     /**
      * Get the binder transaction observer for this process.
      *
+     * TODO(b/299356196): only applies to Java code, not C++/Rust
+     *
      * @hide
      */
     public static void setObserver(@Nullable BinderInternal.Observer observer) {
@@ -202,6 +204,8 @@
      * that require a result must be sent as {@link IBinder#FLAG_ONEWAY} calls
      * which deliver results through a callback interface.
      *
+     * TODO(b/299355525): only applies to Java code, not C++/Rust
+     *
      * @hide
      */
     public static void setWarnOnBlocking(boolean warnOnBlocking) {
@@ -218,6 +222,8 @@
      * interfaces hosted by package that could be upgraded or replaced,
      * otherwise you risk system instability if that remote interface wedges.
      *
+     * TODO(b/299355525): only applies to Java code, not C++/Rust
+     *
      * @hide
      */
     public static IBinder allowBlocking(IBinder binder) {
@@ -1307,6 +1313,8 @@
             int callingUid) {
         // Make sure the observer won't change while processing a transaction.
         final BinderInternal.Observer observer = sObserver;
+
+        // TODO(b/299356196): observer should also observe transactions in native code
         final CallSession callSession =
                 observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null;
         // Theoretically, we should call transact, which will call onTransact,
@@ -1329,7 +1337,7 @@
 
         final boolean tracingEnabled = tagEnabled && transactionTraceName != null;
         try {
-            // TODO - this logic should not be in Java - it should be in native
+            // TODO(b/299356201) - this logic should not be in Java - it should be in native
             // code in libbinder so that it works for all binder users.
             final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
             if (heavyHitterWatcher != null && callingUid != -1) {
@@ -1340,9 +1348,9 @@
                 Trace.traceBegin(Trace.TRACE_TAG_AIDL, transactionTraceName);
             }
 
-            // TODO - this logic should not be in Java - it should be in native
-            // code in libbinder so that it works for all binder users. Further,
-            // this should not re-use flags.
+            // TODO(b/299353919) - this logic should not be in Java - it should be
+            // in native code in libbinder so that it works for all binder users.
+            // Further, this should not re-use flags.
             if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0 && callingUid != -1) {
                 AppOpsManager.startNotedAppOpsCollection(callingUid);
                 try {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 05063365..ac0e493 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -27,6 +27,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
 import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
+
 import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
 
 import android.R;
@@ -240,7 +241,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastMath;
 import com.android.internal.util.Preconditions;
-import com.android.text.flags.Flags;
 
 import libcore.util.EmptyArray;
 
@@ -1634,7 +1634,7 @@
         }
 
         if (CompatChanges.isChangeEnabled(USE_BOUNDS_FOR_WIDTH)) {
-            mUseBoundsForWidth = Flags.useBoundsForWidth();
+            mUseBoundsForWidth = false;  // TODO: Connect to the flag.
         } else {
             mUseBoundsForWidth = false;
         }
diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp
index 233aee2..fe26dc3 100644
--- a/packages/CredentialManager/Android.bp
+++ b/packages/CredentialManager/Android.bp
@@ -50,46 +50,3 @@
         proguard_compatibility: false,
     },
 }
-
-android_app {
-    name: "ClockworkCredentialManager",
-    defaults: ["platform_app_defaults"],
-    certificate: "platform",
-    manifest: "wear/AndroidManifest.xml",
-    srcs: ["wear/src/**/*.kt"],
-    resource_dirs: ["wear/res"],
-
-    dex_preopt: {
-        profile_guided: true,
-        profile: "wear/profile.txt.prof",
-    },
-
-    static_libs: [
-        "PlatformComposeCore",
-        "androidx.activity_activity-compose",
-        "androidx.appcompat_appcompat",
-        "androidx.compose.foundation_foundation",
-        "androidx.compose.foundation_foundation-layout",
-        "androidx.compose.material_material-icons-core",
-        "androidx.compose.material_material-icons-extended",
-        "androidx.compose.ui_ui",
-        "androidx.core_core-ktx",
-        "androidx.credentials_credentials",
-        "androidx.lifecycle_lifecycle-extensions",
-        "androidx.lifecycle_lifecycle-livedata",
-        "androidx.lifecycle_lifecycle-runtime-ktx",
-        "androidx.lifecycle_lifecycle-viewmodel-compose",
-        "androidx.wear.compose_compose-foundation",
-        "androidx.wear.compose_compose-material",
-        "kotlinx-coroutines-core",
-    ],
-
-    platform_apis: true,
-    privileged: true,
-
-    kotlincflags: ["-Xjvm-default=all"],
-
-    optimize: {
-        proguard_compatibility: false,
-    },
-}
diff --git a/packages/CredentialManager/wear/Android.bp b/packages/CredentialManager/wear/Android.bp
new file mode 100644
index 0000000..639e8d1
--- /dev/null
+++ b/packages/CredentialManager/wear/Android.bp
@@ -0,0 +1,53 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+    name: "ClockworkCredentialManager",
+    defaults: ["platform_app_defaults"],
+    certificate: "platform",
+    manifest: "AndroidManifest.xml",
+    srcs: ["src/**/*.kt"],
+    resource_dirs: ["res"],
+
+    dex_preopt: {
+        profile_guided: true,
+        profile: "profile.txt.prof",
+    },
+
+    static_libs: [
+        "Horologist",
+        "PlatformComposeCore",
+        "androidx.activity_activity-compose",
+        "androidx.appcompat_appcompat",
+        "androidx.compose.foundation_foundation",
+        "androidx.compose.foundation_foundation-layout",
+        "androidx.compose.material_material-icons-core",
+        "androidx.compose.material_material-icons-extended",
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.ui_ui",
+        "androidx.core_core-ktx",
+        "androidx.lifecycle_lifecycle-extensions",
+        "androidx.lifecycle_lifecycle-livedata",
+        "androidx.lifecycle_lifecycle-runtime-ktx",
+        "androidx.lifecycle_lifecycle-viewmodel-compose",
+        "androidx.wear.compose_compose-foundation",
+        "androidx.wear.compose_compose-material",
+        "androidx.wear.compose_compose-navigation",
+        "kotlinx-coroutines-core",
+    ],
+
+    platform_apis: true,
+    privileged: true,
+
+    kotlincflags: ["-Xjvm-default=all"],
+
+    optimize: {
+        proguard_compatibility: false,
+    },
+}
diff --git a/packages/CredentialManager/wear/AndroidManifest.xml b/packages/CredentialManager/wear/AndroidManifest.xml
index 001a56d..90248734 100644
--- a/packages/CredentialManager/wear/AndroidManifest.xml
+++ b/packages/CredentialManager/wear/AndroidManifest.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 /*
- * Copyright (c) 2017 Google Inc.
+ * Copyright (c) 2023 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.credentialmanager">
 
+    <uses-feature android:name="android.hardware.type.watch" />
+
     <uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/>
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
     <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
@@ -28,17 +30,15 @@
       android:dataExtractionRules="@xml/data_extraction_rules"
       android:fullBackupContent="@xml/backup_rules"
       android:label="@string/app_name"
-      android:supportsRtl="true"
-      android:theme="@style/Theme.CredentialSelector">
+      android:supportsRtl="true">
 
         <activity
-            android:name=".CredentialSelectorActivity"
+            android:name=".ui.CredentialSelectorActivity"
             android:exported="true"
             android:permission="android.permission.LAUNCH_CREDENTIAL_SELECTOR"
             android:launchMode="singleTop"
             android:label="@string/app_name"
-            android:excludeFromRecents="true"
-            android:theme="@style/Theme.CredentialSelector">
+            android:excludeFromRecents="true">
         </activity>
   </application>
 
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/CredentialSelectorActivity.kt
similarity index 68%
rename from packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
rename to packages/CredentialManager/wear/src/com/android/credentialmanager/ui/CredentialSelectorActivity.kt
index f7b2499..77fffaa 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/CredentialSelectorActivity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,19 +14,29 @@
  * limitations under the License.
  */
 
+package com.android.credentialmanager.ui
+
 import android.os.Bundle
-import androidx.activity.compose.setContent
 import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.navigation.NavHostController
 import androidx.wear.compose.material.MaterialTheme
-import androidx.wear.compose.material.Text
+import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
 
 class CredentialSelectorActivity : ComponentActivity() {
+
+    lateinit var navController: NavHostController
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
+        setTheme(android.R.style.Theme_DeviceDefault)
+
         setContent {
+            navController = rememberSwipeDismissableNavController()
+
             MaterialTheme {
-                Text("Credential Manager entry point")
+                WearApp(navController = navController)
             }
         }
     }
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/Screen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/Screen.kt
new file mode 100644
index 0000000..ee6ea5e
--- /dev/null
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/Screen.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 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.0N
+ *
+ * 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.credentialmanager.ui
+
+sealed class Screen(
+    val route: String,
+) {
+    object Main : Screen("main")
+}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
new file mode 100644
index 0000000..5ec0c8c
--- /dev/null
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 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.0N
+ *
+ * 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.
+ */
+
+@file:OptIn(ExperimentalHorologistApi::class)
+
+package com.android.credentialmanager.ui
+
+import androidx.compose.runtime.Composable
+import androidx.navigation.NavHostController
+import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
+import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState
+import com.android.credentialmanager.ui.screens.MainScreen
+import com.google.android.horologist.annotations.ExperimentalHorologistApi
+import com.google.android.horologist.compose.navscaffold.WearNavScaffold
+import com.google.android.horologist.compose.navscaffold.composable
+
+@Composable
+fun WearApp(
+    navController: NavHostController
+) {
+    val swipeToDismissBoxState = rememberSwipeToDismissBoxState()
+    val navHostState =
+        rememberSwipeDismissableNavHostState(swipeToDismissBoxState = swipeToDismissBoxState)
+
+    WearNavScaffold(
+        startDestination = Screen.Main.route,
+        navController = navController,
+        state = navHostState,
+    ) {
+        composable(Screen.Main.route) {
+            MainScreen()
+        }
+    }
+}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/MainScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/MainScreen.kt
new file mode 100644
index 0000000..662d710
--- /dev/null
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/MainScreen.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.0N
+ *
+ * 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.credentialmanager.ui.screens
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.wear.compose.material.Text
+
+@Composable
+fun MainScreen(modifier: Modifier = Modifier) {
+    Box(modifier = modifier, contentAlignment = Alignment.Center) {
+        Text("This is a placeholder for the main screen.")
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
index fe1034a..3f609a2 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
@@ -65,12 +65,6 @@
      * [NoteTaskController], ensure custom actions can be triggered (i.e., keyboard shortcut).
      */
     private fun initializeHandleSystemKey() {
-        val callbacks =
-            object : CommandQueue.Callbacks {
-                override fun handleSystemKey(key: KeyEvent) {
-                    key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask)
-                }
-            }
         commandQueue.addCallback(callbacks)
     }
 
@@ -142,7 +136,7 @@
  */
 private fun KeyEvent.toNoteTaskEntryPointOrNull(): NoteTaskEntryPoint? =
     when {
-        keyCode == KEYCODE_STYLUS_BUTTON_TAIL -> TAIL_BUTTON
+        keyCode == KEYCODE_STYLUS_BUTTON_TAIL && action == KeyEvent.ACTION_UP -> TAIL_BUTTON
         keyCode == KEYCODE_N && isMetaPressed && isCtrlPressed -> KEYBOARD_SHORTCUT
         else -> null
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
index 95bb3e0..162b7b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
@@ -22,6 +22,8 @@
 import android.testing.AndroidTestingRunner
 import android.view.KeyEvent
 import android.view.KeyEvent.ACTION_DOWN
+import android.view.KeyEvent.ACTION_UP
+import android.view.KeyEvent.KEYCODE_N
 import android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
@@ -30,7 +32,6 @@
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -43,7 +44,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
@@ -66,6 +66,7 @@
 
     private val executor = FakeExecutor(FakeSystemClock())
     private val userTracker = FakeUserTracker()
+    private val handlerCallbacks = mutableListOf<Runnable>()
 
     @Before
     fun setUp() {
@@ -74,19 +75,27 @@
     }
 
     private fun createUnderTest(
-            isEnabled: Boolean,
-            bubbles: Bubbles?,
+        isEnabled: Boolean,
+        bubbles: Bubbles?,
     ): NoteTaskInitializer =
-            NoteTaskInitializer(
-                    controller = controller,
-                    commandQueue = commandQueue,
-                    optionalBubbles = Optional.ofNullable(bubbles),
-                    isEnabled = isEnabled,
-                    roleManager = roleManager,
-                    userTracker = userTracker,
-                    keyguardUpdateMonitor = keyguardMonitor,
-                    backgroundExecutor = executor,
-            )
+        NoteTaskInitializer(
+            controller = controller,
+            commandQueue = commandQueue,
+            optionalBubbles = Optional.ofNullable(bubbles),
+            isEnabled = isEnabled,
+            roleManager = roleManager,
+            userTracker = userTracker,
+            keyguardUpdateMonitor = keyguardMonitor,
+            backgroundExecutor = executor,
+        )
+
+    private fun createKeyEvent(
+        action: Int,
+        code: Int,
+        downTime: Long = 0L,
+        eventTime: Long = 0L,
+        metaState: Int = 0
+    ): KeyEvent = KeyEvent(downTime, eventTime, action, code, 0 /*repeat*/, metaState)
 
     @Test
     fun initialize_withUserUnlocked() {
@@ -120,12 +129,12 @@
         underTest.initialize()
 
         verifyZeroInteractions(
-                commandQueue,
-                bubbles,
-                controller,
-                roleManager,
-                userManager,
-                keyguardMonitor,
+            commandQueue,
+            bubbles,
+            controller,
+            roleManager,
+            userManager,
+            keyguardMonitor,
         )
     }
 
@@ -136,18 +145,23 @@
         underTest.initialize()
 
         verifyZeroInteractions(
-                commandQueue,
-                bubbles,
-                controller,
-                roleManager,
-                userManager,
-                keyguardMonitor,
+            commandQueue,
+            bubbles,
+            controller,
+            roleManager,
+            userManager,
+            keyguardMonitor,
         )
     }
 
     @Test
     fun initialize_handleSystemKey() {
-        val expectedKeyEvent = KeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL)
+        val expectedKeyEvent =
+            createKeyEvent(
+                ACTION_DOWN,
+                KEYCODE_N,
+                metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+            )
         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
         underTest.initialize()
         val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
@@ -176,7 +190,7 @@
         underTest.initialize()
         val callback = withArgCaptor {
             verify(roleManager)
-                    .addOnRoleHoldersChangedListenerAsUser(any(), capture(), eq(UserHandle.ALL))
+                .addOnRoleHoldersChangedListenerAsUser(any(), capture(), eq(UserHandle.ALL))
         }
 
         callback.onRoleHoldersChanged(ROLE_NOTES, userTracker.userHandle)
@@ -203,4 +217,22 @@
 
         verify(controller, times(2)).updateNoteTaskForCurrentUserAndManagedProfiles()
     }
+
+    @Test
+    fun tailButtonGestureDetection_singlePress_shouldShowNoteTaskOnUp() {
+        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
+        underTest.initialize()
+        val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
+
+        callback.handleSystemKey(
+            createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0)
+        )
+        verify(controller, never()).showNoteTask(any())
+
+        callback.handleSystemKey(
+            createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 50)
+        )
+
+        verify(controller).showNoteTask(any())
+    }
 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4d38239..b420acd 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4773,7 +4773,7 @@
             case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
             case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
             case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL: {
-                if (down && mStylusButtonsEnabled) {
+                if (mStylusButtonsEnabled) {
                     sendSystemKeyToStatusBarAsync(event);
                 }
                 result &= ~ACTION_PASS_TO_USER;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9c9c63f..f38f6b0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1843,8 +1843,12 @@
             RemoteCallback navigationObserver, BackAnimationAdapter adapter) {
         mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
                 "startBackNavigation()");
-
-        return mBackNavigationController.startBackNavigation(navigationObserver, adapter);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            return mBackNavigationController.startBackNavigation(navigationObserver, adapter);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 881fdec..bbafa25 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1614,13 +1614,6 @@
             }
         }
 
-        // Take task snapshots before the animation so that we can capture IME before it gets
-        // transferred. If transition is transient, IME won't be moved during the transition and
-        // the tasks are still live, so we take the snapshot at the end of the transition instead.
-        if (mTransientLaunches == null) {
-            mController.mSnapshotController.onTransactionReady(mType, mTargets);
-        }
-
         // This is non-null only if display has changes. It handles the visible windows that don't
         // need to be participated in the transition.
         for (int i = 0; i < mTargetDisplays.size(); ++i) {
@@ -1671,6 +1664,16 @@
 
         reportStartReasonsToLogger();
 
+        // Take snapshots for closing tasks/activities before the animation finished but after
+        // dispatching onTransitionReady, so IME (if there is) can be captured together and the
+        // time spent on snapshot won't delay the start of animation. Note that if this transition
+        // is transient (mTransientLaunches != null), the snapshot will be captured at the end of
+        // the transition, because IME won't move be moved during the transition and the tasks are
+        // still live.
+        if (mTransientLaunches == null) {
+            mController.mSnapshotController.onTransactionReady(mType, mTargets);
+        }
+
         // Since we created root-leash but no longer reference it from core, release it now
         info.releaseAnimSurfaces();