Merge "Adjust cancel back navigation conditions." into udc-dev am: 67182c205b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21470967 Change-Id: I8e57e7c5c2f14e0447a7677e64ee8ddfae54f4d1 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -65,12 +65,12 @@ import android.os.Debug;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.IProgressListener;
|
import android.os.IProgressListener;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.RemoteCallback;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.os.WorkSource;
|
import android.os.WorkSource;
|
||||||
import android.service.voice.IVoiceInteractionSession;
|
import android.service.voice.IVoiceInteractionSession;
|
||||||
import android.view.IRecentsAnimationRunner;
|
import android.view.IRecentsAnimationRunner;
|
||||||
import android.view.IRemoteAnimationRunner;
|
import android.view.IRemoteAnimationRunner;
|
||||||
import android.view.IWindowFocusObserver;
|
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
import android.view.RemoteAnimationAdapter;
|
import android.view.RemoteAnimationAdapter;
|
||||||
import android.window.IWindowOrganizerController;
|
import android.window.IWindowOrganizerController;
|
||||||
@@ -349,12 +349,13 @@ interface IActivityTaskManager {
|
|||||||
/**
|
/**
|
||||||
* Prepare the back navigation in the server. This setups the leashed for sysui to animate
|
* Prepare the back navigation in the server. This setups the leashed for sysui to animate
|
||||||
* the back gesture and returns the data needed for the animation.
|
* the back gesture and returns the data needed for the animation.
|
||||||
* @param focusObserver a remote callback to nofify shell when the focused window lost focus.
|
* @param navigationObserver a remote callback to nofify shell when the focused window is gone,
|
||||||
|
or an unexpected transition has happened on the navigation target.
|
||||||
* @param adaptor a remote animation to be run for the back navigation plays the animation.
|
* @param adaptor a remote animation to be run for the back navigation plays the animation.
|
||||||
* @return Returns the back navigation info.
|
* @return Returns the back navigation info.
|
||||||
*/
|
*/
|
||||||
android.window.BackNavigationInfo startBackNavigation(
|
android.window.BackNavigationInfo startBackNavigation(
|
||||||
in IWindowFocusObserver focusObserver, in BackAnimationAdapter adaptor);
|
in RemoteCallback navigationObserver, in BackAnimationAdapter adaptor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* registers a callback to be invoked when the screen is captured.
|
* registers a callback to be invoked when the screen is captured.
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ import android.content.Context;
|
|||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.hardware.input.InputManager;
|
import android.hardware.input.InputManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.RemoteCallback;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
@@ -39,7 +40,6 @@ import android.provider.Settings.Global;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.IRemoteAnimationRunner;
|
import android.view.IRemoteAnimationRunner;
|
||||||
import android.view.IWindowFocusObserver;
|
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.KeyCharacterMap;
|
import android.view.KeyCharacterMap;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@@ -121,23 +121,22 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
|||||||
private IOnBackInvokedCallback mActiveCallback;
|
private IOnBackInvokedCallback mActiveCallback;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final IWindowFocusObserver mFocusObserver = new IWindowFocusObserver.Stub() {
|
final RemoteCallback mNavigationObserver = new RemoteCallback(
|
||||||
@Override
|
new RemoteCallback.OnResultListener() {
|
||||||
public void focusGained(IBinder inputToken) { }
|
@Override
|
||||||
@Override
|
public void onResult(@Nullable Bundle result) {
|
||||||
public void focusLost(IBinder inputToken) {
|
mShellExecutor.execute(() -> {
|
||||||
mShellExecutor.execute(() -> {
|
if (!mBackGestureStarted || mPostCommitAnimationInProgress) {
|
||||||
if (!mBackGestureStarted || mPostCommitAnimationInProgress) {
|
// If an uninterruptible animation is already in progress, we should
|
||||||
// If an uninterruptible animation is already in progress, we should ignore
|
// ignore this due to it may cause focus lost. (alpha = 0)
|
||||||
// this due to it may cause focus lost. (alpha = 0)
|
return;
|
||||||
return;
|
}
|
||||||
|
ProtoLog.i(WM_SHELL_BACK_PREVIEW, "Navigation window gone.");
|
||||||
|
setTriggerBack(false);
|
||||||
|
onGestureFinished(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
ProtoLog.i(WM_SHELL_BACK_PREVIEW, "Target window lost focus.");
|
|
||||||
setTriggerBack(false);
|
|
||||||
onGestureFinished(false);
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final BackAnimationBackground mAnimationBackground;
|
private final BackAnimationBackground mAnimationBackground;
|
||||||
|
|
||||||
@@ -351,7 +350,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
mBackNavigationInfo = mActivityTaskManager.startBackNavigation(
|
mBackNavigationInfo = mActivityTaskManager.startBackNavigation(
|
||||||
mFocusObserver, mEnableAnimations.get() ? mBackAnimationAdapter : null);
|
mNavigationObserver, mEnableAnimations.get() ? mBackAnimationAdapter : null);
|
||||||
onBackNavigationInfoReceived(mBackNavigationInfo);
|
onBackNavigationInfoReceived(mBackNavigationInfo);
|
||||||
} catch (RemoteException remoteException) {
|
} catch (RemoteException remoteException) {
|
||||||
Log.e(TAG, "Failed to initAnimation", remoteException);
|
Log.e(TAG, "Failed to initAnimation", remoteException);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import static org.mockito.ArgumentMatchers.eq;
|
|||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.reset;
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
@@ -40,7 +39,6 @@ import android.graphics.Point;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.RemoteCallback;
|
import android.os.RemoteCallback;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -341,8 +339,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
|||||||
mController.setTriggerBack(true); // Fake trigger back
|
mController.setTriggerBack(true); // Fake trigger back
|
||||||
|
|
||||||
// In case the focus has been changed.
|
// In case the focus has been changed.
|
||||||
IBinder token = mock(IBinder.class);
|
mController.mNavigationObserver.sendResult(null);
|
||||||
mController.mFocusObserver.focusLost(token);
|
|
||||||
mShellExecutor.flushAll();
|
mShellExecutor.flushAll();
|
||||||
verify(mAnimatorCallback).onBackCancelled();
|
verify(mAnimatorCallback).onBackCancelled();
|
||||||
|
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ import android.os.Parcel;
|
|||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManagerInternal;
|
import android.os.PowerManagerInternal;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.os.RemoteCallback;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
@@ -228,7 +229,6 @@ import android.util.SparseArray;
|
|||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
import android.view.IRecentsAnimationRunner;
|
import android.view.IRecentsAnimationRunner;
|
||||||
import android.view.IWindowFocusObserver;
|
|
||||||
import android.view.RemoteAnimationAdapter;
|
import android.view.RemoteAnimationAdapter;
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
@@ -1853,11 +1853,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BackNavigationInfo startBackNavigation(
|
public BackNavigationInfo startBackNavigation(
|
||||||
IWindowFocusObserver observer, BackAnimationAdapter adapter) {
|
RemoteCallback navigationObserver, BackAnimationAdapter adapter) {
|
||||||
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
|
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
|
||||||
"startBackNavigation()");
|
"startBackNavigation()");
|
||||||
|
|
||||||
return mBackNavigationController.startBackNavigation(observer, adapter);
|
return mBackNavigationController.startBackNavigation(navigationObserver, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ public class AppTransitionController {
|
|||||||
|
|
||||||
ArraySet<ActivityRecord> tmpOpenApps = mDisplayContent.mOpeningApps;
|
ArraySet<ActivityRecord> tmpOpenApps = mDisplayContent.mOpeningApps;
|
||||||
ArraySet<ActivityRecord> tmpCloseApps = mDisplayContent.mClosingApps;
|
ArraySet<ActivityRecord> tmpCloseApps = mDisplayContent.mClosingApps;
|
||||||
if (mDisplayContent.mAtmService.mBackNavigationController.isWaitBackTransition()) {
|
if (mDisplayContent.mAtmService.mBackNavigationController.isMonitoringTransition()) {
|
||||||
tmpOpenApps = new ArraySet<>(mDisplayContent.mOpeningApps);
|
tmpOpenApps = new ArraySet<>(mDisplayContent.mOpeningApps);
|
||||||
tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps);
|
tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps);
|
||||||
if (mDisplayContent.mAtmService.mBackNavigationController
|
if (mDisplayContent.mAtmService.mBackNavigationController
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import android.os.SystemProperties;
|
|||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
import android.view.IWindowFocusObserver;
|
|
||||||
import android.view.RemoteAnimationTarget;
|
import android.view.RemoteAnimationTarget;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
@@ -66,11 +65,11 @@ import java.util.function.Consumer;
|
|||||||
class BackNavigationController {
|
class BackNavigationController {
|
||||||
private static final String TAG = "BackNavigationController";
|
private static final String TAG = "BackNavigationController";
|
||||||
private WindowManagerService mWindowManagerService;
|
private WindowManagerService mWindowManagerService;
|
||||||
private IWindowFocusObserver mFocusObserver;
|
|
||||||
private boolean mBackAnimationInProgress;
|
private boolean mBackAnimationInProgress;
|
||||||
private @BackNavigationInfo.BackTargetType int mLastBackType;
|
private @BackNavigationInfo.BackTargetType int mLastBackType;
|
||||||
private boolean mShowWallpaper;
|
private boolean mShowWallpaper;
|
||||||
private Runnable mPendingAnimation;
|
private Runnable mPendingAnimation;
|
||||||
|
private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();
|
||||||
|
|
||||||
private AnimationHandler mAnimationHandler;
|
private AnimationHandler mAnimationHandler;
|
||||||
private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
|
private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
|
||||||
@@ -86,6 +85,11 @@ class BackNavigationController {
|
|||||||
return SystemProperties.getInt("persist.wm.debug.predictive_back_screenshot", 0) != 0;
|
return SystemProperties.getInt("persist.wm.debug.predictive_back_screenshot", 0) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify focus window changed
|
||||||
|
void onFocusChanged(WindowState newFocus) {
|
||||||
|
mNavigationMonitor.onFocusWindowChanged(newFocus);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the necessary leashes and build a {@link BackNavigationInfo} instance for an upcoming
|
* Set up the necessary leashes and build a {@link BackNavigationInfo} instance for an upcoming
|
||||||
* back gesture animation.
|
* back gesture animation.
|
||||||
@@ -96,13 +100,12 @@ class BackNavigationController {
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@Nullable
|
@Nullable
|
||||||
BackNavigationInfo startBackNavigation(
|
BackNavigationInfo startBackNavigation(@NonNull RemoteCallback navigationObserver,
|
||||||
IWindowFocusObserver observer, BackAnimationAdapter adapter) {
|
BackAnimationAdapter adapter) {
|
||||||
if (!sPredictBackEnable) {
|
if (!sPredictBackEnable) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final WindowManagerService wmService = mWindowManagerService;
|
final WindowManagerService wmService = mWindowManagerService;
|
||||||
mFocusObserver = observer;
|
|
||||||
|
|
||||||
int backType = BackNavigationInfo.TYPE_UNDEFINED;
|
int backType = BackNavigationInfo.TYPE_UNDEFINED;
|
||||||
|
|
||||||
@@ -202,9 +205,7 @@ class BackNavigationController {
|
|||||||
backType = BackNavigationInfo.TYPE_CALLBACK;
|
backType = BackNavigationInfo.TYPE_CALLBACK;
|
||||||
}
|
}
|
||||||
infoBuilder.setOnBackInvokedCallback(callbackInfo.getCallback());
|
infoBuilder.setOnBackInvokedCallback(callbackInfo.getCallback());
|
||||||
if (mFocusObserver != null) {
|
mNavigationMonitor.startMonitor(window, navigationObserver);
|
||||||
window.registerFocusObserver(mFocusObserver);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation currentTask=%s, "
|
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation currentTask=%s, "
|
||||||
@@ -228,10 +229,8 @@ class BackNavigationController {
|
|||||||
|| currentActivity.isActivityTypeHome()
|
|| currentActivity.isActivityTypeHome()
|
||||||
|| currentActivity.mHasSceneTransition) {
|
|| currentActivity.mHasSceneTransition) {
|
||||||
infoBuilder.setType(BackNavigationInfo.TYPE_CALLBACK);
|
infoBuilder.setType(BackNavigationInfo.TYPE_CALLBACK);
|
||||||
final WindowState finalFocusedWindow = window;
|
|
||||||
infoBuilder.setOnBackNavigationDone(new RemoteCallback(result ->
|
infoBuilder.setOnBackNavigationDone(new RemoteCallback(result ->
|
||||||
onBackNavigationDone(result, finalFocusedWindow,
|
onBackNavigationDone(result, BackNavigationInfo.TYPE_CALLBACK)));
|
||||||
BackNavigationInfo.TYPE_CALLBACK)));
|
|
||||||
mLastBackType = BackNavigationInfo.TYPE_CALLBACK;
|
mLastBackType = BackNavigationInfo.TYPE_CALLBACK;
|
||||||
return infoBuilder.build();
|
return infoBuilder.build();
|
||||||
}
|
}
|
||||||
@@ -334,16 +333,19 @@ class BackNavigationController {
|
|||||||
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
|
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
|
||||||
if (finalRemovedWindowContainer != null) {
|
if (finalRemovedWindowContainer != null) {
|
||||||
final int finalBackType = backType;
|
final int finalBackType = backType;
|
||||||
final WindowState finalFocusedWindow = window;
|
|
||||||
RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
|
RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
|
||||||
result, finalFocusedWindow, finalBackType));
|
result, finalBackType));
|
||||||
infoBuilder.setOnBackNavigationDone(onBackNavigationDone);
|
infoBuilder.setOnBackNavigationDone(onBackNavigationDone);
|
||||||
}
|
}
|
||||||
mLastBackType = backType;
|
mLastBackType = backType;
|
||||||
return infoBuilder.build();
|
return infoBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isWaitBackTransition() {
|
boolean isMonitoringTransition() {
|
||||||
|
return isWaitBackTransition() || mNavigationMonitor.isMonitoring();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWaitBackTransition() {
|
||||||
return mAnimationHandler.mComposed && mAnimationHandler.mWaitTransition;
|
return mAnimationHandler.mComposed && mAnimationHandler.mWaitTransition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,11 +365,23 @@ class BackNavigationController {
|
|||||||
*/
|
*/
|
||||||
boolean removeIfContainsBackAnimationTargets(ArraySet<ActivityRecord> openApps,
|
boolean removeIfContainsBackAnimationTargets(ArraySet<ActivityRecord> openApps,
|
||||||
ArraySet<ActivityRecord> closeApps) {
|
ArraySet<ActivityRecord> closeApps) {
|
||||||
if (!isWaitBackTransition()) {
|
if (!isMonitoringTransition()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mTmpCloseApps.addAll(closeApps);
|
mTmpCloseApps.addAll(closeApps);
|
||||||
boolean result = false;
|
final boolean matchAnimationTargets = removeIfWaitForBackTransition(openApps, closeApps);
|
||||||
|
if (!matchAnimationTargets) {
|
||||||
|
mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps);
|
||||||
|
}
|
||||||
|
mTmpCloseApps.clear();
|
||||||
|
return matchAnimationTargets;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean removeIfWaitForBackTransition(ArraySet<ActivityRecord> openApps,
|
||||||
|
ArraySet<ActivityRecord> closeApps) {
|
||||||
|
if (!isWaitBackTransition()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Note: TmpOpenApps is empty. Unlike shell transition, the open apps will be removed from
|
// Note: TmpOpenApps is empty. Unlike shell transition, the open apps will be removed from
|
||||||
// mOpeningApps if there is no visibility change.
|
// mOpeningApps if there is no visibility change.
|
||||||
if (mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps)) {
|
if (mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps)) {
|
||||||
@@ -386,10 +400,76 @@ class BackNavigationController {
|
|||||||
closeApps.removeAt(i);
|
closeApps.removeAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = true;
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NavigationMonitor {
|
||||||
|
// The window which triggering the back navigation.
|
||||||
|
private WindowState mNavigatingWindow;
|
||||||
|
private RemoteCallback mObserver;
|
||||||
|
|
||||||
|
void startMonitor(@NonNull WindowState window, @NonNull RemoteCallback observer) {
|
||||||
|
mNavigatingWindow = window;
|
||||||
|
mObserver = observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopMonitor() {
|
||||||
|
mNavigatingWindow = null;
|
||||||
|
mObserver = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isMonitoring() {
|
||||||
|
return mNavigatingWindow != null && mObserver != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify focus window changed during back navigation. This will cancel the gesture for
|
||||||
|
* scenarios like: a system window popup, or when an activity add a new window.
|
||||||
|
*
|
||||||
|
* This method should only be used to check window-level change, otherwise it may cause
|
||||||
|
* misjudgment in multi-window mode. For example: in split-screen, when user is
|
||||||
|
* navigating on the top task, bottom task can start a new task, which will gain focus for
|
||||||
|
* a short time, but we should not cancel the navigation.
|
||||||
|
*/
|
||||||
|
private void onFocusWindowChanged(WindowState newFocus) {
|
||||||
|
if (!isMonitoring() || !atSameDisplay(newFocus)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Keep navigating if either new focus == navigating window or null.
|
||||||
|
if (newFocus != null && newFocus != mNavigatingWindow
|
||||||
|
&& (newFocus.mActivityRecord == null
|
||||||
|
|| (newFocus.mActivityRecord == mNavigatingWindow.mActivityRecord))) {
|
||||||
|
EventLogTags.writeWmBackNaviCanceled("focusWindowChanged");
|
||||||
|
mObserver.sendResult(null /* result */);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify an unexpected transition has happened during back navigation.
|
||||||
|
*/
|
||||||
|
private void onTransitionReadyWhileNavigate(ArrayList<WindowContainer> opening,
|
||||||
|
ArrayList<WindowContainer> closing) {
|
||||||
|
if (!isMonitoring()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ArrayList<WindowContainer> all = new ArrayList<>(opening);
|
||||||
|
all.addAll(closing);
|
||||||
|
for (WindowContainer app : all) {
|
||||||
|
if (app.hasChild(mNavigatingWindow)) {
|
||||||
|
EventLogTags.writeWmBackNaviCanceled("transitionHappens");
|
||||||
|
mObserver.sendResult(null /* result */);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean atSameDisplay(WindowState newFocus) {
|
||||||
|
final int navigatingDisplayId = mNavigatingWindow.getDisplayId();
|
||||||
|
return newFocus == null || newFocus.getDisplayId() == navigatingDisplayId;
|
||||||
}
|
}
|
||||||
mTmpCloseApps.clear();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For shell transition
|
// For shell transition
|
||||||
@@ -403,8 +483,7 @@ class BackNavigationController {
|
|||||||
* animations, and shouldn't join next transition.
|
* animations, and shouldn't join next transition.
|
||||||
*/
|
*/
|
||||||
boolean containsBackAnimationTargets(Transition transition) {
|
boolean containsBackAnimationTargets(Transition transition) {
|
||||||
if (!mAnimationHandler.mComposed
|
if (!isMonitoringTransition()) {
|
||||||
|| (transition.mType != TRANSIT_CLOSE && transition.mType != TRANSIT_TO_BACK)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final ArraySet<WindowContainer> targets = transition.mParticipants;
|
final ArraySet<WindowContainer> targets = transition.mParticipants;
|
||||||
@@ -420,19 +499,19 @@ class BackNavigationController {
|
|||||||
mTmpCloseApps.add(wc);
|
mTmpCloseApps.add(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final boolean result = mAnimationHandler.containsBackAnimationTargets(
|
final boolean matchAnimationTargets = isWaitBackTransition()
|
||||||
mTmpOpenApps, mTmpCloseApps);
|
&& (transition.mType == TRANSIT_CLOSE || transition.mType == TRANSIT_TO_BACK)
|
||||||
if (result) {
|
&& mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps);
|
||||||
mAnimationHandler.mOpenTransitionTargetMatch =
|
if (!matchAnimationTargets) {
|
||||||
mAnimationHandler.containTarget(mTmpOpenApps, true);
|
mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps);
|
||||||
}
|
}
|
||||||
mTmpOpenApps.clear();
|
mTmpOpenApps.clear();
|
||||||
mTmpCloseApps.clear();
|
mTmpCloseApps.clear();
|
||||||
return result;
|
return matchAnimationTargets;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMonitorTransitionTarget(WindowContainer wc) {
|
boolean isMonitorTransitionTarget(WindowContainer wc) {
|
||||||
if (!mAnimationHandler.mComposed || !mAnimationHandler.mWaitTransition) {
|
if (!isWaitBackTransition()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */);
|
return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */);
|
||||||
@@ -951,16 +1030,13 @@ class BackNavigationController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBackNavigationDone(Bundle result, WindowState focusedWindow, int backType) {
|
private void onBackNavigationDone(Bundle result, int backType) {
|
||||||
boolean triggerBack = result != null && result.getBoolean(
|
boolean triggerBack = result != null && result.getBoolean(
|
||||||
BackNavigationInfo.KEY_TRIGGER_BACK);
|
BackNavigationInfo.KEY_TRIGGER_BACK);
|
||||||
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
|
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
|
||||||
+ "triggerBack=%b", backType, triggerBack);
|
+ "triggerBack=%b", backType, triggerBack);
|
||||||
|
|
||||||
if (mFocusObserver != null) {
|
mNavigationMonitor.stopMonitor();
|
||||||
focusedWindow.unregisterFocusObserver(mFocusObserver);
|
|
||||||
mFocusObserver = null;
|
|
||||||
}
|
|
||||||
mBackAnimationInProgress = false;
|
mBackAnimationInProgress = false;
|
||||||
mShowWallpaper = false;
|
mShowWallpaper = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3809,6 +3809,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
|
getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
|
||||||
|
mAtmService.mBackNavigationController.onFocusChanged(newFocus);
|
||||||
|
|
||||||
if (imWindowChanged && oldFocus != mInputMethodWindow) {
|
if (imWindowChanged && oldFocus != mInputMethodWindow) {
|
||||||
// Focus of the input method window changed. Perform layout if needed.
|
// Focus of the input method window changed. Perform layout if needed.
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ option java_package com.android.server.wm
|
|||||||
# bootanim finished:
|
# bootanim finished:
|
||||||
31007 wm_boot_animation_done (time|2|3)
|
31007 wm_boot_animation_done (time|2|3)
|
||||||
|
|
||||||
|
# Back navigation.
|
||||||
|
31100 wm_back_navi_canceled (Reason|3)
|
||||||
|
|
||||||
# IME surface parent is updated.
|
# IME surface parent is updated.
|
||||||
32003 imf_update_ime_parent (surface name|3)
|
32003 imf_update_ime_parent (surface name|3)
|
||||||
|
|||||||
@@ -17,8 +17,11 @@
|
|||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
|
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
|
||||||
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||||
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
|
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
|
||||||
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
|
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
|
||||||
|
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||||
import static android.window.BackNavigationInfo.typeToString;
|
import static android.window.BackNavigationInfo.typeToString;
|
||||||
|
|
||||||
@@ -42,8 +45,10 @@ import android.app.ActivityOptions;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteCallback;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.window.BackAnimationAdapter;
|
import android.window.BackAnimationAdapter;
|
||||||
import android.window.BackMotionEvent;
|
import android.window.BackMotionEvent;
|
||||||
@@ -320,6 +325,64 @@ public class BackNavigationControllerTests extends WindowTestsBase {
|
|||||||
assertThat(backNavigationInfo).isNull();
|
assertThat(backNavigationInfo).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransitionHappensCancelNavigation() {
|
||||||
|
// Create a floating task and a fullscreen task, then navigating on fullscreen task.
|
||||||
|
// The navigation should not been cancelled when transition happens on floating task, and
|
||||||
|
// only be cancelled when transition happens on the navigating task.
|
||||||
|
final Task floatingTask = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
|
||||||
|
ACTIVITY_TYPE_STANDARD);
|
||||||
|
final ActivityRecord baseFloatingActivity = createActivityRecord(floatingTask);
|
||||||
|
|
||||||
|
final Task fullscreenTask = createTopTaskWithActivity();
|
||||||
|
withSystemCallback(fullscreenTask);
|
||||||
|
final ActivityRecord baseFullscreenActivity = fullscreenTask.getTopMostActivity();
|
||||||
|
|
||||||
|
final CountDownLatch navigationObserver = new CountDownLatch(1);
|
||||||
|
startBackNavigation(navigationObserver);
|
||||||
|
|
||||||
|
final ArraySet<ActivityRecord> opening = new ArraySet<>();
|
||||||
|
final ArraySet<ActivityRecord> closing = new ArraySet<>();
|
||||||
|
final ActivityRecord secondFloatingActivity = createActivityRecord(floatingTask);
|
||||||
|
opening.add(secondFloatingActivity);
|
||||||
|
closing.add(baseFloatingActivity);
|
||||||
|
mBackNavigationController.removeIfContainsBackAnimationTargets(opening, closing);
|
||||||
|
assertEquals("Transition happen on an irrelevant task, callback should not been called",
|
||||||
|
1, navigationObserver.getCount());
|
||||||
|
|
||||||
|
// Create a new activity above navigation target, the transition should cancel navigation.
|
||||||
|
final ActivityRecord topFullscreenActivity = createActivityRecord(fullscreenTask);
|
||||||
|
opening.clear();
|
||||||
|
closing.clear();
|
||||||
|
opening.add(topFullscreenActivity);
|
||||||
|
closing.add(baseFullscreenActivity);
|
||||||
|
mBackNavigationController.removeIfContainsBackAnimationTargets(opening, closing);
|
||||||
|
assertEquals("Transition happen on navigation task, callback should have been called",
|
||||||
|
0, navigationObserver.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWindowFocusChangeCancelNavigation() {
|
||||||
|
Task task = createTopTaskWithActivity();
|
||||||
|
withSystemCallback(task);
|
||||||
|
WindowState focusWindow = task.getTopVisibleAppMainWindow();
|
||||||
|
final CountDownLatch navigationObserver = new CountDownLatch(1);
|
||||||
|
startBackNavigation(navigationObserver);
|
||||||
|
|
||||||
|
mBackNavigationController.onFocusChanged(null);
|
||||||
|
assertEquals("change focus to null, callback should not have been called",
|
||||||
|
1, navigationObserver.getCount());
|
||||||
|
mBackNavigationController.onFocusChanged(focusWindow);
|
||||||
|
assertEquals("change focus back, callback should not have been called",
|
||||||
|
1, navigationObserver.getCount());
|
||||||
|
|
||||||
|
WindowState newWindow = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlayWindow");
|
||||||
|
addToWindowMap(newWindow, true);
|
||||||
|
mBackNavigationController.onFocusChanged(newWindow);
|
||||||
|
assertEquals("Focus change, callback should have been called",
|
||||||
|
0, navigationObserver.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
private IOnBackInvokedCallback withSystemCallback(Task task) {
|
private IOnBackInvokedCallback withSystemCallback(Task task) {
|
||||||
IOnBackInvokedCallback callback = createOnBackInvokedCallback();
|
IOnBackInvokedCallback callback = createOnBackInvokedCallback();
|
||||||
task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo(
|
task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo(
|
||||||
@@ -336,7 +399,14 @@ public class BackNavigationControllerTests extends WindowTestsBase {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private BackNavigationInfo startBackNavigation() {
|
private BackNavigationInfo startBackNavigation() {
|
||||||
return mBackNavigationController.startBackNavigation(null, mBackAnimationAdapter);
|
return mBackNavigationController.startBackNavigation(
|
||||||
|
createNavigationObserver(null), mBackAnimationAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private BackNavigationInfo startBackNavigation(CountDownLatch navigationObserverLatch) {
|
||||||
|
return mBackNavigationController.startBackNavigation(
|
||||||
|
createNavigationObserver(navigationObserverLatch), mBackAnimationAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -371,6 +441,14 @@ public class BackNavigationControllerTests extends WindowTestsBase {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RemoteCallback createNavigationObserver(CountDownLatch latch) {
|
||||||
|
return new RemoteCallback(result -> {
|
||||||
|
if (latch != null) {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private Task initHomeActivity() {
|
private Task initHomeActivity() {
|
||||||
final Task task = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask();
|
final Task task = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask();
|
||||||
task.forAllLeafTasks((t) -> {
|
task.forAllLeafTasks((t) -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user