5edf9e2923
- Change drawable to match specs, using ShadowDrawable to add shadow when necessary based on workspace theme. - New drawable is 18dp by 6dp; add support for different width vs height, and decouple from workspace page indicator (which is still 24dp tall). Bug: 151768994 Change-Id: Icfd0eac197ebc4d1f5bb799f8538c4bd99d800cd
296 lines
12 KiB
Java
296 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2018 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.quickstep.views;
|
|
|
|
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
|
|
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
|
import static com.android.launcher3.LauncherState.OVERVIEW;
|
|
import static com.android.launcher3.LauncherState.QUICK_SWITCH;
|
|
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
|
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
|
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
|
|
|
import android.content.Context;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Path;
|
|
import android.graphics.Path.Direction;
|
|
import android.graphics.Path.Op;
|
|
import android.graphics.Rect;
|
|
import android.util.AttributeSet;
|
|
import android.view.animation.Interpolator;
|
|
|
|
import com.android.launcher3.BaseQuickstepLauncher;
|
|
import com.android.launcher3.DeviceProfile;
|
|
import com.android.launcher3.LauncherState;
|
|
import com.android.launcher3.R;
|
|
import com.android.launcher3.Utilities;
|
|
import com.android.launcher3.anim.Interpolators;
|
|
import com.android.launcher3.config.FeatureFlags;
|
|
import com.android.launcher3.uioverrides.states.OverviewState;
|
|
import com.android.launcher3.util.Themes;
|
|
import com.android.launcher3.views.ScrimView;
|
|
import com.android.quickstep.SysUINavigationMode;
|
|
import com.android.quickstep.SysUINavigationMode.Mode;
|
|
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
|
|
import com.android.quickstep.util.LayoutUtils;
|
|
|
|
/**
|
|
* Scrim used for all-apps and shelf in Overview
|
|
* In transposed layout, it behaves as a simple color scrim.
|
|
* In portrait layout, it draws a rounded rect such that
|
|
* From normal state to overview state, the shelf just fades in and does not move
|
|
* From overview state to all-apps state the shelf moves up and fades in to cover the screen
|
|
*/
|
|
public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
|
|
implements NavigationModeChangeListener {
|
|
|
|
// If the progress is more than this, shelf follows the finger, otherwise it moves faster to
|
|
// cover the whole screen
|
|
private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f;
|
|
|
|
// Temporarily needed until android.R.attr.bottomDialogCornerRadius becomes public
|
|
private static final float BOTTOM_CORNER_RADIUS_RATIO = 2f;
|
|
|
|
// In transposed layout, we simply draw a flat color.
|
|
private boolean mDrawingFlatColor;
|
|
|
|
// For shelf mode
|
|
private final int mEndAlpha;
|
|
private final float mRadius;
|
|
private final int mMaxScrimAlpha;
|
|
private final Paint mPaint;
|
|
|
|
// Mid point where the alpha changes
|
|
private int mMidAlpha;
|
|
private float mMidProgress;
|
|
|
|
// The progress at which the drag handle starts moving up with the shelf.
|
|
private float mDragHandleProgress;
|
|
|
|
private Interpolator mBeforeMidProgressColorInterpolator = ACCEL;
|
|
private Interpolator mAfterMidProgressColorInterpolator = ACCEL;
|
|
|
|
private float mShiftRange;
|
|
|
|
private float mTopOffset;
|
|
private float mShelfTop;
|
|
private float mShelfTopAtThreshold;
|
|
|
|
private int mShelfColor;
|
|
private int mRemainingScreenColor;
|
|
|
|
private final Path mTempPath = new Path();
|
|
private final Path mRemainingScreenPath = new Path();
|
|
private boolean mRemainingScreenPathValid = false;
|
|
|
|
private Mode mSysUINavigationMode;
|
|
|
|
public ShelfScrimView(Context context, AttributeSet attrs) {
|
|
super(context, attrs);
|
|
mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255);
|
|
|
|
mEndAlpha = Color.alpha(mEndScrim);
|
|
mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
|
|
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
// Just assume the easiest UI for now, until we have the proper layout information.
|
|
mDrawingFlatColor = true;
|
|
}
|
|
|
|
@Override
|
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
|
super.onSizeChanged(w, h, oldw, oldh);
|
|
mRemainingScreenPathValid = false;
|
|
}
|
|
|
|
@Override
|
|
protected void onAttachedToWindow() {
|
|
super.onAttachedToWindow();
|
|
onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(getContext())
|
|
.addModeChangeListener(this));
|
|
}
|
|
|
|
@Override
|
|
protected void onDetachedFromWindow() {
|
|
super.onDetachedFromWindow();
|
|
SysUINavigationMode.INSTANCE.get(getContext()).removeModeChangeListener(this);
|
|
}
|
|
|
|
@Override
|
|
public void onNavigationModeChanged(Mode newMode) {
|
|
mSysUINavigationMode = newMode;
|
|
// Note that these interpolators are inverted because progress goes 1 to 0.
|
|
if (mSysUINavigationMode == Mode.NO_BUTTON) {
|
|
// Show the shelf more quickly before reaching overview progress.
|
|
mBeforeMidProgressColorInterpolator = ACCEL_2;
|
|
mAfterMidProgressColorInterpolator = ACCEL;
|
|
} else {
|
|
mBeforeMidProgressColorInterpolator = ACCEL;
|
|
mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void reInitUi() {
|
|
DeviceProfile dp = mLauncher.getDeviceProfile();
|
|
mDrawingFlatColor = dp.isVerticalBarLayout();
|
|
|
|
if (!mDrawingFlatColor) {
|
|
mRemainingScreenPathValid = false;
|
|
mShiftRange = mLauncher.getAllAppsController().getShiftRange();
|
|
|
|
Context context = getContext();
|
|
if ((OVERVIEW.getVisibleElements(mLauncher) & ALL_APPS_HEADER_EXTRA) == 0) {
|
|
mDragHandleProgress = 1;
|
|
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()
|
|
&& SysUINavigationMode.removeShelfFromOverview(context)) {
|
|
// Fade in all apps background quickly to distinguish from swiping from nav bar.
|
|
mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
|
|
mMidProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
|
|
} else {
|
|
mMidAlpha = 0;
|
|
mMidProgress = 1;
|
|
}
|
|
} else {
|
|
mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
|
|
mMidProgress = OVERVIEW.getVerticalProgress(mLauncher);
|
|
Rect hotseatPadding = dp.getHotseatLayoutPadding();
|
|
int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom
|
|
+ hotseatPadding.bottom + hotseatPadding.top;
|
|
float dragHandleTop =
|
|
Math.min(hotseatSize, LayoutUtils.getDefaultSwipeHeight(context, dp));
|
|
mDragHandleProgress = 1 - (dragHandleTop / mShiftRange);
|
|
}
|
|
mTopOffset = dp.getInsets().top - mDragHandleSize.y;
|
|
mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
|
|
}
|
|
updateColors();
|
|
updateDragHandleAlpha();
|
|
invalidate();
|
|
}
|
|
|
|
@Override
|
|
public void updateColors() {
|
|
super.updateColors();
|
|
mDragHandleOffset = 0;
|
|
if (mDrawingFlatColor) {
|
|
return;
|
|
}
|
|
|
|
if (mProgress < mDragHandleProgress) {
|
|
mDragHandleOffset = mShiftRange * (mDragHandleProgress - mProgress);
|
|
}
|
|
|
|
if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
|
|
mShelfTop = mShiftRange * mProgress + mTopOffset;
|
|
} else {
|
|
mShelfTop = Utilities.mapRange(mProgress / SCRIM_CATCHUP_THRESHOLD, -mRadius,
|
|
mShelfTopAtThreshold);
|
|
}
|
|
|
|
if (mProgress >= 1) {
|
|
mRemainingScreenColor = 0;
|
|
mShelfColor = 0;
|
|
LauncherState state = mLauncher.getStateManager().getState();
|
|
if (mSysUINavigationMode == Mode.NO_BUTTON
|
|
&& (state == BACKGROUND_APP || state == QUICK_SWITCH)
|
|
&& mLauncher.getShelfPeekAnim().isPeeking()) {
|
|
// Show the shelf background when peeking during swipe up.
|
|
mShelfColor = setColorAlphaBound(mEndScrim, mMidAlpha);
|
|
}
|
|
} else if (mProgress >= mMidProgress) {
|
|
mRemainingScreenColor = 0;
|
|
|
|
int alpha = Math.round(Utilities.mapToRange(
|
|
mProgress, mMidProgress, 1, mMidAlpha, 0, mBeforeMidProgressColorInterpolator));
|
|
mShelfColor = setColorAlphaBound(mEndScrim, alpha);
|
|
} else {
|
|
// Note that these ranges and interpolators are inverted because progress goes 1 to 0.
|
|
int alpha = Math.round(
|
|
Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha,
|
|
(float) mMidAlpha, mAfterMidProgressColorInterpolator));
|
|
mShelfColor = setColorAlphaBound(mEndScrim, alpha);
|
|
|
|
int remainingScrimAlpha = Math.round(
|
|
Utilities.mapToRange(mProgress, (float) 0, mMidProgress, mMaxScrimAlpha,
|
|
(float) 0, LINEAR));
|
|
mRemainingScreenColor = setColorAlphaBound(mScrimColor, remainingScrimAlpha);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean shouldDragHandleBeVisible() {
|
|
boolean twoZoneSwipeModel = FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()
|
|
&& SysUINavigationMode.removeShelfFromOverview(mLauncher);
|
|
return twoZoneSwipeModel || super.shouldDragHandleBeVisible();
|
|
}
|
|
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
drawBackground(canvas);
|
|
drawDragHandle(canvas);
|
|
}
|
|
|
|
private void drawBackground(Canvas canvas) {
|
|
if (mDrawingFlatColor) {
|
|
if (mCurrentFlatColor != 0) {
|
|
canvas.drawColor(mCurrentFlatColor);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (Color.alpha(mShelfColor) == 0) {
|
|
return;
|
|
} else if (mProgress <= 0) {
|
|
canvas.drawColor(mShelfColor);
|
|
return;
|
|
}
|
|
|
|
int height = getHeight();
|
|
int width = getWidth();
|
|
// Draw the scrim over the remaining screen if needed.
|
|
if (mRemainingScreenColor != 0) {
|
|
if (!mRemainingScreenPathValid) {
|
|
mTempPath.reset();
|
|
// Using a arbitrary '+10' in the bottom to avoid any left-overs at the
|
|
// corners due to rounding issues.
|
|
mTempPath.addRoundRect(0, height - mRadius, width, height + mRadius + 10,
|
|
mRadius, mRadius, Direction.CW);
|
|
mRemainingScreenPath.reset();
|
|
mRemainingScreenPath.addRect(0, 0, width, height, Direction.CW);
|
|
mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE);
|
|
}
|
|
|
|
float offset = height - mRadius - mShelfTop;
|
|
canvas.translate(0, -offset);
|
|
mPaint.setColor(mRemainingScreenColor);
|
|
canvas.drawPath(mRemainingScreenPath, mPaint);
|
|
canvas.translate(0, offset);
|
|
}
|
|
|
|
mPaint.setColor(mShelfColor);
|
|
canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
|
|
}
|
|
|
|
@Override
|
|
public float getVisualTop() {
|
|
return mShelfTop;
|
|
}
|
|
}
|