9/ Update transitions/starting window for shell thread

Bug: 161979899
Test: atest WMShellUnitTests
Test: atest SystemUITests
Change-Id: I0afbacd0db32ef02f1e178f7a53b16df5b64449b
This commit is contained in:
Winson Chung
2021-01-20 23:28:56 -08:00
parent f3e2661602
commit 6c75e58fc6
10 changed files with 157 additions and 87 deletions

View File

@@ -377,12 +377,10 @@ public class StartingSurfaceDrawer {
final int taskId = startingWindowInfo.taskInfo.taskId;
final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
mMainExecutor.execute(() -> {
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
final StartingWindowRecord tView =
new StartingWindowRecord(null/* decorView */, surface);
mStartingWindowRecords.put(taskId, tView);
});
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
final StartingWindowRecord tView =
new StartingWindowRecord(null/* decorView */, surface);
mStartingWindowRecords.put(taskId, tView);
}
/**
@@ -392,42 +390,40 @@ public class StartingSurfaceDrawer {
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
}
mMainExecutor.execute(() -> removeWindowSynced(taskId));
removeWindowSynced(taskId);
}
protected void postAddWindow(int taskId, IBinder appToken,
View view, WindowManager wm, WindowManager.LayoutParams params) {
mMainExecutor.execute(() -> {
boolean shouldSaveView = true;
try {
wm.addView(view, params);
} catch (WindowManager.BadTokenException e) {
// ignore
Slog.w(TAG, appToken + " already running, starting window not displayed. "
+ e.getMessage());
View view, WindowManager wm, WindowManager.LayoutParams params) {
boolean shouldSaveView = true;
try {
wm.addView(view, params);
} catch (WindowManager.BadTokenException e) {
// ignore
Slog.w(TAG, appToken + " already running, starting window not displayed. "
+ e.getMessage());
shouldSaveView = false;
} catch (RuntimeException e) {
// don't crash if something else bad happens, for example a
// failure loading resources because we are loading from an app
// on external storage that has been unmounted.
Slog.w(TAG, appToken + " failed creating starting window", e);
shouldSaveView = false;
} finally {
if (view != null && view.getParent() == null) {
Slog.w(TAG, "view not successfully added to wm, removing view");
wm.removeViewImmediate(view);
shouldSaveView = false;
} catch (RuntimeException e) {
// don't crash if something else bad happens, for example a
// failure loading resources because we are loading from an app
// on external storage that has been unmounted.
Slog.w(TAG, appToken + " failed creating starting window", e);
shouldSaveView = false;
} finally {
if (view != null && view.getParent() == null) {
Slog.w(TAG, "view not successfully added to wm, removing view");
wm.removeViewImmediate(view);
shouldSaveView = false;
}
}
}
if (shouldSaveView) {
removeWindowSynced(taskId);
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
final StartingWindowRecord tView =
new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
mStartingWindowRecords.put(taskId, tView);
}
});
if (shouldSaveView) {
removeWindowSynced(taskId);
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
final StartingWindowRecord tView =
new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
mStartingWindowRecords.put(taskId, tView);
}
}
protected void removeWindowSynced(int taskId) {
@@ -445,7 +441,7 @@ public class StartingSurfaceDrawer {
if (DEBUG_TASK_SNAPSHOT) {
Slog.v(TAG, "Removing task snapshot window for " + taskId);
}
record.mTaskSnapshotWindow.remove(mMainExecutor);
record.mTaskSnapshotWindow.remove();
}
mStartingWindowRecords.remove(taskId);
}

View File

@@ -82,6 +82,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DecorView;
import com.android.internal.view.BaseIWindow;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
/**
* This class represents a starting window that shows a snapshot.
@@ -121,6 +122,7 @@ public class TaskSnapshotWindow {
private final Window mWindow;
private final Surface mSurface;
private final Runnable mClearWindowHandler;
private final ShellExecutor mMainExecutor;
private SurfaceControl mSurfaceControl;
private SurfaceControl mChildSurfaceControl;
private final IWindowSession mSession;
@@ -213,7 +215,7 @@ public class TaskSnapshotWindow {
final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
topWindowInsetsState, clearWindowHandler);
topWindowInsetsState, clearWindowHandler, mainExecutor);
final Window window = snapshotSurface.mWindow;
final InsetsState mTmpInsetsState = new InsetsState();
@@ -229,7 +231,7 @@ public class TaskSnapshotWindow {
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
}
window.setOuter(snapshotSurface, mainExecutor);
window.setOuter(snapshotSurface);
try {
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
@@ -249,7 +251,8 @@ public class TaskSnapshotWindow {
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
int currentOrientation, int activityType, InsetsState topWindowInsetsState,
Runnable clearWindowHandler) {
Runnable clearWindowHandler, ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
mSurface = new Surface();
mSession = WindowManagerGlobal.getWindowSession();
mWindow = new Window();
@@ -286,28 +289,26 @@ public class TaskSnapshotWindow {
mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
}
void remove(ShellExecutor mainExecutor) {
void remove() {
final long now = SystemClock.uptimeMillis();
if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
// Show the latest content as soon as possible for unlocking to home.
&& mActivityType != ACTIVITY_TYPE_HOME) {
final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now;
mainExecutor.executeDelayed(() -> remove(mainExecutor), delayTime);
mMainExecutor.executeDelayed(() -> remove(), delayTime);
if (DEBUG) {
Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
}
return;
}
mainExecutor.execute(() -> {
try {
if (DEBUG) {
Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
}
mSession.remove(mWindow);
} catch (RemoteException e) {
// nothing
try {
if (DEBUG) {
Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
}
});
mSession.remove(mWindow);
} catch (RemoteException e) {
// nothing
}
}
/**
@@ -497,13 +498,12 @@ public class TaskSnapshotWindow {
}
}
@ExternalThread
static class Window extends BaseIWindow {
private TaskSnapshotWindow mOuter;
private ShellExecutor mMainExecutor;
public void setOuter(TaskSnapshotWindow outer, ShellExecutor mainExecutor) {
public void setOuter(TaskSnapshotWindow outer) {
mOuter = outer;
mMainExecutor = mainExecutor;
}
@Override
@@ -511,22 +511,20 @@ public class TaskSnapshotWindow {
MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {
if (mOuter != null) {
if (mergedConfiguration != null
&& mOuter.mOrientationOnCreation
!= mergedConfiguration.getMergedConfiguration().orientation) {
// The orientation of the screen is changing. We better remove the snapshot ASAP
// as we are going to wait on the new window in any case to unfreeze the screen,
// and the starting window is not needed anymore.
mMainExecutor.execute(() -> {
mOuter.mMainExecutor.execute(() -> {
if (mergedConfiguration != null
&& mOuter.mOrientationOnCreation
!= mergedConfiguration.getMergedConfiguration().orientation) {
// The orientation of the screen is changing. We better remove the snapshot
// ASAP as we are going to wait on the new window in any case to unfreeze
// the screen, and the starting window is not needed anymore.
mOuter.clearWindowSynced();
});
} else if (reportDraw) {
mMainExecutor.execute(() -> {
} else if (reportDraw) {
if (mOuter.mHasDrawn) {
mOuter.reportDrawn();
}
});
}
}
});
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2021 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.wm.shell.transition;
import android.annotation.NonNull;
import android.window.IRemoteTransition;
import android.window.TransitionFilter;
import com.android.wm.shell.common.annotations.ExternalThread;
/**
* Interface to manage remote transitions.
*/
@ExternalThread
public interface RemoteTransitions {
/**
* Registers a remote transition.
*/
void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition);
/**
* Unregisters a remote transition.
*/
void unregisterRemote(@NonNull IRemoteTransition remoteTransition);
}

