Adding hint text for drop targets.
Bug: 28192178 Change-Id: Id7be5129488622b56082d2dfa328b751311cabd7
This commit is contained in:
@@ -640,6 +640,9 @@
|
||||
<!-- The amount of overscroll allowed when flinging to the end of the stack. -->
|
||||
<dimen name="recents_fling_overscroll_distance">24dp</dimen>
|
||||
|
||||
<!-- The size of the drag hint text. -->
|
||||
<dimen name="recents_drag_hint_text_size">14sp</dimen>
|
||||
|
||||
<!-- The min alpha to apply to a task affiliation group color. -->
|
||||
<item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
|
||||
|
||||
|
||||
@@ -737,6 +737,8 @@
|
||||
<string name="recents_stack_action_button_label">Clear all</string>
|
||||
<!-- Recents: Incompatible task message. [CHAR LIMIT=NONE] -->
|
||||
<string name="recents_incompatible_app_message">App doesn\'t support split screen</string>
|
||||
<!-- Recents: Hint text that shows on the drop targets to start multiwindow. [CHAR LIMIT=NONE] -->
|
||||
<string name="recents_drag_hint_message">Drag here to use split screen</string>
|
||||
|
||||
<!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
|
||||
<string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
|
||||
|
||||
@@ -30,17 +30,21 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.RectEvaluator;
|
||||
import android.annotation.IntDef;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.IntProperty;
|
||||
import android.util.SparseArray;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
@@ -56,6 +60,8 @@ import com.android.systemui.recents.views.DropTarget;
|
||||
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -240,22 +246,30 @@ public class TaskStack {
|
||||
*/
|
||||
public static class DockState implements DropTarget {
|
||||
|
||||
// The rotation to apply to the hint text
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({HORIZONTAL, VERTICAL})
|
||||
public @interface TextOrientation {}
|
||||
private static final int HORIZONTAL = 0;
|
||||
private static final int VERTICAL = 1;
|
||||
|
||||
private static final int DOCK_AREA_ALPHA = 192;
|
||||
public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, null, null, null);
|
||||
public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL,
|
||||
null, null, null);
|
||||
public static final DockState LEFT = new DockState(DOCKED_LEFT,
|
||||
DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
|
||||
DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL,
|
||||
new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
|
||||
new RectF(0, 0, 0.5f, 1));
|
||||
public static final DockState TOP = new DockState(DOCKED_TOP,
|
||||
DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
|
||||
DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
|
||||
new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
|
||||
new RectF(0, 0, 1, 0.5f));
|
||||
public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
|
||||
DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
|
||||
DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL,
|
||||
new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
|
||||
new RectF(0.5f, 0, 1, 1));
|
||||
public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
|
||||
DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
|
||||
DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
|
||||
new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
|
||||
new RectF(0, 0.5f, 1, 1));
|
||||
|
||||
@@ -267,33 +281,109 @@ public class TaskStack {
|
||||
}
|
||||
|
||||
// Represents the view state of this dock state
|
||||
public class ViewState {
|
||||
public static class ViewState {
|
||||
private static final IntProperty<ViewState> HINT_ALPHA =
|
||||
new IntProperty<ViewState>("drawableAlpha") {
|
||||
@Override
|
||||
public void setValue(ViewState object, int alpha) {
|
||||
object.mHintTextAlpha = alpha;
|
||||
object.dockAreaOverlay.invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(ViewState object) {
|
||||
return object.mHintTextAlpha;
|
||||
}
|
||||
};
|
||||
|
||||
public final int dockAreaAlpha;
|
||||
public final ColorDrawable dockAreaOverlay;
|
||||
private AnimatorSet dockAreaOverlayAnimator;
|
||||
public final int hintTextAlpha;
|
||||
public final int hintTextOrientation;
|
||||
|
||||
private ViewState(int alpha) {
|
||||
dockAreaAlpha = alpha;
|
||||
private final int mHintTextResId;
|
||||
private String mHintText;
|
||||
private Paint mHintTextPaint;
|
||||
private Point mHintTextBounds = new Point();
|
||||
private int mHintTextAlpha = 255;
|
||||
private AnimatorSet mDockAreaOverlayAnimator;
|
||||
private Rect mTmpRect = new Rect();
|
||||
|
||||
private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
|
||||
int hintTextResId) {
|
||||
dockAreaAlpha = areaAlpha;
|
||||
dockAreaOverlay = new ColorDrawable(0xFFffffff);
|
||||
dockAreaOverlay.setAlpha(0);
|
||||
hintTextAlpha = hintAlpha;
|
||||
hintTextOrientation = hintOrientation;
|
||||
mHintTextResId = hintTextResId;
|
||||
mHintTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mHintTextPaint.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view state with the given context.
|
||||
*/
|
||||
public void update(Context context) {
|
||||
Resources res = context.getResources();
|
||||
mHintText = context.getString(mHintTextResId);
|
||||
mHintTextPaint.setTextSize(res.getDimensionPixelSize(
|
||||
R.dimen.recents_drag_hint_text_size));
|
||||
mHintTextPaint.getTextBounds(mHintText, 0, mHintText.length(), mTmpRect);
|
||||
mHintTextBounds.set((int) mHintTextPaint.measureText(mHintText), mTmpRect.height());
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the current view state.
|
||||
*/
|
||||
public void draw(Canvas canvas) {
|
||||
// Draw the overlay background
|
||||
if (dockAreaOverlay.getAlpha() > 0) {
|
||||
dockAreaOverlay.draw(canvas);
|
||||
}
|
||||
|
||||
// Draw the hint text
|
||||
if (mHintTextAlpha > 0) {
|
||||
Rect bounds = dockAreaOverlay.getBounds();
|
||||
int x = bounds.left + (bounds.width() - mHintTextBounds.x) / 2;
|
||||
int y = bounds.top + (bounds.height() + mHintTextBounds.y) / 2;
|
||||
mHintTextPaint.setAlpha(mHintTextAlpha);
|
||||
if (hintTextOrientation == VERTICAL) {
|
||||
canvas.save();
|
||||
canvas.rotate(-90f, bounds.centerX(), bounds.centerY());
|
||||
}
|
||||
canvas.drawText(mHintText, x, y, mHintTextPaint);
|
||||
if (hintTextOrientation == VERTICAL) {
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bounds and alpha animation.
|
||||
*/
|
||||
public void startAnimation(Rect bounds, int alpha, int duration,
|
||||
public void startAnimation(Rect bounds, int areaAlpha, int hintAlpha, int duration,
|
||||
Interpolator interpolator, boolean animateAlpha, boolean animateBounds) {
|
||||
if (dockAreaOverlayAnimator != null) {
|
||||
dockAreaOverlayAnimator.cancel();
|
||||
if (mDockAreaOverlayAnimator != null) {
|
||||
mDockAreaOverlayAnimator.cancel();
|
||||
}
|
||||
|
||||
ArrayList<Animator> animators = new ArrayList<>();
|
||||
if (dockAreaOverlay.getAlpha() != alpha) {
|
||||
if (dockAreaOverlay.getAlpha() != areaAlpha) {
|
||||
if (animateAlpha) {
|
||||
animators.add(ObjectAnimator.ofInt(dockAreaOverlay,
|
||||
Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), alpha));
|
||||
Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha));
|
||||
} else {
|
||||
dockAreaOverlay.setAlpha(alpha);
|
||||
dockAreaOverlay.setAlpha(areaAlpha);
|
||||
}
|
||||
}
|
||||
if (mHintTextAlpha != hintAlpha) {
|
||||
if (animateAlpha) {
|
||||
animators.add(ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha,
|
||||
hintAlpha));
|
||||
} else {
|
||||
mHintTextAlpha = hintAlpha;
|
||||
dockAreaOverlay.invalidateSelf();
|
||||
}
|
||||
}
|
||||
if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
|
||||
@@ -307,11 +397,11 @@ public class TaskStack {
|
||||
}
|
||||
}
|
||||
if (!animators.isEmpty()) {
|
||||
dockAreaOverlayAnimator = new AnimatorSet();
|
||||
dockAreaOverlayAnimator.playTogether(animators);
|
||||
dockAreaOverlayAnimator.setDuration(duration);
|
||||
dockAreaOverlayAnimator.setInterpolator(interpolator);
|
||||
dockAreaOverlayAnimator.start();
|
||||
mDockAreaOverlayAnimator = new AnimatorSet();
|
||||
mDockAreaOverlayAnimator.playTogether(animators);
|
||||
mDockAreaOverlayAnimator.setDuration(duration);
|
||||
mDockAreaOverlayAnimator.setInterpolator(interpolator);
|
||||
mDockAreaOverlayAnimator.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,16 +421,25 @@ public class TaskStack {
|
||||
* the initial touch area. This is also the new dock area to
|
||||
* draw.
|
||||
*/
|
||||
DockState(int dockSide, int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea,
|
||||
DockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha,
|
||||
@TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea,
|
||||
RectF expandedTouchDockArea) {
|
||||
this.dockSide = dockSide;
|
||||
this.createMode = createMode;
|
||||
this.viewState = new ViewState(dockAreaAlpha);
|
||||
this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation,
|
||||
R.string.recents_drag_hint_message);
|
||||
this.dockArea = dockArea;
|
||||
this.touchArea = touchArea;
|
||||
this.expandedTouchDockArea = expandedTouchDockArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the dock state with the given context.
|
||||
*/
|
||||
public void update(Context context) {
|
||||
viewState.update(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether {@param x} and {@param y} are contained in the area scaled to the
|
||||
* given {@param width} and {@param height}.
|
||||
|
||||
@@ -426,10 +426,7 @@ public class RecentsView extends FrameLayout {
|
||||
|
||||
ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
|
||||
for (int i = visDockStates.size() - 1; i >= 0; i--) {
|
||||
Drawable d = visDockStates.get(i).viewState.dockAreaOverlay;
|
||||
if (d.getAlpha() > 0) {
|
||||
d.draw(canvas);
|
||||
}
|
||||
visDockStates.get(i).viewState.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +462,7 @@ public class RecentsView extends FrameLayout {
|
||||
public final void onBusEvent(DragStartEvent event) {
|
||||
updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
|
||||
true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
|
||||
TaskStack.DockState.NONE.viewState.hintTextAlpha,
|
||||
true /* animateAlpha */, false /* animateBounds */);
|
||||
}
|
||||
|
||||
@@ -472,11 +470,12 @@ public class RecentsView extends FrameLayout {
|
||||
if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
|
||||
updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
|
||||
true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
|
||||
TaskStack.DockState.NONE.viewState.hintTextAlpha,
|
||||
true /* animateAlpha */, true /* animateBounds */);
|
||||
} else {
|
||||
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
|
||||
updateVisibleDockRegions(new TaskStack.DockState[] {dockState},
|
||||
false /* isDefaultDockState */, -1, true /* animateAlpha */,
|
||||
false /* isDefaultDockState */, -1, -1, true /* animateAlpha */,
|
||||
true /* animateBounds */);
|
||||
}
|
||||
if (mStackActionButton != null) {
|
||||
@@ -498,13 +497,9 @@ public class RecentsView extends FrameLayout {
|
||||
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
|
||||
|
||||
// Hide the dock region
|
||||
updateVisibleDockRegions(null, false /* isDefaultDockState */, -1,
|
||||
updateVisibleDockRegions(null, false /* isDefaultDockState */, -1, -1,
|
||||
false /* animateAlpha */, false /* animateBounds */);
|
||||
|
||||
TaskStackLayoutAlgorithm stackLayout = mTaskStackView.getStackAlgorithm();
|
||||
TaskStackViewScroller stackScroller = mTaskStackView.getScroller();
|
||||
TaskViewTransform tmpTransform = new TaskViewTransform();
|
||||
|
||||
// We translated the view but we need to animate it back from the current layout-space
|
||||
// rect to its final layout-space rect
|
||||
int x = (int) event.taskView.getTranslationX();
|
||||
@@ -548,7 +543,7 @@ public class RecentsView extends FrameLayout {
|
||||
event.task.getTopComponent().flattenToShortString());
|
||||
} else {
|
||||
// Animate the overlay alpha back to 0
|
||||
updateVisibleDockRegions(null, true /* isDefaultDockState */, -1,
|
||||
updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1,
|
||||
true /* animateAlpha */, false /* animateBounds */);
|
||||
}
|
||||
}
|
||||
@@ -710,8 +705,8 @@ public class RecentsView extends FrameLayout {
|
||||
* Updates the dock region to match the specified dock state.
|
||||
*/
|
||||
private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates,
|
||||
boolean isDefaultDockState, int overrideAlpha, boolean animateAlpha,
|
||||
boolean animateBounds) {
|
||||
boolean isDefaultDockState, int overrideAreaAlpha, int overrideHintAlpha,
|
||||
boolean animateAlpha, boolean animateBounds) {
|
||||
ArraySet<TaskStack.DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates,
|
||||
new ArraySet<TaskStack.DockState>());
|
||||
ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
|
||||
@@ -720,11 +715,16 @@ public class RecentsView extends FrameLayout {
|
||||
TaskStack.DockState.ViewState viewState = dockState.viewState;
|
||||
if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
|
||||
// This is no longer visible, so hide it
|
||||
viewState.startAnimation(null, 0, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
|
||||
viewState.startAnimation(null, 0, 0, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
|
||||
Interpolators.ALPHA_OUT, animateAlpha, animateBounds);
|
||||
} else {
|
||||
// This state is now visible, update the bounds and show it
|
||||
int alpha = (overrideAlpha != -1 ? overrideAlpha : viewState.dockAreaAlpha);
|
||||
int areaAlpha = overrideAreaAlpha != -1
|
||||
? overrideAreaAlpha
|
||||
: viewState.dockAreaAlpha;
|
||||
int hintAlpha = overrideHintAlpha != -1
|
||||
? overrideHintAlpha
|
||||
: viewState.hintTextAlpha;
|
||||
Rect bounds = isDefaultDockState
|
||||
? dockState.getPreDockedBounds(getMeasuredWidth(), getMeasuredHeight())
|
||||
: dockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight(),
|
||||
|
||||
@@ -171,6 +171,7 @@ public class RecentsViewTouchHandler {
|
||||
TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
|
||||
for (TaskStack.DockState dockState : dockStates) {
|
||||
registerDropTargetForCurrentDrag(dockState);
|
||||
dockState.update(mRv.getContext());
|
||||
mVisibleDockStates.add(dockState);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user