Merge "Synchronize bubble activity rendering status and its visibility change." into qt-r1-dev
This commit is contained in:
@@ -120,6 +120,7 @@ public class ActivityView extends ViewGroup {
|
||||
|
||||
mActivityTaskManager = ActivityTaskManager.getService();
|
||||
mSurfaceView = new SurfaceView(context);
|
||||
mSurfaceView.setAlpha(0f);
|
||||
mSurfaceCallback = new SurfaceCallback();
|
||||
mSurfaceView.getHolder().addCallback(mSurfaceCallback);
|
||||
addView(mSurfaceView);
|
||||
@@ -346,6 +347,16 @@ public class ActivityView extends ViewGroup {
|
||||
mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(float alpha) {
|
||||
mSurfaceView.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAlpha() {
|
||||
return mSurfaceView.getAlpha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean gatherTransparentRegion(Region region) {
|
||||
// The tap exclude region may be affected by any view on top of it, so we detect the
|
||||
|
||||
@@ -169,4 +169,12 @@ oneway interface ITaskStackListener {
|
||||
* @param taskInfo info about the task which received the back press
|
||||
*/
|
||||
void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
|
||||
|
||||
/*
|
||||
* Called when contents are drawn for the first time on a display which can only contain one
|
||||
* task.
|
||||
*
|
||||
* @param displayId the id of the display on which contents are drawn.
|
||||
*/
|
||||
void onSingleTaskDisplayDrawn(int displayId);
|
||||
}
|
||||
|
||||
@@ -173,4 +173,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
|
||||
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)
|
||||
throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.content.res.Configuration;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.HardwareRenderer;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
@@ -201,6 +202,29 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
|
||||
|
||||
private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
|
||||
|
||||
/**
|
||||
* A callback which reflects an alpha value of this view onto the underlying surfaces.
|
||||
*
|
||||
* <p class="note"><strong>Note:</strong> This doesn't have to be defined as a member variable,
|
||||
* but can be defined as an inline lambda when calling ViewRootImpl#registerRtFrameCallback().
|
||||
* However when we do so, the callback is triggered only for a few times and stops working for
|
||||
* some reason. It's suspected that there is a problem around garbage collection, and until
|
||||
* the cause is fixed, we will keep this callback in a member variable.</p>
|
||||
*/
|
||||
private HardwareRenderer.FrameDrawingCallback mSetSurfaceAlphaCallback = frame -> {
|
||||
final ViewRootImpl viewRoot = getViewRootImpl();
|
||||
if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
|
||||
// In this case, the alpha value is reflected on the screen in #updateSurface() later.
|
||||
return;
|
||||
}
|
||||
|
||||
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
t.setAlpha(mSurfaceControl, getAlpha());
|
||||
t.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface, frame);
|
||||
t.setEarlyWakeup();
|
||||
t.apply();
|
||||
};
|
||||
|
||||
public SurfaceView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -288,6 +312,17 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
|
||||
updateSurface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(float alpha) {
|
||||
super.setAlpha(alpha);
|
||||
final ViewRootImpl viewRoot = getViewRootImpl();
|
||||
if (viewRoot == null) {
|
||||
return;
|
||||
}
|
||||
viewRoot.registerRtFrameCallback(mSetSurfaceAlphaCallback);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void performDrawFinished() {
|
||||
if (mPendingReportDraws > 0) {
|
||||
mDrawFinished = true;
|
||||
@@ -647,6 +682,13 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
|
||||
}
|
||||
updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl());
|
||||
|
||||
// Alpha value change is handled in setAlpha() directly using a local
|
||||
// transaction. However it can happen that setAlpha() is called while
|
||||
// local transactions cannot be applied, so the value is stored in a View
|
||||
// but not yet reflected on the Surface.
|
||||
mSurfaceControl.setAlpha(getAlpha());
|
||||
mBackgroundControl.setAlpha(getAlpha());
|
||||
|
||||
// While creating the surface, we will set it's initial
|
||||
// geometry. Outside of that though, we should generally
|
||||
// leave it to the RenderThread.
|
||||
|
||||
@@ -260,6 +260,13 @@ public interface WindowManager extends ViewManager {
|
||||
*/
|
||||
int TRANSIT_TASK_CHANGE_WINDOWING_MODE = 27;
|
||||
|
||||
/**
|
||||
* A display which can only contain one task is being shown because the first activity is
|
||||
* started or it's being turned on.
|
||||
* @hide
|
||||
*/
|
||||
int TRANSIT_SHOW_SINGLE_TASK_DISPLAY = 28;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -287,7 +294,8 @@ public interface WindowManager extends ViewManager {
|
||||
TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
|
||||
TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
|
||||
TRANSIT_CRASHING_ACTIVITY_CLOSE,
|
||||
TRANSIT_TASK_CHANGE_WINDOWING_MODE
|
||||
TRANSIT_TASK_CHANGE_WINDOWING_MODE,
|
||||
TRANSIT_SHOW_SINGLE_TASK_DISPLAY
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface TransitionType {}
|
||||
|
||||
@@ -64,6 +64,14 @@ public abstract class TaskStackChangeListener {
|
||||
onActivityLaunchOnSecondaryDisplayRerouted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when contents are drawn for the first time on a display which can only contain one
|
||||
* task.
|
||||
*
|
||||
* @param displayId the id of the display on which contents are drawn.
|
||||
*/
|
||||
public void onSingleTaskDisplayDrawn(int displayId) { }
|
||||
|
||||
public void onTaskProfileLocked(int taskId, int userId) { }
|
||||
public void onTaskCreated(int taskId, ComponentName componentName) { }
|
||||
public void onTaskRemoved(int taskId) { }
|
||||
|
||||
@@ -196,11 +196,18 @@ public class TaskStackChangeListeners extends TaskStackListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
|
||||
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken)
|
||||
throws RemoteException {
|
||||
mHandler.obtainMessage(H.ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId, 0 /* unused */,
|
||||
activityToken).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
|
||||
mHandler.obtainMessage(H.ON_SINGLE_TASK_DISPLAY_DRAWN, displayId,
|
||||
0 /* unused */).sendToTarget();
|
||||
}
|
||||
|
||||
private final class H extends Handler {
|
||||
private static final int ON_TASK_STACK_CHANGED = 1;
|
||||
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
|
||||
@@ -220,6 +227,7 @@ public class TaskStackChangeListeners extends TaskStackListener {
|
||||
private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 16;
|
||||
private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 17;
|
||||
private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18;
|
||||
private static final int ON_SINGLE_TASK_DISPLAY_DRAWN = 19;
|
||||
|
||||
|
||||
public H(Looper looper) {
|
||||
@@ -356,6 +364,12 @@ public class TaskStackChangeListeners extends TaskStackListener {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ON_SINGLE_TASK_DISPLAY_DRAWN: {
|
||||
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
|
||||
mTaskStackListeners.get(i).onSingleTaskDisplayDrawn(msg.arg1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package com.android.systemui.bubbles;
|
||||
|
||||
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
|
||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -129,6 +131,20 @@ class Bubble {
|
||||
mInflated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visibility of bubble in the expanded state.
|
||||
*
|
||||
* @param visibility {@code true} if the expanded bubble should be visible on the screen.
|
||||
*
|
||||
* Note that this contents visibility doesn't affect visibility at {@link android.view.View},
|
||||
* and setting {@code false} actually means rendering the expanded view in transparent.
|
||||
*/
|
||||
void setContentVisibility(boolean visibility) {
|
||||
if (expandedView != null) {
|
||||
expandedView.setContentVisibility(visibility);
|
||||
}
|
||||
}
|
||||
|
||||
void setDismissed() {
|
||||
entry.setBubbleDismissed(true);
|
||||
// TODO: move this somewhere where it can be guaranteed not to run until safe from flicker
|
||||
@@ -167,6 +183,13 @@ class Bubble {
|
||||
return mLastAccessed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the display id of the virtual display on which bubble contents is drawn.
|
||||
*/
|
||||
int getDisplayId() {
|
||||
return expandedView != null ? expandedView.getVirtualDisplayId() : INVALID_DISPLAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be invoked whenever a Bubble is accessed (selected while expanded).
|
||||
*/
|
||||
|
||||
@@ -603,17 +603,23 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
* status bar, otherwise returns {@link Display#INVALID_DISPLAY}.
|
||||
*/
|
||||
public int getExpandedDisplayId(Context context) {
|
||||
final Bubble bubble = getExpandedBubble(context);
|
||||
return bubble != null ? bubble.getDisplayId() : INVALID_DISPLAY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Bubble getExpandedBubble(Context context) {
|
||||
if (mStackView == null) {
|
||||
return INVALID_DISPLAY;
|
||||
return null;
|
||||
}
|
||||
boolean defaultDisplay = context.getDisplay() != null
|
||||
final boolean defaultDisplay = context.getDisplay() != null
|
||||
&& context.getDisplay().getDisplayId() == DEFAULT_DISPLAY;
|
||||
Bubble b = mStackView.getExpandedBubble();
|
||||
if (defaultDisplay && b != null && isStackExpanded()
|
||||
final Bubble expandedBubble = mStackView.getExpandedBubble();
|
||||
if (defaultDisplay && expandedBubble != null && isStackExpanded()
|
||||
&& !mStatusBarWindowController.getPanelExpanded()) {
|
||||
return b.expandedView.getVirtualDisplayId();
|
||||
return expandedBubble;
|
||||
}
|
||||
return INVALID_DISPLAY;
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -730,6 +736,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
mBubbleData.setExpanded(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSingleTaskDisplayDrawn(int displayId) {
|
||||
final Bubble expandedBubble = getExpandedBubble(mContext);
|
||||
if (expandedBubble != null && expandedBubble.getDisplayId() == displayId) {
|
||||
expandedBubble.setContentVisibility(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldAutoBubbleMessages(Context context) {
|
||||
|
||||
@@ -185,6 +185,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
|
||||
|
||||
mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
|
||||
true /* singleTaskInstance */);
|
||||
|
||||
setContentVisibility(false);
|
||||
addView(mActivityView);
|
||||
|
||||
// Expanded stack layout, top to bottom:
|
||||
@@ -238,6 +240,22 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visibility of contents in the expanded state.
|
||||
*
|
||||
* @param visibility {@code true} if the contents should be visible on the screen.
|
||||
*
|
||||
* Note that this contents visibility doesn't affect visibility at {@link android.view.View},
|
||||
* and setting {@code false} actually means rendering the contents in transparent.
|
||||
*/
|
||||
void setContentVisibility(boolean visibility) {
|
||||
final float alpha = visibility ? 1f : 0f;
|
||||
mPointerView.setAlpha(alpha);
|
||||
if (mActivityView != null) {
|
||||
mActivityView.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
|
||||
* This should be done post-move and post-animation.
|
||||
@@ -310,6 +328,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
|
||||
parent.removeView(mNotifRow);
|
||||
}
|
||||
addView(mNotifRow, 1 /* index */);
|
||||
mPointerView.setAlpha(1f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,12 +355,12 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
|
||||
removeView(mNotifRow);
|
||||
mNotifRow = null;
|
||||
}
|
||||
setContentVisibility(false);
|
||||
mActivityView.setVisibility(VISIBLE);
|
||||
} else {
|
||||
// Hide activity view if we had it previously
|
||||
mActivityView.setVisibility(GONE);
|
||||
mNotifRow = mEntry.getRow();
|
||||
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
@@ -440,6 +459,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
|
||||
mActivityView.onLocationChanged();
|
||||
} else if (mNotifRow != null) {
|
||||
applyRowState(mNotifRow);
|
||||
mPointerView.setAlpha(1f);
|
||||
}
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
@@ -740,12 +740,16 @@ public class BubbleStackView extends FrameLayout {
|
||||
}
|
||||
final Bubble previouslySelected = mExpandedBubble;
|
||||
mExpandedBubble = bubbleToSelect;
|
||||
|
||||
if (mIsExpanded) {
|
||||
// Make the container of the expanded view transparent before removing the expanded view
|
||||
// from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
|
||||
// expanded view becomes visible on the screen. See b/126856255
|
||||
mExpandedViewContainer.setAlpha(0.0f);
|
||||
mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
|
||||
if (previouslySelected != null) {
|
||||
previouslySelected.setContentVisibility(false);
|
||||
}
|
||||
updateExpandedBubble();
|
||||
updatePointerPosition();
|
||||
requestUpdate();
|
||||
@@ -774,6 +778,14 @@ public class BubbleStackView extends FrameLayout {
|
||||
}
|
||||
if (wasExpanded) {
|
||||
// Collapse the stack
|
||||
mExpandedViewContainer.setAlpha(0.0f);
|
||||
// TODO: In order to prevent flicker, code below should be executed after the alpha
|
||||
// value set on the mExpandedViewContainer is reflected on the screen. However, we
|
||||
// cannot just postpone the execution like #setSelectedBubble(), since some of member
|
||||
// variables referred by the code are overridden before the execution.
|
||||
if (mExpandedBubble != null) {
|
||||
mExpandedBubble.setContentVisibility(false);
|
||||
}
|
||||
animateExpansion(false /* expand */);
|
||||
logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
|
||||
} else {
|
||||
@@ -931,14 +943,10 @@ public class BubbleStackView extends FrameLayout {
|
||||
if (shouldExpand) {
|
||||
mExpandedViewContainer.setTranslationX(xStart);
|
||||
mExpandedViewContainer.setTranslationY(yStart);
|
||||
mExpandedViewContainer.setAlpha(0f);
|
||||
}
|
||||
|
||||
mExpandedViewXAnim.animateToFinalPosition(shouldExpand ? 0f : xStart);
|
||||
mExpandedViewYAnim.animateToFinalPosition(shouldExpand ? yDest : yStart);
|
||||
mExpandedViewContainer.animate()
|
||||
.setDuration(100)
|
||||
.alpha(shouldExpand ? 1f : 0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
|
||||
@@ -3194,6 +3195,8 @@ class ActivityStack extends ConfigurationContainer {
|
||||
if (newTask) {
|
||||
if (r.mLaunchTaskBehind) {
|
||||
transit = TRANSIT_TASK_OPEN_BEHIND;
|
||||
} else if (getDisplay().isSingleTaskInstance()) {
|
||||
transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
|
||||
} else {
|
||||
// If a new task is being launched, then mark the existing top activity as
|
||||
// supporting picture-in-picture while pausing only if the starting activity
|
||||
|
||||
@@ -34,7 +34,6 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.service.voice.IVoiceInteractionSession;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
@@ -188,6 +187,13 @@ public abstract class ActivityTaskManagerInternal {
|
||||
*/
|
||||
public abstract void notifyDockedStackMinimizedChanged(boolean minimized);
|
||||
|
||||
/**
|
||||
* Notify listeners that contents are drawn for the first time on a single task display.
|
||||
*
|
||||
* @param displayId An ID of the display on which contents are drawn.
|
||||
*/
|
||||
public abstract void notifySingleTaskDisplayDrawn(int displayId);
|
||||
|
||||
/**
|
||||
* Start activity {@code intents} as if {@code packageName} on user {@code userId} did it.
|
||||
*
|
||||
|
||||
@@ -6087,13 +6087,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp) {
|
||||
public void notifyAppTransitionStarting(SparseIntArray reasons,
|
||||
long timestamp) {
|
||||
synchronized (mGlobalLock) {
|
||||
mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
|
||||
reasons, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySingleTaskDisplayDrawn(int displayId) {
|
||||
mTaskChangeNotificationController.notifySingleTaskDisplayDrawn(displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyAppTransitionFinished() {
|
||||
synchronized (mGlobalLock) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPE
|
||||
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
|
||||
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
|
||||
@@ -2052,6 +2053,9 @@ public class AppTransition implements Dump {
|
||||
case TRANSIT_CRASHING_ACTIVITY_CLOSE: {
|
||||
return "TRANSIT_CRASHING_ACTIVITY_CLOSE";
|
||||
}
|
||||
case TRANSIT_SHOW_SINGLE_TASK_DISPLAY: {
|
||||
return "TRANSIT_SHOW_SINGLE_TASK_DISPLAY";
|
||||
}
|
||||
default: {
|
||||
return "<UNKNOWN: " + transition + ">";
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_W
|
||||
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
|
||||
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
|
||||
@@ -211,6 +212,12 @@ public class AppTransitionController {
|
||||
mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
|
||||
SystemClock.uptimeMillis());
|
||||
|
||||
if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
|
||||
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
|
||||
mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
|
||||
});
|
||||
}
|
||||
|
||||
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
|
||||
|
||||
mDisplayContent.pendingLayoutChanges |=
|
||||
|
||||
@@ -35,6 +35,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
|
||||
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
|
||||
|
||||
import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
|
||||
import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS;
|
||||
@@ -1217,6 +1218,15 @@ class RootActivityContainer extends ConfigurationContainer
|
||||
if (displayShouldSleep) {
|
||||
stack.goToSleepIfPossible(false /* shuttingDown */);
|
||||
} else {
|
||||
// When the display which can only contain one task turns on, start a special
|
||||
// transition. {@link AppTransitionController#handleAppTransitionReady} later
|
||||
// picks up the transition, and schedules
|
||||
// {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is
|
||||
// triggered after contents are drawn on the display.
|
||||
if (display.isSingleTaskInstance()) {
|
||||
display.mDisplayContent.prepareAppTransition(
|
||||
TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
|
||||
}
|
||||
stack.awakeFromSleepingLocked();
|
||||
if (stack.isFocusedStackOnDisplay()
|
||||
&& !mStackSupervisor.getKeyguardController()
|
||||
|
||||
@@ -54,6 +54,7 @@ class TaskChangeNotificationController {
|
||||
private static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED_MSG = 19;
|
||||
private static final int NOTIFY_SIZE_COMPAT_MODE_ACTIVITY_CHANGED_MSG = 20;
|
||||
private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21;
|
||||
private static final int NOTIFY_SINGLE_TASK_DISPLAY_DRAWN = 22;
|
||||
|
||||
// Delay in notifying task stack change listeners (in millis)
|
||||
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
|
||||
@@ -154,6 +155,10 @@ class TaskChangeNotificationController {
|
||||
l.onSizeCompatModeActivityChanged(m.arg1, (IBinder) m.obj);
|
||||
};
|
||||
|
||||
private final TaskStackConsumer mNotifySingleTaskDisplayDrawn = (l, m) -> {
|
||||
l.onSingleTaskDisplayDrawn(m.arg1);
|
||||
};
|
||||
|
||||
@FunctionalInterface
|
||||
public interface TaskStackConsumer {
|
||||
void accept(ITaskStackListener t, Message m) throws RemoteException;
|
||||
@@ -233,6 +238,9 @@ class TaskChangeNotificationController {
|
||||
case NOTIFY_BACK_PRESSED_ON_TASK_ROOT:
|
||||
forAllRemoteListeners(mNotifyBackPressedOnTaskRoot, msg);
|
||||
break;
|
||||
case NOTIFY_SINGLE_TASK_DISPLAY_DRAWN:
|
||||
forAllRemoteListeners(mNotifySingleTaskDisplayDrawn, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,4 +485,14 @@ class TaskChangeNotificationController {
|
||||
forAllLocalListeners(mNotifyBackPressedOnTaskRoot, msg);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify listeners that contents are drawn for the first time on a single task display.
|
||||
*/
|
||||
void notifySingleTaskDisplayDrawn(int displayId) {
|
||||
final Message msg = mHandler.obtainMessage(NOTIFY_SINGLE_TASK_DISPLAY_DRAWN,
|
||||
displayId, 0 /* unused */);
|
||||
forAllLocalListeners(mNotifySingleTaskDisplayDrawn, msg);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" />
|
||||
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" />
|
||||
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" />
|
||||
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityViewTestActivity" />
|
||||
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityInActivityView"
|
||||
android:resizeableActivity="true" />
|
||||
<activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
|
||||
android:showWhenLocked="true" />
|
||||
</application>
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -26,18 +28,22 @@ import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.ActivityView;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.ITaskStackListener;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.Instrumentation.ActivityMonitor;
|
||||
import android.app.TaskStackListener;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.test.filters.FlakyTest;
|
||||
import androidx.test.filters.MediumTest;
|
||||
@@ -231,6 +237,40 @@ public class TaskStackChangedListenerTest {
|
||||
assertTrue(activity.mOnDetachedFromWindowCalled);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskOnSingleTaskDisplayDrawn() throws Exception {
|
||||
final Instrumentation instrumentation = getInstrumentation();
|
||||
|
||||
final CountDownLatch activityViewReadyLatch = new CountDownLatch(1);
|
||||
final CountDownLatch singleTaskDisplayDrawnLatch = new CountDownLatch(1);
|
||||
registerTaskStackChangedListener(new TaskStackListener() {
|
||||
@Override
|
||||
public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
|
||||
singleTaskDisplayDrawnLatch.countDown();
|
||||
}
|
||||
});
|
||||
final ActivityViewTestActivity activity =
|
||||
(ActivityViewTestActivity) startTestActivity(ActivityViewTestActivity.class);
|
||||
final ActivityView activityView = activity.getActivityView();
|
||||
activityView.setCallback(new ActivityView.StateCallback() {
|
||||
@Override
|
||||
public void onActivityViewReady(ActivityView view) {
|
||||
activityViewReadyLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityViewDestroyed(ActivityView view) {
|
||||
}
|
||||
});
|
||||
waitForCallback(activityViewReadyLatch);
|
||||
|
||||
final Context context = instrumentation.getContext();
|
||||
Intent intent = new Intent(context, ActivityInActivityView.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
activityView.startActivity(intent);
|
||||
waitForCallback(singleTaskDisplayDrawnLatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the provided activity and returns the started instance.
|
||||
*/
|
||||
@@ -369,4 +409,29 @@ public class TaskStackChangedListenerTest {
|
||||
mOnDetachedFromWindowCountDownLatch = countDownLatch;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ActivityViewTestActivity extends TestActivity {
|
||||
private ActivityView mActivityView;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mActivityView = new ActivityView(this, null /* attrs */, 0 /* defStyle */,
|
||||
true /* singleTaskInstance */);
|
||||
setContentView(mActivityView);
|
||||
|
||||
ViewGroup.LayoutParams layoutParams = mActivityView.getLayoutParams();
|
||||
layoutParams.width = MATCH_PARENT;
|
||||
layoutParams.height = MATCH_PARENT;
|
||||
mActivityView.requestLayout();
|
||||
}
|
||||
|
||||
ActivityView getActivityView() {
|
||||
return mActivityView;
|
||||
}
|
||||
}
|
||||
|
||||
// Activity that has {@link android.R.attr#resizeableActivity} attribute set to {@code true}
|
||||
public static class ActivityInActivityView extends TestActivity {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user