View File

@@ -67,6 +67,7 @@ public class Transitions {
private final ShellExecutor mAnimExecutor;
private final TransitionPlayerImpl mPlayerImpl;
private final RemoteTransitionHandler mRemoteTransitionHandler;
private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
@@ -78,6 +79,10 @@ public class Transitions {
/** Keeps track of currently tracked transitions and all the animations associated with each */
private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>();
public static RemoteTransitions asRemoteTransitions(Transitions transitions) {
return transitions.mImpl;
}
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
mOrganizer = organizer;
@@ -101,8 +106,20 @@ public class Transitions {
/** Create an empty/non-registering transitions object for system-ui tests. */
@VisibleForTesting
public static Transitions createEmptyForTesting() {
return new Transitions();
public static RemoteTransitions createEmptyForTesting() {
return new RemoteTransitions() {
@Override
public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
@androidx.annotation.NonNull IRemoteTransition remoteTransition) {
// Do nothing
}
@Override
public void unregisterRemote(
@androidx.annotation.NonNull IRemoteTransition remoteTransition) {
// Do nothing
}
};
}
/** Register this transition handler with Core */
@@ -134,16 +151,14 @@ public class Transitions {
}
/** Register a remote transition to be used when `filter` matches an incoming transition */
@ExternalThread
public void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> mRemoteTransitionHandler.addFiltered(filter, remoteTransition));
mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
}
/** Unregisters a remote transition and all associated filters */
@ExternalThread
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> mRemoteTransitionHandler.removeFiltered(remoteTransition));
mRemoteTransitionHandler.removeFiltered(remoteTransition);
}
/** @return true if the transition was triggered by opening something vs closing something */
@@ -361,4 +376,22 @@ public class Transitions {
mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));
}
}
@ExternalThread
private class RemoteTransitionImpl implements RemoteTransitions {
@Override
public void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
Transitions.this.registerRemote(filter, remoteTransition);
});
}
@Override
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
Transitions.this.unregisterRemote(remoteTransition);
});
}
}
}

