Merge "Attach navigation bar to app during quick switching (2/N)" into sc-dev

This commit is contained in:
Shawn Lin
2021-03-12 13:45:19 +00:00
committed by Android (Google) Code Review
14 changed files with 237 additions and 42 deletions

View File

@@ -142,7 +142,13 @@ interface IRecentsAnimationController {
*
* The system reparents the leash of navigation bar to the app when the recents animation starts
* and Launcher should call this method to let system restore the navigation bar to its
* original position when the quick switch gesture is finished.
* original position when the quick switch gesture is finished and will run the fade-in
* animation If {@param moveHomeToTop} is {@code true}. Otherwise, restore the navigtation bar
* without animation.
*
* @param moveHomeToTop if {@code true}, the home activity should be moved to the top.
* Otherwise, the home activity is hidden and the user is returned to the
* app.
*/
void detachNavigationBarFromApp();
void detachNavigationBarFromApp(boolean moveHomeToTop);
}

View File

@@ -257,4 +257,12 @@ oneway interface IStatusBar
* file descriptor passed in.
*/
void passThroughShellCommand(in String[] args, in ParcelFileDescriptor pfd);
/**
* Enables/disables the navigation bar luma sampling.
*
* @param displayId the id of the display to notify.
* @param enable {@code true} if enable, otherwise set to {@code false}.
*/
void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable);
}

View File

@@ -16,11 +16,11 @@
package com.android.systemui.shared.system;
import android.window.TaskSnapshot;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.window.TaskSnapshot;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -141,9 +141,9 @@ public class RecentsAnimationControllerCompat {
/**
* @see IRecentsAnimationController#detachNavigationBarFromApp
*/
public void detachNavigationBarFromApp() {
public void detachNavigationBarFromApp(boolean moveHomeToTop) {
try {
mAnimationController.detachNavigationBarFromApp();
mAnimationController.detachNavigationBarFromApp(moveHomeToTop);
} catch (RemoteException e) {
Log.e(TAG, "Failed to detach the navigation bar from app", e);
}

View File

@@ -212,6 +212,14 @@ public class NavigationBarController implements Callbacks,
createNavigationBar(display, null /* savedState */, null /* result */);
}
@Override
public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
final NavigationBarView navigationBarView = getNavigationBarView(displayId);
if (navigationBarView != null) {
navigationBarView.setNavigationBarLumaSamplingEnabled(enable);
}
}
/**
* Recreates the navigation bar for the given display.
*/

View File

@@ -1397,4 +1397,12 @@ public class NavigationBarView extends FrameLayout implements
private final Consumer<Rect> mPipListener = bounds -> post(() -> {
mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds);
});
void setNavigationBarLumaSamplingEnabled(boolean enable) {
if (enable) {
mRegionSamplingHelper.start(mSamplingBounds);
} else {
mRegionSamplingHelper.stop();
}
}
}

View File

@@ -141,6 +141,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 57 << MSG_SHIFT;
//TODO(b/169175022) Update name and when feature name is locked.
private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE = 58 << MSG_SHIFT;
private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -369,6 +370,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
* Handles a window manager shell logging command.
*/
default void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {}
/**
* @see IStatusBar#setNavigationBarLumaSamplingEnabled(int, boolean)
*/
default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
}
public CommandQueue(Context context) {
@@ -1018,6 +1024,14 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
}
@Override
public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
synchronized (mLock) {
mHandler.obtainMessage(MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED, displayId,
enable ? 1 : 0).sendToTarget();
}
}
@Override
public void passThroughShellCommand(String[] args, ParcelFileDescriptor pfd) {
final FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
@@ -1400,6 +1414,12 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
args.recycle();
break;
case MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).setNavigationBarLumaSamplingEnabled(msg.arg1,
msg.arg2 != 0);
}
break;
}
}
}

View File

@@ -476,4 +476,11 @@ public class CommandQueueTest extends SysuiTestCase {
waitForIdleSync();
verify(mCallbacks).requestWindowMagnificationConnection(true);
}
@Test
public void testSetEnableNavigationBarLumaSampling() {
mCommandQueue.setNavigationBarLumaSamplingEnabled(1, true);
waitForIdleSync();
verify(mCallbacks).setNavigationBarLumaSamplingEnabled(eq(1), eq(true));
}
}

View File

@@ -160,4 +160,10 @@ public interface StatusBarManagerInternal {
* Handles a logging command from the WM shell command.
*/
void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd);
/**
* @see com.android.internal.statusbar.IStatusBar#setNavigationBarLumaSamplingEnabled(int,
* boolean)
*/
void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable);
}

View File

