Splitscreen for minimized state that works with resizable launchers

If a launcher is resizable, going to minimized mode (dock task and then
press home) would show a cropped height of the task at the top in a
minimized state and the fullscreen stack would show the home launcher
which takes the rest of the remaining height. If the launcher is not
resizable, it will default the original behavior.

To enable this in a launcher, add android:resizeableActivity="true" in
the AndroidManifest.xml in the <application/> tag.

Test: manual - rotating while minimized, minimizing using dragging task
or holding overview nav button, installing resizable launcher with a
non-resizable launcher
Fixes: 32504542
Change-Id: Idf4015b40f9bec81b70f146f0f2d7df8ccfb4cf0
This commit is contained in:
Matthew Ng
2016-12-20 15:36:29 -08:00
parent 04b926a68b
commit e15352e516
16 changed files with 343 additions and 185 deletions

View File

@@ -40,8 +40,11 @@ oneway interface IDockedStackListener {
*
* @param minimized Whether the docked stack is currently minimized.
* @param animDuration The duration of the animation for changing the minimized state.
* @param isHomeStackResizable If the home stack is resizable, a portion of the docked stack
* will be shown with the divider
*/
void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
boolean isHomeStackResizable);
/**
* Called when window manager decides to adjust the divider for IME. Like the minimized state,

View File

@@ -53,6 +53,11 @@ public class DividerSnapAlgorithm {
*/
private static final int SNAP_ONLY_1_1 = 2;
/**
* 1 snap target: minimized height, (1 - minimized height)
*/
private static final int SNAP_MODE_MINIMIZED = 3;
private final float mMinFlingVelocityPxPerSecond;
private final float mMinDismissVelocityPxPerSecond;
private final int mDisplayWidth;
@@ -62,6 +67,7 @@ public class DividerSnapAlgorithm {
private final Rect mInsets = new Rect();
private final int mSnapMode;
private final int mMinimalSizeResizableTask;
private final int mTaskHeightInMinimizedMode;
private final float mFixedRatio;
private boolean mIsHorizontalDivision;
@@ -93,6 +99,11 @@ public class DividerSnapAlgorithm {
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
boolean isHorizontalDivision, Rect insets) {
this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false);
}
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) {
mMinFlingVelocityPxPerSecond =
MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
mMinDismissVelocityPxPerSecond =
@@ -102,12 +113,14 @@ public class DividerSnapAlgorithm {
mDisplayHeight = displayHeight;
mIsHorizontalDivision = isHorizontalDivision;
mInsets.set(insets);
mSnapMode = res.getInteger(
com.android.internal.R.integer.config_dockedStackDividerSnapMode);
mSnapMode = isMinimizedMode ? SNAP_MODE_MINIMIZED :
res.getInteger(com.android.internal.R.integer.config_dockedStackDividerSnapMode);
mFixedRatio = res.getFraction(
com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
mMinimalSizeResizableTask = res.getDimensionPixelSize(
com.android.internal.R.dimen.default_minimal_size_resizable_task);
mTaskHeightInMinimizedMode = res.getDimensionPixelSize(
com.android.internal.R.dimen.task_height_of_minimized_mode);
calculateTargets(isHorizontalDivision);
mFirstSplitTarget = mTargets.get(1);
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
@@ -246,6 +259,7 @@ public class DividerSnapAlgorithm {
int dividerMax = isHorizontalDivision
? mDisplayHeight
: mDisplayWidth;
int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right;
mTargets.add(new SnapTarget(-mDividerSize, -mDividerSize, SnapTarget.FLAG_DISMISS_START,
0.35f));
switch (mSnapMode) {
@@ -258,8 +272,10 @@ public class DividerSnapAlgorithm {
case SNAP_ONLY_1_1:
addMiddleTarget(isHorizontalDivision);
break;
case SNAP_MODE_MINIMIZED:
addMinimizedTarget(isHorizontalDivision);
break;
}
int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right;
mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
SnapTarget.FLAG_DISMISS_END, 0.35f));
}
@@ -315,6 +331,12 @@ public class DividerSnapAlgorithm {
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
}
private void addMinimizedTarget(boolean isHorizontalDivision) {
int position = mTaskHeightInMinimizedMode;
position += isHorizontalDivision ? mInsets.top : mInsets.left;
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
}
public SnapTarget getMiddleTarget() {
return mMiddleTarget;
}

View File

@@ -488,6 +488,9 @@
<!-- The default minimal size of a resizable task, in both dimensions. -->
<dimen name="default_minimal_size_resizable_task">220dp</dimen>
<!-- Height of a task when in minimized mode from the top when launcher is resizable. -->
<dimen name="task_height_of_minimized_mode">80dp</dimen>
<!-- Minimum "smallest width" of the display for cascading menus to be enabled. -->
<dimen name="cascading_menus_min_smallest_width">720dp</dimen>

View File

@@ -1772,6 +1772,7 @@
<java-symbol type="id" name="replace_message" />
<java-symbol type="fraction" name="config_dimBehindFadeDuration" />
<java-symbol type="dimen" name="default_minimal_size_resizable_task" />
<java-symbol type="dimen" name="task_height_of_minimized_mode" />
<java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
<java-symbol type="fraction" name="config_autoBrightnessAdjustmentMaxGamma" />
<java-symbol type="integer" name="config_autoBrightnessAmbientLightHorizon"/>

View File

@@ -44,6 +44,7 @@ public class Divider extends SystemUI {
private boolean mVisible = false;
private boolean mMinimized = false;
private boolean mAdjustedForIme = false;
private boolean mHomeStackResizable = false;
private ForcedResizableInfoActivityController mForcedResizableController;
@Override
@@ -75,6 +76,7 @@ public class Divider extends SystemUI {
mView = (DividerView)
LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
final int size = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
@@ -92,7 +94,7 @@ public class Divider extends SystemUI {
removeDivider();
addDivider(configuration);
if (mMinimized) {
mView.setMinimizedDockStack(true);
mView.setMinimizedDockStack(true, mHomeStackResizable);
updateTouchable();
}
}
@@ -106,13 +108,14 @@ public class Divider extends SystemUI {
mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
// Update state because animations won't finish.
mView.setMinimizedDockStack(mMinimized);
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
}
}
});
}
private void updateMinimizedDockedStack(final boolean minimized, final long animDuration) {
private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
final boolean isHomeStackResizable) {
mView.post(new Runnable() {
@Override
public void run() {
@@ -120,9 +123,9 @@ public class Divider extends SystemUI {
mMinimized = minimized;
updateTouchable();
if (animDuration > 0) {
mView.setMinimizedDockStack(minimized, animDuration);
mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
} else {
mView.setMinimizedDockStack(minimized);
mView.setMinimizedDockStack(minimized, isHomeStackResizable);
}
}
}
@@ -139,7 +142,7 @@ public class Divider extends SystemUI {
}
private void updateTouchable() {
mWindowManager.setTouchable(!mMinimized && !mAdjustedForIme);
mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);
}
@Override
@@ -162,9 +165,10 @@ public class Divider extends SystemUI {
}
@Override
public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
throws RemoteException {
updateMinimizedDockedStack(minimized, animDuration);
public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
boolean isHomeStackResizable) throws RemoteException {
mHomeStackResizable = isHomeStackResizable;
updateMinimizedDockedStack(minimized, animDuration, isHomeStackResizable);
}
@Override

View File

@@ -64,6 +64,7 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
@@ -123,6 +124,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private boolean mMoving;
private int mTouchSlop;
private boolean mBackgroundLifted;
private boolean mIsInMinimizeInteraction;
private int mDividerPositionBeforeMinimized;
private int mDividerInsets;
private int mDisplayWidth;
@@ -145,6 +148,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
private DividerSnapAlgorithm mSnapAlgorithm;
private DividerSnapAlgorithm mMinimizedSnapAlgorithm;
private final Rect mStableInsets = new Rect();
private boolean mGrowRecents;
@@ -154,6 +158,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private int mExitStartPosition;
private GestureDetector mGestureDetector;
private boolean mDockedStackMinimized;
private boolean mHomeStackResizable;
private boolean mAdjustedForIme;
private DividerState mState;
@@ -350,8 +355,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|| mStableInsets.bottom != insets.getStableInsetBottom()) {
mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
insets.getStableInsetRight(), insets.getStableInsetBottom());
if (mSnapAlgorithm != null) {
if (mSnapAlgorithm != null || mMinimizedSnapAlgorithm != null) {
mSnapAlgorithm = null;
mMinimizedSnapAlgorithm = null;
initializeSnapAlgorithm();
}
}
@@ -446,11 +452,17 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
}
if (mMinimizedSnapAlgorithm == null) {
mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(),
mStableInsets, mDockedStackMinimized && mHomeStackResizable);
}
}
public DividerSnapAlgorithm getSnapAlgorithm() {
initializeSnapAlgorithm();
return mSnapAlgorithm;
return mDockedStackMinimized && mHomeStackResizable ? mMinimizedSnapAlgorithm :
mSnapAlgorithm;
}
public int getCurrentPosition() {
@@ -495,7 +507,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mMoving = true;
}
if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(
SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
mStartPosition, 0 /* velocity */, false /* hardDismiss */);
resizeStackDelayed(calculatePosition(x, y), mStartPosition, snapTarget);
}
@@ -551,9 +563,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private void fling(int position, float velocity, boolean avoidDismissStart,
boolean logMetrics) {
SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
snapTarget = mSnapAlgorithm.getFirstSplitTarget();
DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm();
SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity);
if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) {
snapTarget = currentSnapAlgorithm.getFirstSplitTarget();
}
if (logMetrics) {
logResizeEvent(snapTarget);
@@ -574,6 +587,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
final long endDelay) {
if (mCurrentAnimator != null) {
cancelFlingAnimation();
updateDockSide();
}
final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(),
@@ -590,6 +607,12 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mExitAnimationRunning = false;
EventBus.getDefault().send(new StoppedDragingEvent());
};
Runnable notCancelledEndAction = () -> {
// Reset minimized divider position after unminimized state animation finishes
if (!mDockedStackMinimized && mIsInMinimizeInteraction) {
mIsInMinimizeInteraction = false;
}
};
anim.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -612,8 +635,14 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
if (delay == 0) {
endAction.run();
if (!mCancelled) {
notCancelledEndAction.run();
}
} else {
mHandler.postDelayed(endAction, delay);
if (!mCancelled) {
mHandler.postDelayed(notCancelledEndAction, delay);
}
}
}
});
@@ -692,57 +721,92 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
public void setMinimizedDockStack(boolean minimized) {
public void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable) {
mHomeStackResizable = isHomeStackResizable;
updateDockSide();
mHandle.setAlpha(minimized ? 0f : 1f);
if (!minimized) {
resetBackground();
} else if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
} else if (mDockSide == WindowManager.DOCKED_LEFT
|| mDockSide == WindowManager.DOCKED_RIGHT) {
mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
? 0
: mBackground.getWidth());
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
} else if (!isHomeStackResizable) {
if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
} else if (mDockSide == WindowManager.DOCKED_LEFT
|| mDockSide == WindowManager.DOCKED_RIGHT) {
mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
? 0
: mBackground.getWidth());
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
}
}
mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
mDockedStackMinimized = minimized;
if (!isHomeStackResizable) {
mHandle.setAlpha(minimized ? 0f : 1f);
mDockedStackMinimized = minimized;
} else if (mDockedStackMinimized != minimized) {
if (mStableInsets.isEmpty()) {
SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
}
if (!mIsInMinimizeInteraction && minimized) {
mIsInMinimizeInteraction = true;
mDividerPositionBeforeMinimized = DockedDividerUtils.calculateMiddlePosition(
isHorizontalDivision(), mStableInsets, mDisplayWidth, mDisplayHeight,
mDividerSize);
}
mMinimizedSnapAlgorithm = null;
mDockedStackMinimized = minimized;
initializeSnapAlgorithm();
}
}
public void setMinimizedDockStack(boolean minimized, long animDuration) {
public void setMinimizedDockStack(boolean minimized, long animDuration,
boolean isHomeStackResizable) {
mHomeStackResizable = isHomeStackResizable;
updateDockSide();
mHandle.animate()
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
.alpha(minimized ? 0f : 1f)
.start();
if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
mBackground.animate()
.scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
} else if (mDockSide == WindowManager.DOCKED_LEFT
|| mDockSide == WindowManager.DOCKED_RIGHT) {
mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
? 0
: mBackground.getWidth());
mBackground.animate()
.scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
if (!isHomeStackResizable) {
mMinimizedShadow.animate()
.alpha(minimized ? 1f : 0f)
.setInterpolator(Interpolators.ALPHA_IN)
.setDuration(animDuration)
.start();
mHandle.animate()
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
.alpha(minimized ? 0f : 1f)
.start();
if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
mBackground.animate()
.scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
} else if (mDockSide == WindowManager.DOCKED_LEFT
|| mDockSide == WindowManager.DOCKED_RIGHT) {
mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
? 0
: mBackground.getWidth());
mBackground.animate()
.scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
}
mDockedStackMinimized = minimized;
} else if (mDockedStackMinimized != minimized) {
mIsInMinimizeInteraction = true;
if (minimized) {
mDividerPositionBeforeMinimized = getCurrentPosition();
}
mMinimizedSnapAlgorithm = null;
mDockedStackMinimized = minimized;
initializeSnapAlgorithm();
stopDragging(getCurrentPosition(), minimized ?
mMinimizedSnapAlgorithm.getMiddleTarget() :
mSnapAlgorithm.calculateNonDismissingSnapTarget(
mDividerPositionBeforeMinimized),
animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
}
if (!minimized) {
mBackground.animate().withEndAction(mResetBackgroundRunnable);
}
mMinimizedShadow.animate()
.alpha(minimized ? 1f : 0f)
.setInterpolator(Interpolators.ALPHA_IN)
.setDuration(animDuration)
.start();
mBackground.animate()
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
.start();
mDockedStackMinimized = minimized;
}
public void setAdjustedForIme(boolean adjustedForIme) {
@@ -809,6 +873,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mDisplayWidth = info.logicalWidth;
mDisplayHeight = info.logicalHeight;
mSnapAlgorithm = null;
mMinimizedSnapAlgorithm = null;
initializeSnapAlgorithm();
}
@@ -871,6 +936,15 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
mLastResizeRect.set(mDockedRect);
if (mHomeStackResizable && mIsInMinimizeInteraction) {
calculateBoundsForPosition(mDividerPositionBeforeMinimized, mDockSide, mDockedTaskRect);
calculateBoundsForPosition(mDividerPositionBeforeMinimized,
DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
mOtherTaskRect, null);
return;
}
if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
if (mCurrentAnimator != null) {
calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
@@ -922,7 +996,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
} else {
mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
}
SnapTarget closestDismissTarget = mSnapAlgorithm.getClosestDismissTarget(position);
SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
float dimFraction = getDimFraction(position, closestDismissTarget);
mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f,
getStackIdForDismissTarget(closestDismissTarget),
@@ -943,7 +1017,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mEntranceAnimationRunning) {
return 0f;
}
float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
float fraction = getSnapAlgorithm().calculateDismissingFraction(position);
fraction = Math.max(0, Math.min(fraction, 1f));
fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
if (hasInsetsAtDismissTarget(dismissTarget)) {
@@ -959,13 +1033,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
*/
private boolean hasInsetsAtDismissTarget(SnapTarget dismissTarget) {
if (isHorizontalDivision()) {
if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
if (dismissTarget == getSnapAlgorithm().getDismissStartTarget()) {
return mStableInsets.top != 0;
} else {
return mStableInsets.bottom != 0;
}
} else {
if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
if (dismissTarget == getSnapAlgorithm().getDismissStartTarget()) {
return mStableInsets.left != 0;
} else {
return mStableInsets.right != 0;
@@ -1135,6 +1209,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mStableInsets.isEmpty()) {
SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
mSnapAlgorithm = null;
mMinimizedSnapAlgorithm = null;
initializeSnapAlgorithm();
}

View File

@@ -553,8 +553,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
@Override
public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
throws RemoteException {
public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
boolean isHomeStackResizable) throws RemoteException {
}
@Override

View File

@@ -19598,10 +19598,15 @@ public class ActivityManagerService extends IActivityManager.Stub
/** Helper method that requests bounds from WM and applies them to stack. */
private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
final Rect newBounds = mStackSupervisor.getStack(stackId).getBoundsForNewConfiguration();
final Rect newStackBounds = new Rect();
final Rect newTempTaskBounds = new Rect();
mStackSupervisor.getStack(stackId).getBoundsForNewConfiguration(newStackBounds,
newTempTaskBounds);
mStackSupervisor.resizeStackLocked(
stackId, newBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
stackId, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
!newTempTaskBounds.isEmpty() ? newTempTaskBounds : null /* tempTaskBounds */,
null /* tempTaskInsetBounds */, false /* preserveWindows */,
false /* allowResizeInDockedMode */, deferResume);
}
/**

View File

@@ -542,8 +542,10 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL
mWindowContainerController.setPictureInPictureAspectRatio(aspectRatio);
}
void getStackDockedModeBounds(Rect outBounds, boolean ignoreVisibility) {
mWindowContainerController.getStackDockedModeBounds(outBounds, ignoreVisibility);
void getStackDockedModeBounds(Rect outBounds, Rect outTempBounds, Rect outTempInsetBounds,
boolean ignoreVisibility) {
mWindowContainerController.getStackDockedModeBounds(outBounds, outTempBounds,
outTempInsetBounds, ignoreVisibility);
}
void prepareFreezingTaskBounds() {
@@ -562,8 +564,8 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL
outBounds.setEmpty();
}
Rect getBoundsForNewConfiguration() {
return mWindowContainerController.getBoundsForNewConfiguration();
void getBoundsForNewConfiguration(Rect outBounds, Rect outTempBounds) {
mWindowContainerController.getBoundsForNewConfiguration(outBounds, outTempBounds);
}
void positionChildWindowContainerAtTop(TaskRecord child) {

View File

@@ -418,8 +418,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ActivityMetricsLogger mActivityMetricsLogger;
private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
@Override
protected int getChildCount() {
return mActivityDisplays.size();
@@ -529,7 +527,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mService = service;
mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
mResizeDockedStackTimeout = new ResizeDockedStackTimeout(service, this, mHandler);
mKeyguardController = new KeyguardController(service, this);
}
@@ -2346,13 +2343,19 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// static stacks need to be adjusted so they don't overlap with the docked stack.
// We get the bounds to use from window manager which has been adjusted for any
// screen controls and is also the same for all stacks.
final Rect tempOtherTaskRect = new Rect();
final Rect tempOtherTaskInsetRect = new Rect();
for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
final ActivityStack current = getStack(i);
if (current != null && StackId.isResizeableByDockedStack(i)) {
current.getStackDockedModeBounds(tempRect, true /* ignoreVisibility */);
resizeStackLocked(i, tempRect, tempOtherTaskBounds,
tempOtherTaskInsetBounds, preserveWindows,
true /* allowResizeInDockedMode */, deferResume);
current.getStackDockedModeBounds(tempRect, tempOtherTaskRect,
tempOtherTaskInsetRect, true /* ignoreVisibility */);
resizeStackLocked(i, tempRect,
!tempOtherTaskRect.isEmpty() ? tempOtherTaskRect :
tempOtherTaskBounds,
!tempOtherTaskInsetRect.isEmpty() ? tempOtherTaskInsetRect :
tempOtherTaskInsetBounds,
preserveWindows, true /* allowResizeInDockedMode */, deferResume);
}
}
}
@@ -2364,12 +2367,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
mResizeDockedStackTimeout.notifyResizing(dockedBounds,
tempDockedTaskBounds != null
|| tempDockedTaskInsetBounds != null
|| tempOtherTaskBounds != null
|| tempOtherTaskInsetBounds != null);
}
void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {

View File

@@ -1,63 +0,0 @@
/*
* Copyright (C) 2015 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.server.am;
import android.graphics.Rect;
import android.os.Handler;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
/**
* When resizing the docked stack, a caller can temporarily supply task bounds that are different
* from the stack bounds. In order to return to a sane state if the caller crashes or has a bug,
* this class manages this cycle.
*/
class ResizeDockedStackTimeout {
private static final long TIMEOUT_MS = 10 * 1000;
private final ActivityManagerService mService;
private final ActivityStackSupervisor mSupervisor;
private final Handler mHandler;
private final Rect mCurrentDockedBounds = new Rect();
private final Runnable mTimeoutRunnable = new Runnable() {
@Override
public void run() {
synchronized (mService) {
mSupervisor.resizeDockedStackLocked(mCurrentDockedBounds, null, null, null, null,
PRESERVE_WINDOWS);
}
}
};
ResizeDockedStackTimeout(ActivityManagerService service, ActivityStackSupervisor supervisor,
Handler handler) {
mService = service;
mSupervisor = supervisor;
mHandler = handler;
}
void notifyResizing(Rect dockedBounds, boolean hasTempBounds) {
mHandler.removeCallbacks(mTimeoutRunnable);
if (!hasTempBounds) {
return;
}
mCurrentDockedBounds.set(dockedBounds);
mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
}
}

View File

@@ -102,12 +102,14 @@ public class DockedStackDividerController implements DimLayerUser {
private int mDividerWindowWidth;
private int mDividerWindowWidthInactive;
private int mDividerInsets;
private int mTaskHeightInMinimizedMode;
private boolean mResizing;
private WindowState mWindow;
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
private final Rect mTmpRect3 = new Rect();
private final Rect mLastRect = new Rect();
private final Rect mMiddlePositionDockedStackRect = new Rect();
private boolean mLastVisibility = false;
private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
= new RemoteCallbackList<>();
@@ -189,6 +191,40 @@ public class DockedStackDividerController implements DimLayerUser {
return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
}
/**
* The middlePositionDockedStackRect is half the screen area that sits at the top (portrait) or
* left (landscape).
*
* @return fixed rect for temp stack
*/
Rect getMiddlePositionDockedStackRect() {
return mMinimizedDock && isHomeStackResizable() ? mMiddlePositionDockedStackRect : null;
}
void getHomeStackBoundsInDockedMode(Rect outBounds) {
final DisplayInfo di = mDisplayContent.getDisplayInfo();
mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
mTmpRect);
int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
Configuration configuration = mDisplayContent.getConfiguration();
if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
di.logicalWidth, di.logicalHeight);
} else {
outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left, 0,
di.logicalWidth, di.logicalHeight);
}
}
boolean isHomeStackResizable() {
final TaskStack homeStack = mDisplayContent.getHomeStack();
if (homeStack == null) {
return false;
}
final Task homeTask = homeStack.findHomeTask();
return homeTask != null && homeTask.isResizeable();
}
private void initSnapAlgorithmForRotations() {
final Configuration baseConfig = mDisplayContent.getConfiguration();
@@ -228,11 +264,34 @@ public class DockedStackDividerController implements DimLayerUser {
com.android.internal.R.dimen.docked_stack_divider_insets);
mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.task_height_of_minimized_mode);
initSnapAlgorithmForRotations();
}
/**
* Calculates the constant rects {@link mMiddlePositionDockedStackRect} based on orientation,
* stable insets and display size.
*/
private void updateConstantRects() {
final DisplayInfo di = mDisplayContent.getDisplayInfo();
mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
mTmpRect);
int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
Configuration configuration = mDisplayContent.getConfiguration();
boolean isHorizontal = configuration.orientation == Configuration.ORIENTATION_PORTRAIT;
int middlePosition = DockedDividerUtils.calculateMiddlePosition(isHorizontal, mTmpRect,
di.logicalWidth, di.logicalHeight, dividerSize);
if (isHorizontal) {
mMiddlePositionDockedStackRect.set(0, 0, di.logicalWidth, middlePosition);
} else {
mMiddlePositionDockedStackRect.set(0, 0, middlePosition, di.logicalHeight);
}
}
void onConfigurationChanged() {
loadDimens();
updateConstantRects();
}
boolean isResizing() {
@@ -412,7 +471,19 @@ public class DockedStackDividerController implements DimLayerUser {
return mImeHideRequested;
}
private void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
boolean isHomeStackResizable) {
long animDuration = 0;
if (animate) {
final TaskStack stack = mDisplayContent.getStackById(DOCKED_STACK_ID);
final long transitionDuration = isAnimationMaximizing()
? mService.mAppTransition.getLastClipRevealTransitionDuration()
: DEFAULT_APP_TRANSITION_DURATION;
mAnimationDuration = (long)
(transitionDuration * mService.getTransitionAnimationScaleLocked());
mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
}
mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
minimizedDock ? 1 : 0, 0).sendToTarget();
@@ -420,7 +491,8 @@ public class DockedStackDividerController implements DimLayerUser {
for (int i = 0; i < size; ++i) {
final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
try {
listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
isHomeStackResizable);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
}
@@ -458,7 +530,8 @@ public class DockedStackDividerController implements DimLayerUser {
mDockedStackListeners.register(listener);
notifyDockedDividerVisibilityChanged(wasVisible());
notifyDockedStackExistsChanged(mDisplayContent.getDockedStackIgnoringVisibility() != null);
notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
isHomeStackResizable());
notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
}
@@ -577,17 +650,23 @@ public class DockedStackDividerController implements DimLayerUser {
final boolean imeChanged = clearImeAdjustAnimation();
boolean minimizedChange = false;
if (minimizedDock) {
if (animate) {
startAdjustAnimation(0f, 1f);
} else {
minimizedChange |= setMinimizedDockedStack(true);
}
if (isHomeStackResizable()) {
notifyDockedStackMinimizedChanged(minimizedDock, true /* animate */,
true /* isHomeStackResizable */);
minimizedChange = true;
} else {
if (animate) {
startAdjustAnimation(1f, 0f);
if (minimizedDock) {
if (animate) {
startAdjustAnimation(0f, 1f);
} else {
minimizedChange |= setMinimizedDockedStack(true);
}
} else {
minimizedChange |= setMinimizedDockedStack(false);
if (animate) {
startAdjustAnimation(1f, 0f);
} else {
minimizedChange |= setMinimizedDockedStack(false);
}
}
}
if (imeChanged || minimizedChange) {
@@ -688,7 +767,7 @@ public class DockedStackDividerController implements DimLayerUser {
private boolean setMinimizedDockedStack(boolean minimized) {
final TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
notifyDockedStackMinimizedChanged(minimized, 0);
notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
}
@@ -742,14 +821,8 @@ public class DockedStackDividerController implements DimLayerUser {
if (!mAnimationStarted) {
mAnimationStarted = true;
mAnimationStartTime = now;
final long transitionDuration = isAnimationMaximizing()
? mService.mAppTransition.getLastClipRevealTransitionDuration()
: DEFAULT_APP_TRANSITION_DURATION;
mAnimationDuration = (long)
(transitionDuration * mService.getTransitionAnimationScaleLocked());
mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
notifyDockedStackMinimizedChanged(mMinimizedDock,
(long) (mAnimationDuration * mMaximizeMeetFraction));
notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
isHomeStackResizable() /* isHomeStackResizable */);
}
float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)

View File

@@ -619,7 +619,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
final InputChannel inputChannel = w.mInputChannel;
final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
|| w.isAdjustedForMinimizedDock()) {
|| w.canReceiveTouchInput()) {
// Skip this window because it cannot possibly receive input.
return;
}

View File

@@ -220,13 +220,17 @@ public class StackWindowController
}
}
public void getStackDockedModeBounds(Rect outBounds, boolean ignoreVisibility) {
public void getStackDockedModeBounds(Rect outBounds, Rect outTempBounds,
Rect outTempInsetBounds, boolean ignoreVisibility) {
synchronized (mWindowMap) {
if (mContainer != null) {
mContainer.getStackDockedModeBoundsLocked(outBounds, ignoreVisibility);
mContainer.getStackDockedModeBoundsLocked(outBounds, outTempBounds,
outTempInsetBounds, ignoreVisibility);
return;
}
outBounds.setEmpty();
outTempBounds.setEmpty();
outTempInsetBounds.setEmpty();
}
}
@@ -269,11 +273,9 @@ public class StackWindowController
}
}
public Rect getBoundsForNewConfiguration() {
public void getBoundsForNewConfiguration(Rect outBounds, Rect outTempBounds) {
synchronized(mWindowMap) {
final Rect outBounds = new Rect();
mContainer.getBoundsForNewConfiguration(outBounds);
return outBounds;
mContainer.getBoundsForNewConfiguration(outBounds, outTempBounds);
}
}

View File

@@ -213,7 +213,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mAdjustedBounds.set(bounds);
final boolean adjusted = !mAdjustedBounds.isEmpty();
Rect insetBounds = null;
if (adjusted && isAdjustedForMinimizedDock()) {
if (adjusted && isAdjustedForMinimizedDockedStack()) {
insetBounds = mBounds;
} else if (adjusted && mAdjustedForIme) {
if (mImeGoingAway) {
@@ -420,9 +420,14 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return true;
}
void getBoundsForNewConfiguration(Rect outBounds) {
void getBoundsForNewConfiguration(Rect outBounds, Rect outTempBounds) {
outBounds.set(mBoundsAfterRotation);
mBoundsAfterRotation.setEmpty();
final DockedStackDividerController controller = getDisplayContent()
.mDividerControllerLocked;
if (controller.isMinimizedDock() && mStackId == DOCKED_STACK_ID) {
outTempBounds.set(controller.getMiddlePositionDockedStackRect());
}
}
/**
@@ -482,7 +487,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
isMinimizedDockAndHomeStackResizable());
final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
// Recalculate the bounds based on the position of the target.
@@ -675,7 +681,18 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
super.onDisplayChanged(dc);
}
void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
void getStackDockedModeBoundsLocked(Rect outBounds, Rect outTempBounds,
Rect outTempInsetBounds, boolean ignoreVisibility) {
if (mStackId == HOME_STACK_ID && findHomeTask().isResizeable()) {
// Calculate the home stack bounds when in docked mode
getDisplayContent().mDividerControllerLocked
.getHomeStackBoundsInDockedMode(outTempBounds);
outTempInsetBounds.set(outTempBounds);
} else {
outTempBounds.setEmpty();
outTempInsetBounds.setEmpty();
}
if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
|| mDisplayContent == null) {
outBounds.set(mBounds);
@@ -789,7 +806,9 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mService.mDockedStackCreateBounds = null;
final Rect bounds = new Rect();
getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
final Rect tempBounds = new Rect();
final Rect tempInsetBounds = new Rect();
getStackDockedModeBoundsLocked(bounds, tempBounds, tempInsetBounds, true /*ignoreVisibility*/);
getController().requestResize(bounds);
}
@@ -946,8 +965,9 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
}
boolean isAdjustedForMinimizedDock() {
return mMinimizeAmount != 0f;
boolean shouldIgnoreInput() {
return isAdjustedForMinimizedDockedStack() || mStackId == DOCKED_STACK_ID &&
isMinimizedDockAndHomeStackResizable();
}
/**
@@ -1075,6 +1095,11 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return true;
}
private boolean isMinimizedDockAndHomeStackResizable() {
return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
&& mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
}
/**
* @return the distance in pixels how much the stack gets minimized from it's original size
*/
@@ -1344,9 +1369,17 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
* tasks (including the focused).
*
* We save the focused task region once we find it, and add it back at the end.
*
* If the task is home stack and it is resizable in the minimized state, we want to
* exclude the docked stack from touch so we need the entire screen area and not just a
* small portion which the home stack currently is resized to.
*/
task.getDimBounds(mTmpRect);
if (task.isHomeTask() && isMinimizedDockAndHomeStackResizable()) {
mDisplayContent.getLogicalDisplayRect(mTmpRect);
} else {
task.getDimBounds(mTmpRect);
}
if (task == focusedTask) {
// Add the focused task rect back into the exclude region once we are done

View File

@@ -1671,11 +1671,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return !mLastReportedConfiguration.equals(getConfiguration());
}
boolean isAdjustedForMinimizedDock() {
return mAppToken != null && mAppToken.mTask != null
&& mAppToken.mTask.mStack.isAdjustedForMinimizedDock();
}
void onWindowReplacementTimeout() {
if (mWillReplaceWindow) {
// Since the window already timed out, remove it immediately now.
@@ -2364,7 +2359,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
&& (mAppToken == null || mAppToken.windowsAreFocusable())
&& !isAdjustedForMinimizedDock();
&& !canReceiveTouchInput();
}
/** @return true if this window desires touch events. */
boolean canReceiveTouchInput() {
return mAppToken != null && mAppToken.mTask != null
&& mAppToken.mTask.mStack.shouldIgnoreInput();
}
@Override