View File

@@ -47,6 +47,7 @@ import android.window.TaskSnapshot;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
import org.junit.Test;
@@ -83,7 +84,7 @@ public class TaskSnapshotWindowTest {
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(),
null /* clearWindow */);
null /* clearWindow */, new TestShellExecutor());
}
private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,

View File

@@ -33,7 +33,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -86,7 +86,7 @@ public interface SysUIComponent {
Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
@BindsInstance
Builder setTransitions(Transitions t);
Builder setTransitions(RemoteTransitions t);
SysUIComponent build();
}

View File

@@ -27,7 +27,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -55,16 +55,12 @@ public interface WMComponent {
getShellInit().init();
}
// Gets the Shell init instance
@WMSingleton
ShellInit getShellInit();
// Gets the Shell dump instance
@WMSingleton
Optional<ShellCommandHandler> getShellCommandHandler();
// TODO(b/162923491): We currently pass the instances through to SysUI, but that may change
// depending on the threading mechanism we go with
@WMSingleton
Optional<OneHanded> getOneHanded();
@@ -89,7 +85,6 @@ public interface WMComponent {
@WMSingleton
Optional<TaskViewFactory> getTaskViewFactory();
/** Gets transitions */
@WMSingleton
Transitions getTransitions();
RemoteTransitions getTransitions();
}

View File

@@ -101,7 +101,7 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.RemoteTransitions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -149,7 +149,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final ScreenshotHelper mScreenshotHelper;
private final Optional<OneHanded> mOneHandedOptional;
private final CommandQueue mCommandQueue;
private final Transitions mShellTransitions;
private final RemoteTransitions mShellTransitions;
private Region mActiveNavBarRegion;
@@ -799,7 +799,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
Transitions shellTransitions) {
RemoteTransitions shellTransitions) {
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;

View File

@@ -75,6 +75,7 @@ import com.android.wm.shell.sizecompatui.SizeCompatUI;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -386,6 +387,12 @@ public abstract class WMShellBaseModule {
return new FullscreenTaskListener(syncQueue);
}
@WMSingleton
@Provides
static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
return Transitions.asRemoteTransitions(transitions);
}
@WMSingleton
@Provides
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,

View File

@@ -43,7 +43,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.RemoteTransitions;
import org.junit.Before;
import org.junit.Test;
@@ -78,7 +78,7 @@ public class OverviewProxyServiceTest extends SysuiTestCase {
@Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
@Mock private PackageManager mPackageManager;
@Mock private SysUiState mMockSysUiState;
@Mock private Transitions mMockTransitions;
@Mock private RemoteTransitions mMockTransitions;
@Before
public void setUp() throws RemoteException {