summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3
diff options
context:
space:
mode:
authorMario Bertschler <bmario@google.com>2017-01-30 17:05:24 -0800
committerMario Bertschler <bmario@google.com>2017-05-03 10:32:57 -0700
commit48198d004af64d0d7c8b86bc243087f68dc374c9 (patch)
tree503173ab33803b465990dff9ed62a8731d5f7e80 /src/com/android/launcher3
parent2526ba8215976432806c69c468f7b556e7877513 (diff)
downloadandroid_packages_apps_Trebuchet-48198d004af64d0d7c8b86bc243087f68dc374c9.tar.gz
android_packages_apps_Trebuchet-48198d004af64d0d7c8b86bc243087f68dc374c9.tar.bz2
android_packages_apps_Trebuchet-48198d004af64d0d7c8b86bc243087f68dc374c9.zip
All Apps transition with gradient and scrim.
The transition is behind a feature flag and turned off by default. Change-Id: I155840ba82b5a573d874376797db5f739a52d706
Diffstat (limited to 'src/com/android/launcher3')
-rw-r--r--src/com/android/launcher3/Hotseat.java8
-rw-r--r--src/com/android/launcher3/Launcher.java4
-rw-r--r--src/com/android/launcher3/Utilities.java25
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java3
-rw-r--r--src/com/android/launcher3/allapps/AllAppsTransitionController.java47
-rw-r--r--src/com/android/launcher3/dynamicui/ColorExtractionService.java13
-rw-r--r--src/com/android/launcher3/dynamicui/ExtractedColors.java28
-rw-r--r--src/com/android/launcher3/graphics/RadialGradientView.java146
-rw-r--r--src/com/android/launcher3/graphics/ScrimView.java97
9 files changed, 361 insertions, 10 deletions
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 128d95603..ab82c988e 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -72,7 +72,9 @@ public class Hotseat extends FrameLayout
mBackgroundColor = ColorUtils.setAlphaComponent(
Themes.getAttrColor(context, android.R.attr.colorPrimary), 0);
mBackground = new ColorDrawable(mBackgroundColor);
- setBackground(mBackground);
+ if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ setBackground(mBackground);
+ }
}
public CellLayout getLayout() {
@@ -179,6 +181,10 @@ public class Hotseat extends FrameLayout
}
public void updateColor(ExtractedColors extractedColors, boolean animate) {
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ // not hotseat visible
+ return;
+ }
if (!mHasVerticalHotseat) {
int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX);
if (mBackgroundColorAnimator != null) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 90dc2ef3f..756a85360 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -466,7 +466,9 @@ public class Launcher extends BaseActivity
@Override
public void onExtractedColorsChanged() {
loadExtractedColorsAndColorItems();
-
+ if (mAllAppsController != null) {
+ mAllAppsController.onExtractedColorsChanged();
+ }
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onExtractedColorsChanged();
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 776ec2f62..54e7dd2bc 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -28,6 +28,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -645,4 +646,28 @@ public final class Utilities {
hashSet.add(elem);
return hashSet;
}
+
+ /**
+ * @return creates a new alpha mask bitmap out of an existing bitmap
+ */
+ public static Bitmap convertToAlphaMask(Bitmap b, float applyAlpha) {
+ Bitmap a = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ALPHA_8);
+ Canvas c = new Canvas(a);
+ Paint paint = new Paint();
+ paint.setAlpha((int) (255f * applyAlpha));
+ c.drawBitmap(b, 0f, 0f, paint);
+ return a;
+ }
+
+ /**
+ * @return a new white 1x1 bitmap with ALPHA_8
+ */
+ public static Bitmap createOnePixBitmap() {
+ Bitmap a = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+ Canvas c = new Canvas(a);
+ Paint paint = new Paint();
+ paint.setColor(Color.WHITE);
+ c.drawPaint(paint);
+ return a;
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index af6763107..7be8e8f0e 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -492,7 +492,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
ViewGroup.LayoutParams navBarBgLp = navBarBg.getLayoutParams();
navBarBgLp.height = insets.bottom;
navBarBg.setLayoutParams(navBarBgLp);
- navBarBg.setVisibility(View.VISIBLE);
+ navBarBg.setVisibility(FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS
+ ? View.INVISIBLE : View.VISIBLE);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 30ed180e7..121ce4ce1 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -22,6 +22,10 @@ import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dynamicui.ExtractedColors;
+import com.android.launcher3.graphics.RadialGradientView;
+import com.android.launcher3.graphics.ScrimView;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.Themes;
@@ -91,6 +95,8 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
// Used in discovery bounce animation to provide the transition without workspace changing.
private boolean mIsTranslateWithoutWorkspace = false;
private AnimatorSet mDiscoBounceAnimation;
+ private RadialGradientView mGradientView;
+ private ScrimView mScrimView;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
@@ -247,7 +253,9 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
if (!mLauncher.isAllAppsVisible()) {
mLauncher.tryAndUpdatePredictedApps();
mAppsView.setVisibility(View.VISIBLE);
- mAppsView.setRevealDrawableColor(mHotseatBackgroundColor);
+ if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ mAppsView.setRevealDrawableColor(mHotseatBackgroundColor);
+ }
}
}
}
@@ -263,6 +271,36 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
mLauncher.activateLightSystemBars(forceLight, true /* statusBar */, true /* navBar */);
}
+ private void updateAllAppsBg(float progress) {
+ // gradient
+ if (mGradientView == null) {
+ mGradientView = (RadialGradientView) mLauncher.findViewById(R.id.gradient_bg);
+ mGradientView.setVisibility(View.VISIBLE);
+ onExtractedColorsChanged();
+ }
+ mGradientView.setProgress(progress);
+
+ // scrim
+ if (mScrimView == null) {
+ mScrimView = (ScrimView) mLauncher.findViewById(R.id.scrim_bg);
+ mScrimView.setVisibility(View.VISIBLE);
+ }
+ mScrimView.setProgress(progress);
+ }
+
+ public void onExtractedColorsChanged() {
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ if (mGradientView != null) {
+ int color1 = mLauncher.getExtractedColors()
+ .getColor(ExtractedColors.ALLAPPS_GRADIENT_MAIN_INDEX);
+ int color2 = mLauncher.getExtractedColors()
+ .getColor(ExtractedColors.ALLAPPS_GRADIENT_SECONDARY_INDEX);
+ mGradientView.onExtractedColorsChanged(color1, color2);
+ mGradientView.requestLayout();
+ }
+ }
+ }
+
/**
* @param progress value between 0 and 1, 0 shows all apps and 1 shows workspace
*/
@@ -280,7 +318,12 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
int bgAlpha = Color.alpha((int) mEvaluator.evaluate(alpha,
mHotseatBackgroundColor, mAllAppsBackgroundColor));
- mAppsView.setRevealDrawableColor(ColorUtils.setAlphaComponent(color, bgAlpha));
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ updateAllAppsBg(alpha);
+ } else {
+ mAppsView.setRevealDrawableColor(ColorUtils.setAlphaComponent(color, bgAlpha));
+ }
+
mAppsView.getContentView().setAlpha(alpha);
mAppsView.setTranslationY(shiftCurrent);
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
index 9379a7285..f6b02aa9c 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionService.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
@@ -63,8 +63,11 @@ public class ColorExtractionService extends IntentService {
// We can't extract colors from live wallpapers, so just use the default color always.
extractedColors.updateHotseatPalette(null);
- if (FeatureFlags.QSB_IN_HOTSEAT) {
+ if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
extractedColors.updateWallpaperThemePalette(null);
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ extractedColors.updateAllAppsGradientPalette(null);
+ }
}
} else {
// We extract colors for the hotseat and status bar separately,
@@ -75,8 +78,12 @@ public class ColorExtractionService extends IntentService {
extractedColors.updateStatusBarPalette(getStatusBarPalette());
}
- if (FeatureFlags.QSB_IN_HOTSEAT) {
- extractedColors.updateWallpaperThemePalette(getWallpaperPalette());
+ if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ Palette wallpaperPalette = getWallpaperPalette();
+ extractedColors.updateWallpaperThemePalette(wallpaperPalette);
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ extractedColors.updateAllAppsGradientPalette(wallpaperPalette);
+ }
}
}
diff --git a/src/com/android/launcher3/dynamicui/ExtractedColors.java b/src/com/android/launcher3/dynamicui/ExtractedColors.java
index 2e52a0b8c..3c4aba130 100644
--- a/src/com/android/launcher3/dynamicui/ExtractedColors.java
+++ b/src/com/android/launcher3/dynamicui/ExtractedColors.java
@@ -18,6 +18,7 @@ package com.android.launcher3.dynamicui;
import android.content.Context;
import android.graphics.Color;
+import android.support.annotation.Nullable;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.graphics.Palette;
import android.util.Log;
@@ -42,12 +43,24 @@ public class ExtractedColors {
public static final int HOTSEAT_INDEX = 1;
public static final int STATUS_BAR_INDEX = 2;
public static final int WALLPAPER_VIBRANT_INDEX = 3;
+ public static final int ALLAPPS_GRADIENT_MAIN_INDEX = 4;
+ public static final int ALLAPPS_GRADIENT_SECONDARY_INDEX = 5;
private static final int VERSION;
private static final int[] DEFAULT_VALUES;
static {
- if (FeatureFlags.QSB_IN_HOTSEAT) {
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ VERSION = 3;
+ DEFAULT_VALUES = new int[] {
+ VERSION, // VERSION_INDEX
+ 0x40FFFFFF, // HOTSEAT_INDEX: White with 25% alpha
+ DEFAULT_DARK, // STATUS_BAR_INDEX
+ 0xFFCCCCCC, // WALLPAPER_VIBRANT_INDEX
+ 0xFF000000, // ALLAPPS_GRADIENT_MAIN_INDEX
+ 0xFF000000 // ALLAPPS_GRADIENT_SECONDARY_INDEX
+ };
+ } else if (FeatureFlags.QSB_IN_HOTSEAT) {
VERSION = 2;
DEFAULT_VALUES = new int[] {
VERSION, // VERSION_INDEX
@@ -142,9 +155,20 @@ public class ExtractedColors {
DEFAULT_LIGHT : DEFAULT_DARK);
}
- public void updateWallpaperThemePalette(Palette wallpaperPalette) {
+ public void updateWallpaperThemePalette(@Nullable Palette wallpaperPalette) {
int defaultColor = DEFAULT_VALUES[WALLPAPER_VIBRANT_INDEX];
setColorAtIndex(WALLPAPER_VIBRANT_INDEX, wallpaperPalette == null
? defaultColor : wallpaperPalette.getVibrantColor(defaultColor));
}
+
+ public void updateAllAppsGradientPalette(@Nullable Palette wallpaperPalette) {
+ // TODO b/37089857 will be modified to take the system extracted colors into account
+ int idx;
+ idx = ALLAPPS_GRADIENT_MAIN_INDEX;
+ setColorAtIndex(idx, wallpaperPalette == null
+ ? DEFAULT_VALUES[idx] : wallpaperPalette.getDarkVibrantColor(DEFAULT_VALUES[idx]));
+ idx = ALLAPPS_GRADIENT_SECONDARY_INDEX;
+ setColorAtIndex(idx, wallpaperPalette == null
+ ? DEFAULT_VALUES[idx] : wallpaperPalette.getVibrantColor(DEFAULT_VALUES[idx]));
+ }
}
diff --git a/src/com/android/launcher3/graphics/RadialGradientView.java b/src/com/android/launcher3/graphics/RadialGradientView.java
new file mode 100644
index 000000000..cf6851c00
--- /dev/null
+++ b/src/com/android/launcher3/graphics/RadialGradientView.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 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.launcher3.graphics;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+/**
+ * Draws a translucent radial gradient background from an initial state with progress 0.0 to a
+ * final state with progress 1.0;
+ */
+public class RadialGradientView extends View {
+
+ public static final int DEFAULT_COLOR_1 = Color.WHITE;
+ public static final int DEFAULT_COLOR_2 = Color.BLACK;
+
+ private static Bitmap sFinalGradientMask;
+ private static Bitmap sAlphaGradientMask;
+
+ // TODO needs to be cleaned up once design finalizes
+ static class Config {
+ // dimens
+ final float gradientCenterX = 0.5f;
+ final float gradientCenterY = 1.05f;
+ final float gradientHeadStartFactor = 0.35f;
+ final float gradientAlphaMaskLengthDp = 700;
+ // interpolation
+ final boolean useGradientAlphaDecel = false;
+ final float decelFactorForGradientAlpha = 2f;
+ // colors
+ final float finalGradientAlpha = 0.75f;
+ int color1 = DEFAULT_COLOR_1;
+ int color2 = DEFAULT_COLOR_2;
+ }
+
+ private final RectF mAlphaMaskRect = new RectF();
+ private final RectF mFinalMaskRect = new RectF();
+ private final Paint mPaint = new Paint();
+ private final Config mConfig = new Config();
+ private final DecelerateInterpolator mDecelInterpolator;
+ private float mProgress;
+ private int mWidth;
+ private int mHeight;
+ private final int mMaskHeight;
+ private final Context mAppContext;
+
+ public RadialGradientView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ this.mAppContext = context.getApplicationContext();
+ this.mDecelInterpolator = new DecelerateInterpolator(mConfig.decelFactorForGradientAlpha);
+ this.mMaskHeight = Utilities.pxFromDp(mConfig.gradientAlphaMaskLengthDp,
+ mAppContext.getResources().getDisplayMetrics());
+
+ if (sFinalGradientMask == null) {
+ sFinalGradientMask = Utilities.convertToAlphaMask(
+ Utilities.createOnePixBitmap(), mConfig.finalGradientAlpha);
+ }
+ if (sAlphaGradientMask == null) {
+ Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(context.getResources(),
+ R.drawable.all_apps_alpha_mask);
+ sAlphaGradientMask = Utilities.convertToAlphaMask(
+ alphaMaskFromResource, mConfig.finalGradientAlpha);
+ }
+ }
+
+ public void onExtractedColorsChanged(int color1, int color2) {
+ mConfig.color1 = color1;
+ mConfig.color2 = color2;
+ if (mWidth + mHeight > 0) {
+ createRadialShader();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ this.mWidth = getMeasuredWidth();
+ this.mHeight = getMeasuredHeight();
+ if (mWidth + mHeight > 0) {
+ createRadialShader();
+ }
+ }
+
+ // only being called when colors change
+ private void createRadialShader() {
+ float radius = Math.max(mHeight, mWidth) * mConfig.gradientCenterY;
+
+ float posScreenBottom = (radius - mHeight) / radius; // center lives below screen
+ RadialGradient shader = new RadialGradient(
+ mWidth * mConfig.gradientCenterX,
+ mHeight * mConfig.gradientCenterY,
+ radius,
+ new int[] {mConfig.color1, mConfig.color1, mConfig.color2},
+ new float[] {0f, posScreenBottom, 1f},
+ Shader.TileMode.CLAMP);
+ mPaint.setShader(shader);
+ }
+
+ public void setProgress(float progress) {
+ this.mProgress = progress;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ float head = mConfig.gradientHeadStartFactor;
+ float linearProgress = head + (mProgress * (1f - head));
+ float adjustProgress = mConfig.useGradientAlphaDecel
+ ? mDecelInterpolator.getInterpolation(linearProgress)
+ : linearProgress;
+ float startMaskY = (1f - adjustProgress) * mHeight - mMaskHeight * adjustProgress;
+
+ mAlphaMaskRect.set(0, startMaskY, mWidth, startMaskY + mMaskHeight);
+ mFinalMaskRect.set(0, startMaskY + mMaskHeight, mWidth, mHeight);
+ canvas.drawBitmap(sAlphaGradientMask, null, mAlphaMaskRect, mPaint);
+ canvas.drawBitmap(sFinalGradientMask, null, mFinalMaskRect, mPaint);
+ }
+
+} \ No newline at end of file
diff --git a/src/com/android/launcher3/graphics/ScrimView.java b/src/com/android/launcher3/graphics/ScrimView.java
new file mode 100644
index 000000000..521fbedd6
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ScrimView.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 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.launcher3.graphics;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.support.v4.graphics.ColorUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+public class ScrimView extends View {
+
+ // Config
+ private static final int MASK_HEIGHT_DP = 600;
+ private static final float MASK_START_LENGTH_FACTOR = 0.4f;
+ private static final float FINAL_ALPHA = 0.87f;
+ private static final int SCRIM_COLOR = ColorUtils.setAlphaComponent(
+ Color.WHITE, (int) (FINAL_ALPHA * 255));
+
+ private static Bitmap sFinalScrimMask;
+ private static Bitmap sAlphaScrimMask;
+
+ private final int mMaskHeight;
+ private int mVisibleHeight;
+ private final int mHeadStart;
+
+ private final RectF mAlphaMaskRect = new RectF();
+ private final RectF mFinalMaskRect = new RectF();
+ private final Paint mPaint = new Paint();
+ private float mProgress;
+
+ public ScrimView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mMaskHeight = Utilities.pxFromDp(MASK_HEIGHT_DP, getResources().getDisplayMetrics());
+ mHeadStart = (int) (mMaskHeight * MASK_START_LENGTH_FACTOR);
+ mPaint.setColor(SCRIM_COLOR);
+
+ if (sFinalScrimMask == null) {
+ sFinalScrimMask = Utilities.convertToAlphaMask(
+ Utilities.createOnePixBitmap(), FINAL_ALPHA);
+ }
+ if (sAlphaScrimMask == null) {
+ Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(getResources(),
+ R.drawable.all_apps_alpha_mask);
+ sAlphaScrimMask = Utilities.convertToAlphaMask(alphaMaskFromResource, FINAL_ALPHA);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ mVisibleHeight = MeasureSpec.getSize(heightMeasureSpec);
+ int fullHeight = mVisibleHeight * 2 + mMaskHeight;
+ setMeasuredDimension(width, fullHeight);
+ setProgress(mProgress);
+ }
+
+ public void setProgress(float progress) {
+ mProgress = progress;
+ float initialY = mVisibleHeight - mHeadStart;
+ float fullTranslationY = mMaskHeight + initialY + mVisibleHeight;
+ float translationY = initialY - progress * fullTranslationY;
+ setTranslationY(translationY);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ mAlphaMaskRect.set(0, 0, getWidth(), mMaskHeight);
+ mFinalMaskRect.set(0, mMaskHeight, getWidth(), getHeight());
+ canvas.drawBitmap(sAlphaScrimMask, null, mAlphaMaskRect, mPaint);
+ canvas.drawBitmap(sFinalScrimMask, null, mFinalMaskRect, mPaint);
+ }
+
+}