@@ -588,6 +588,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
} catch (RemoteException ex) { }
}
}
@Override
public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
if (mBar != null) {
try {
mBar.setNavigationBarLumaSamplingEnabled(displayId, enable);
} catch (RemoteException ex) { }
}
}
};
private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {

View File

@@ -37,10 +37,15 @@ public class FixedRotationAnimationController extends FadeAnimationController {
super(displayContent);
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
mStatusBar = displayPolicy.getStatusBar();
// Do not animate movable navigation bar (e.g. non-gesture mode).
final RecentsAnimationController controller =
displayContent.mWmService.getRecentsAnimationController();
final boolean navBarControlledByRecents =
controller != null && controller.isNavigationBarAttachedToApp();
// Do not animate movable navigation bar (e.g. non-gesture mode) or when the navigation bar
// is currently controlled by recents animation.
mNavigationBar = !displayPolicy.navigationBarCanMove()
? displayPolicy.getNavigationBar()
: null;
&& !navBarControlledByRecents ? displayPolicy.getNavigationBar() : null;
}
/** Applies show animation on the previously hidden window tokens. */

View File

@@ -17,7 +17,9 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -104,7 +106,8 @@ public class RecentsAnimationController implements DeathRecipient {
public @interface ReorderMode {}
private final WindowManagerService mService;
private final StatusBarManagerInternal mStatusBar;
@VisibleForTesting
final StatusBarManagerInternal mStatusBar;
private IRecentsAnimationRunner mRunner;
private final RecentsAnimationCallbacks mCallbacks;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
@@ -149,6 +152,7 @@ public class RecentsAnimationController implements DeathRecipient {
@VisibleForTesting
boolean mShouldAttachNavBarToAppDuringTransition;
private boolean mNavigationBarAttachedToApp;
/**
* Animates the screenshot of task that used to be controlled by RecentsAnimation.
@@ -369,7 +373,17 @@ public class RecentsAnimationController implements DeathRecipient {
}
@Override
public void detachNavigationBarFromApp() {}
public void detachNavigationBarFromApp(boolean moveHomeToTop) {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mService.getWindowManagerLock()) {
restoreNavigationBarFromApp(moveHomeToTop);
mService.mWindowPlacerLocked.requestTraversal();
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
};
/**
@@ -440,9 +454,7 @@ public class RecentsAnimationController implements DeathRecipient {
return;
}
if (mShouldAttachNavBarToAppDuringTransition) {
attachNavBarToApp();
}
attachNavigationBarToApp();
// Adjust the wallpaper visibility for the showing target activity
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
@@ -577,32 +589,52 @@ public class RecentsAnimationController implements DeathRecipient {
}
}
@VisibleForTesting
WindowToken getNavigationBarWindowToken() {
WindowState navBar = mDisplayContent.getDisplayPolicy().getNavigationBar();
if (navBar != null) {
return navBar.mToken;
}
return null;
boolean isNavigationBarAttachedToApp() {
return mNavigationBarAttachedToApp;
}
private void attachNavBarToApp() {
@VisibleForTesting
WindowState getNavigationBarWindow() {
return mDisplayContent.getDisplayPolicy().getNavigationBar();
}
private void attachNavigationBarToApp() {
if (!mShouldAttachNavBarToAppDuringTransition
// Skip the case where the nav bar is controlled by fixed rotation.
|| mDisplayContent.getFixedRotationAnimationController() != null) {
return;
}
ActivityRecord topActivity = null;
boolean shouldTranslateNavBar = false;
final boolean isDisplayLandscape =
mDisplayContent.getConfiguration().orientation == ORIENTATION_LANDSCAPE;
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
final Task task = adapter.mTask;
if (!task.isHomeOrRecentsRootTask()) {
topActivity = task.getTopVisibleActivity();
break;
final boolean isSplitScreenSecondary =
task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
if (task.isHomeOrRecentsRootTask()
// TODO(b/178449492): Will need to update for the new split screen mode once
// it's ready.
// Skip if the task is the secondary split screen and in landscape.
|| (isSplitScreenSecondary && isDisplayLandscape)) {
continue;
}
}
final WindowToken navToken = getNavigationBarWindowToken();
if (topActivity == null || navToken == null) {
return;
shouldTranslateNavBar = isSplitScreenSecondary;
topActivity = task.getTopVisibleActivity();
break;
}
final SurfaceControl.Transaction t = navToken.getPendingTransaction();
final SurfaceControl navSurfaceControl = navToken.getSurfaceControl();
final WindowState navWindow = getNavigationBarWindow();
if (topActivity == null || navWindow == null || navWindow.mToken == null) {
return;
}
mNavigationBarAttachedToApp = true;
final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
if (shouldTranslateNavBar) {
navWindow.setSurfaceTranslationY(-topActivity.getBounds().top);
}
t.reparent(navSurfaceControl, topActivity.getSurfaceControl());
t.show(navSurfaceControl);
@@ -613,16 +645,32 @@ public class RecentsAnimationController implements DeathRecipient {
// Place the nav bar on top of anything else in the top activity.
t.setLayer(navSurfaceControl, Integer.MAX_VALUE);
}
if (mStatusBar != null) {
mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, false);
}
}
private void restoreNavBarFromApp(boolean animate) {
// Reparent the SurfaceControl of nav bar token back.
final WindowToken navToken = getNavigationBarWindowToken();
final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
if (navToken != null) {
final WindowContainer parent = navToken.getParent();
t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
private void restoreNavigationBarFromApp(boolean animate) {
if (!mNavigationBarAttachedToApp) {
return;
}
if (mStatusBar != null) {
mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, true);
}
final WindowState navWindow = getNavigationBarWindow();
if (navWindow == null) {
return;
}
navWindow.setSurfaceTranslationY(0);
if (navWindow.mToken == null) {
return;
}
final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
final WindowContainer parent = navWindow.mToken.getParent();
// Reparent the SurfaceControl of nav bar token back.
t.reparent(navWindow.mToken.getSurfaceControl(), parent.getSurfaceControl());
if (animate) {
// Run fade-in animation to show navigation bar back to bottom of the display.
@@ -852,9 +900,7 @@ public class RecentsAnimationController implements DeathRecipient {
removeWallpaperAnimation(wallpaperAdapter);
}
if (mShouldAttachNavBarToAppDuringTransition) {
restoreNavBarFromApp(reorderMode == REORDER_MOVE_TO_TOP);
}
restoreNavigationBarFromApp(reorderMode == REORDER_MOVE_TO_TOP);
// Clear any pending failsafe runnables
mService.mH.removeCallbacks(mFailsafeRunnable);

View File

@@ -778,6 +778,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
};
/**
* @see #setSurfaceTranslationY(int)
*/
private int mSurfaceTranslationY;
/**
* Returns the visibility of the given {@link InternalInsetsType type} requested by the client.
*
@@ -5368,6 +5373,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Expand for surface insets. See WindowState.expandForSurfaceInsets.
transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
outPoint.offset(-mTmpPoint.x, -mTmpPoint.y);
outPoint.y += mSurfaceTranslationY;
}
/**
@@ -5886,4 +5893,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return hadHandlers;
}
/**
* Adds an additional translation offset to be applied when positioning the surface. Used to
* correct offsets in specific reparenting situations, e.g. the navigation bar window attached
* on the lower split-screen app.
*/
void setSurfaceTranslationY(int translationY) {
mSurfaceTranslationY = translationY;
}
}

View File

@@ -16,6 +16,9 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -49,6 +52,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -511,6 +515,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
mDefaultDisplay.mDisplayId, false);
verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
final WindowContainer parent = navToken.getParent();
@@ -518,6 +524,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
mDefaultDisplay.mDisplayId, true);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
verify(navBarFadeAnimationController).fadeWindowToken(true);
}
@@ -532,6 +540,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
mDefaultDisplay.mDisplayId, false);
verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
final WindowContainer parent = navToken.getParent();
@@ -539,6 +549,51 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
mDefaultDisplay.mDisplayId, true);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
}
@Test
public void testNotAttachNavigationBar_controlledByFixedRotationAnimation() {
setupForShouldAttachNavBarDuringTransition();
FixedRotationAnimationController mockController =
mock(FixedRotationAnimationController.class);
doReturn(mockController).when(mDefaultDisplay).getFixedRotationAnimationController();
final ActivityRecord homeActivity = createHomeActivity();
initializeRecentsAnimationController(mController, homeActivity);
assertFalse(mController.isNavigationBarAttachedToApp());
}
@Test
public void testAttachNavBarInSplitScreenMode() {
setupForShouldAttachNavBarDuringTransition();
final ActivityRecord primary = createActivityRecordWithParentTask(mDefaultDisplay,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
final ActivityRecord secondary = createActivityRecordWithParentTask(mDefaultDisplay,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
final ActivityRecord homeActivity = createHomeActivity();
homeActivity.setVisibility(true);
initializeRecentsAnimationController(mController, homeActivity);
WindowState navWindow = mController.getNavigationBarWindow();
final WindowToken navToken = navWindow.mToken;
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
mDefaultDisplay.mDisplayId, false);
verify(navWindow).setSurfaceTranslationY(-secondary.getBounds().top);
verify(transaction).reparent(navToken.getSurfaceControl(), secondary.getSurfaceControl());
reset(navWindow);
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
final WindowContainer parent = navToken.getParent();
final NavBarFadeAnimationController navBarFadeAnimationController =
mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
mDefaultDisplay.mDisplayId, true);
verify(navWindow).setSurfaceTranslationY(0);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
}
@@ -600,9 +655,10 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
private void setupForShouldAttachNavBarDuringTransition() {
mController.mShouldAttachNavBarToAppDuringTransition = true;
final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
final WindowState navBar = spy(createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar"));
mDefaultDisplay.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
mWm.setRecentsAnimationController(mController);
doReturn(navBar).when(mController).getNavigationBarWindow();
final NavBarFadeAnimationController mockNavBarFadeAnimationController =
mock(NavBarFadeAnimationController.class);
final DisplayPolicy displayPolicy = spy(mDefaultDisplay.getDisplayPolicy());

View File

@@ -470,7 +470,7 @@ public class ZOrderingTests extends WindowTestsBase {
mWm, mockRunner, null, displayId);
spyOn(controller);
controller.mShouldAttachNavBarToAppDuringTransition = true;
doReturn(mNavBarWindow.mToken).when(controller).getNavigationBarWindowToken();
doReturn(mNavBarWindow).when(controller).getNavigationBarWindow();
mWm.setRecentsAnimationController(controller);
// set ime visible