Home | History | Annotate | Download | only in views
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.quickstep.views;
     17 
     18 import static android.support.v4.graphics.ColorUtils.compositeColors;
     19 import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
     20 
     21 import static com.android.launcher3.LauncherState.OVERVIEW;
     22 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
     23 
     24 import android.content.Context;
     25 import android.graphics.Canvas;
     26 import android.graphics.Color;
     27 import android.graphics.Paint;
     28 import android.graphics.Path;
     29 import android.graphics.Path.Direction;
     30 import android.graphics.Path.Op;
     31 import android.util.AttributeSet;
     32 
     33 import com.android.launcher3.DeviceProfile;
     34 import com.android.launcher3.R;
     35 import com.android.launcher3.uioverrides.OverviewState;
     36 import com.android.launcher3.util.Themes;
     37 import com.android.launcher3.views.ScrimView;
     38 
     39 /**
     40  * Scrim used for all-apps and shelf in Overview
     41  * In transposed layout, it behaves as a simple color scrim.
     42  * In portrait layout, it draws a rounded rect such that
     43  *    From normal state to overview state, the shelf just fades in and does not move
     44  *    From overview state to all-apps state the shelf moves up and fades in to cover the screen
     45  */
     46 public class ShelfScrimView extends ScrimView {
     47 
     48     // In transposed layout, we simply draw a flat color.
     49     private boolean mDrawingFlatColor;
     50 
     51     // For shelf mode
     52     private final int mEndAlpha;
     53     private final int mThresholdAlpha;
     54     private final float mRadius;
     55     private final float mMaxScrimAlpha;
     56     private final Paint mPaint;
     57 
     58     // Max vertical progress after which the scrim stops moving.
     59     private float mMoveThreshold;
     60     // Minimum visible size of the scrim.
     61     private int mMinSize;
     62 
     63     private float mScrimMoveFactor = 0;
     64     private int mShelfColor;
     65     private int mRemainingScreenColor;
     66 
     67     private final Path mTempPath = new Path();
     68     private final Path mRemainingScreenPath = new Path();
     69     private boolean mRemainingScreenPathValid = false;
     70 
     71     public ShelfScrimView(Context context, AttributeSet attrs) {
     72         super(context, attrs);
     73         mMaxScrimAlpha = OVERVIEW.getWorkspaceScrimAlpha(mLauncher);
     74 
     75         mEndAlpha = Color.alpha(mEndScrim);
     76         mThresholdAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
     77         mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius);
     78         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     79 
     80         // Just assume the easiest UI for now, until we have the proper layout information.
     81         mDrawingFlatColor = true;
     82     }
     83 
     84     @Override
     85     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     86         super.onSizeChanged(w, h, oldw, oldh);
     87         mRemainingScreenPathValid = false;
     88     }
     89 
     90     @Override
     91     public void reInitUi() {
     92         DeviceProfile dp = mLauncher.getDeviceProfile();
     93         mDrawingFlatColor = dp.isVerticalBarLayout();
     94 
     95         if (!mDrawingFlatColor) {
     96             float swipeLength = OverviewState.getDefaultSwipeHeight(mLauncher);
     97             mMoveThreshold = 1 - swipeLength / mLauncher.getAllAppsController().getShiftRange();
     98             mMinSize = dp.hotseatBarSizePx + dp.getInsets().bottom;
     99             mRemainingScreenPathValid = false;
    100             updateColors();
    101         }
    102         updateDragHandleAlpha();
    103         invalidate();
    104     }
    105 
    106     @Override
    107     public void updateColors() {
    108         super.updateColors();
    109         if (mDrawingFlatColor) {
    110             return;
    111         }
    112 
    113         if (mProgress >= mMoveThreshold) {
    114             mScrimMoveFactor = 1;
    115 
    116             if (mProgress >= 1) {
    117                 mShelfColor = 0;
    118             } else {
    119                 int alpha = Math.round(mThresholdAlpha * ACCEL_2.getInterpolation(
    120                         (1 - mProgress) / (1 - mMoveThreshold)));
    121                 mShelfColor = setAlphaComponent(mEndScrim, alpha);
    122             }
    123 
    124             mRemainingScreenColor = 0;
    125         } else if (mProgress <= 0) {
    126             mScrimMoveFactor = 0;
    127             mShelfColor = mCurrentFlatColor;
    128             mRemainingScreenColor = 0;
    129 
    130         } else {
    131             mScrimMoveFactor = mProgress / mMoveThreshold;
    132             mRemainingScreenColor = setAlphaComponent(mScrimColor,
    133                     Math.round((1 - mScrimMoveFactor) * mMaxScrimAlpha * 255));
    134 
    135             // Merge the remainingScreenColor and shelfColor in one to avoid overdraw.
    136             int alpha = mEndAlpha - Math.round((mEndAlpha - mThresholdAlpha) * mScrimMoveFactor);
    137             mShelfColor = compositeColors(setAlphaComponent(mEndScrim, alpha),
    138                     mRemainingScreenColor);
    139         }
    140     }
    141 
    142     @Override
    143     protected void onDraw(Canvas canvas) {
    144         float translate = drawBackground(canvas);
    145 
    146         if (mDragHandle != null) {
    147             canvas.translate(0, -translate);
    148             mDragHandle.draw(canvas);
    149             canvas.translate(0, translate);
    150         }
    151     }
    152 
    153     private float drawBackground(Canvas canvas) {
    154         if (mDrawingFlatColor) {
    155             if (mCurrentFlatColor != 0) {
    156                 canvas.drawColor(mCurrentFlatColor);
    157             }
    158             return 0;
    159         }
    160 
    161         if (mShelfColor == 0) {
    162             return 0;
    163         } else if (mScrimMoveFactor <= 0) {
    164             canvas.drawColor(mShelfColor);
    165             return getHeight();
    166         }
    167 
    168         float minTop = getHeight() - mMinSize;
    169         float top = minTop * mScrimMoveFactor - mDragHandleSize;
    170 
    171         // Draw the scrim over the remaining screen if needed.
    172         if (mRemainingScreenColor != 0) {
    173             if (!mRemainingScreenPathValid) {
    174                 mTempPath.reset();
    175                 // Using a arbitrary '+10' in the bottom to avoid any left-overs at the
    176                 // corners due to rounding issues.
    177                 mTempPath.addRoundRect(0, minTop, getWidth(), getHeight() + mRadius + 10,
    178                         mRadius, mRadius, Direction.CW);
    179 
    180                 mRemainingScreenPath.reset();
    181                 mRemainingScreenPath.addRect(0, 0, getWidth(), getHeight(), Direction.CW);
    182                 mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE);
    183             }
    184 
    185             float offset = minTop - top;
    186             canvas.translate(0, -offset);
    187             mPaint.setColor(mRemainingScreenColor);
    188             canvas.drawPath(mRemainingScreenPath, mPaint);
    189             canvas.translate(0, offset);
    190         }
    191 
    192         mPaint.setColor(mShelfColor);
    193         canvas.drawRoundRect(0, top, getWidth(), getHeight() + mRadius,
    194                 mRadius, mRadius, mPaint);
    195         return minTop - mDragHandleSize - top;
    196     }
    197 }
    198