From 19cf2972582198484816ac15ba83a4f46946082b Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Thu, 7 Apr 2016 23:26:10 -0700 Subject: [PATCH] Disable snap targets that make apps <220dp - Make minimal task size 220dp. - Disable upper and lower targets if they result in less than 220dp task size. - If even the middle target doesn't allow 220dp task size, disable entering split screen altogether. Bug: 26451260 Change-Id: I06e358c9b3da0172c5def75cdadf975f87f9fa57 --- .../internal/policy/DividerSnapAlgorithm.java | 76 ++++++++++++++++--- core/res/res/values/config.xml | 4 - core/res/res/values/dimens.xml | 3 + core/res/res/values/symbols.xml | 2 +- .../views/RecentsViewTouchHandler.java | 20 ++++- .../statusbar/phone/PhoneStatusBar.java | 4 +- .../server/am/ActivityStackSupervisor.java | 10 +-- 7 files changed, 93 insertions(+), 26 deletions(-) diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java index 9907ea92670b2..669e1efb92491 100644 --- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java @@ -17,9 +17,13 @@ package com.android.internal.policy; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; +import android.hardware.display.DisplayManager; import android.util.Log; +import android.view.Display; +import android.view.DisplayInfo; import java.util.ArrayList; @@ -57,6 +61,7 @@ public class DividerSnapAlgorithm { private final ArrayList mTargets = new ArrayList<>(); private final Rect mInsets = new Rect(); private final int mSnapMode; + private final int mMinimalSizeResizableTask; private final float mFixedRatio; private boolean mIsHorizontalDivision; @@ -70,6 +75,22 @@ public class DividerSnapAlgorithm { private final SnapTarget mDismissEndTarget; private final SnapTarget mMiddleTarget; + public static DividerSnapAlgorithm create(Context ctx, Rect insets) { + DisplayInfo displayInfo = new DisplayInfo(); + ctx.getSystemService(DisplayManager.class).getDisplay( + Display.DEFAULT_DISPLAY).getDisplayInfo(displayInfo); + int dividerWindowWidth = ctx.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.docked_stack_divider_thickness); + int dividerInsets = ctx.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.docked_stack_divider_insets); + return new DividerSnapAlgorithm(ctx.getResources(), + displayInfo.logicalWidth, displayInfo.logicalHeight, + dividerWindowWidth - 2 * dividerInsets, + ctx.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_PORTRAIT, + insets); + } + public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision, Rect insets) { mMinFlingVelocityPxPerSecond = @@ -85,6 +106,8 @@ public class DividerSnapAlgorithm { 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); calculateTargets(isHorizontalDivision); mFirstSplitTarget = mTargets.get(1); mLastSplitTarget = mTargets.get(mTargets.size() - 2); @@ -93,6 +116,20 @@ public class DividerSnapAlgorithm { mMiddleTarget = mTargets.get(mTargets.size() / 2); } + /** + * @return whether it's feasible to enable split screen in the current configuration, i.e. when + * snapping in the middle both tasks are larger than the minimal task size. + */ + public boolean isSplitScreenFeasible() { + int statusBarSize = mInsets.top; + int navBarSize = mIsHorizontalDivision ? mInsets.bottom : mInsets.right; + int size = mIsHorizontalDivision + ? mDisplayHeight + : mDisplayWidth; + int availableSpace = size - navBarSize - statusBarSize - mDividerSize; + return availableSpace / 2 >= mMinimalSizeResizableTask; + } + public SnapTarget calculateSnapTarget(int position, float velocity) { return calculateSnapTarget(position, velocity, true /* hardDismiss */); } @@ -212,10 +249,10 @@ public class DividerSnapAlgorithm { mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START, 0.35f)); switch (mSnapMode) { case SNAP_MODE_16_9: - addRatio16_9Targets(isHorizontalDivision); + addRatio16_9Targets(isHorizontalDivision, dividerMax); break; case SNAP_FIXED_RATIO: - addFixedDivisionTargets(isHorizontalDivision); + addFixedDivisionTargets(isHorizontalDivision, dividerMax); break; case SNAP_ONLY_1_1: addMiddleTarget(isHorizontalDivision); @@ -225,19 +262,24 @@ public class DividerSnapAlgorithm { mTargets.add(new SnapTarget(dividerMax - navBarSize, SnapTarget.FLAG_DISMISS_END, 0.35f)); } - private void addFixedDivisionTargets(boolean isHorizontalDivision) { + private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition, + int bottomPosition, int dividerMax) { + maybeAddTarget(topPosition, topPosition - mInsets.top); + addMiddleTarget(isHorizontalDivision); + maybeAddTarget(bottomPosition, dividerMax - mInsets.bottom + - (bottomPosition + mDividerSize)); + } + private void addFixedDivisionTargets(boolean isHorizontalDivision, int dividerMax) { int start = isHorizontalDivision ? mInsets.top : mInsets.left; int end = isHorizontalDivision ? mDisplayHeight - mInsets.bottom : mDisplayWidth - mInsets.right; - mTargets.add(new SnapTarget((int) (start + mFixedRatio * (end - start)) - mDividerSize / 2, - SnapTarget.FLAG_NONE)); - addMiddleTarget(isHorizontalDivision); - mTargets.add(new SnapTarget((int) (start + (1 - mFixedRatio) * (end - start)) - - mDividerSize / 2, SnapTarget.FLAG_NONE)); + int topPosition = (int) (start + mFixedRatio * (end - start)) - mDividerSize / 2; + int bottomPosition = (int) (start + (1 - mFixedRatio) * (end - start)) - mDividerSize / 2; + addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax); } - private void addRatio16_9Targets(boolean isHorizontalDivision) { + private void addRatio16_9Targets(boolean isHorizontalDivision, int dividerMax) { int start = isHorizontalDivision ? mInsets.top : mInsets.left; int end = isHorizontalDivision ? mDisplayHeight - mInsets.bottom @@ -248,9 +290,19 @@ public class DividerSnapAlgorithm { : mDisplayHeight - mInsets.bottom; float size = 9.0f / 16.0f * (endOther - startOther); int sizeInt = (int) Math.floor(size); - mTargets.add(new SnapTarget(start + sizeInt, SnapTarget.FLAG_NONE)); - addMiddleTarget(isHorizontalDivision); - mTargets.add(new SnapTarget(end - sizeInt - mDividerSize, SnapTarget.FLAG_NONE)); + int topPosition = start + sizeInt; + int bottomPosition = end - sizeInt - mDividerSize; + addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax); + } + + /** + * Adds a target at {@param position} but only if the area with size of {@param smallerSize} + * meets the minimal size requirement. + */ + private void maybeAddTarget(int position, int smallerSize) { + if (smallerSize >= mMinimalSizeResizableTask) { + mTargets.add(new SnapTarget(position, SnapTarget.FLAG_NONE)); + } } private void addMiddleTarget(boolean isHorizontalDivision) { diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b4371c189d405..04f1e17757367 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2434,10 +2434,6 @@ disables NetworkPolicyManagerService's presentation of data-usage notifications. --> - - 25% - diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 9aec1bb5e1636..dd54d57058afe 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -455,4 +455,7 @@ 34.15% 5dp + + + 220dp diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9342eb1b93979..6abb43bdf6673 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1727,7 +1727,7 @@ - + diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java index 33d5bb7b0c99e..a867bdeecb694 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java @@ -19,15 +19,20 @@ package com.android.systemui.recents.views; import android.app.ActivityManager; import android.content.res.Configuration; import android.graphics.Point; +import android.graphics.Rect; +import android.provider.Settings; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.ViewDebug; import android.widget.Toast; +import com.android.internal.policy.DividerSnapAlgorithm; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.RecentsImpl; import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.ConfigurationChangedEvent; import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; @@ -81,12 +86,20 @@ public class RecentsViewTouchHandler { private float mDragSlop; private DropTarget mLastDropTarget; + private DividerSnapAlgorithm mDividerSnapAlgorithm; private ArrayList mDropTargets = new ArrayList<>(); private ArrayList mVisibleDockStates = new ArrayList<>(); public RecentsViewTouchHandler(RecentsView rv) { mRv = rv; mDragSlop = ViewConfiguration.get(rv.getContext()).getScaledTouchSlop(); + updateSnapAlgorithm(); + } + + private void updateSnapAlgorithm() { + Rect insets = new Rect(); + SystemServicesProxy.getInstance(mRv.getContext()).getStableInsets(insets); + mDividerSnapAlgorithm = DividerSnapAlgorithm.create(mRv.getContext(), insets); } /** @@ -150,7 +163,8 @@ public class RecentsViewTouchHandler { mTaskView.setTranslationY(y); mVisibleDockStates.clear(); - if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()) { + if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask() + && mDividerSnapAlgorithm.isSplitScreenFeasible()) { if (!event.task.isDockable) { Toast.makeText(mRv.getContext(), R.string.recents_drag_non_dockable_task_message, Toast.LENGTH_SHORT).show(); @@ -176,6 +190,10 @@ public class RecentsViewTouchHandler { mLastDropTarget = null; } + public final void onBusEvent(ConfigurationChangedEvent event) { + updateSnapAlgorithm(); + } + /** * Handles dragging touch events */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index d036fe4807cde..933d5bdb743dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1167,7 +1167,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public boolean onLongClick(View v) { - if (mRecents == null || !ActivityManager.supportsMultiWindow()) { + if (mRecents == null || !ActivityManager.supportsMultiWindow() + || !getComponent(Divider.class).getView().getSnapAlgorithm() + .isSplitScreenFeasible()) { return false; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 83950837dd289..d34e8fc461ea2 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -3249,13 +3249,9 @@ public final class ActivityStackSupervisor implements DisplayListener { } private void calculateDefaultMinimalSizeOfResizeableTasks(ActivityDisplay display) { - if (display.mDisplayId != Display.DEFAULT_DISPLAY) { - return; - } - final float fraction = mService.mContext.getResources().getFraction(com.android.internal.R. - fraction.config_displayFractionForDefaultMinimalSizeOfResizeableTask, 1, 1); - mDefaultMinimalSizeOfResizeableTask = (int) (fraction * Math.min( - display.mDisplayInfo.logicalWidth, display.mDisplayInfo.logicalHeight)); + mDefaultMinimalSizeOfResizeableTask = + mService.mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.default_minimal_size_resizable_task); } private void handleDisplayRemoved(int displayId) {