Merge "All Apps transition with gradient and scrim." into ub-launcher3-dorval-polish

This commit is contained in:
Mario Bertschler
2017-05-03 18:04:10 +00:00
committed by Android (Google) Code Review
15 changed files with 400 additions and 10 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+2
View File
@@ -32,6 +32,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/gradient_scrim" />
<!-- The workspace contains 5 screens of cells -->
<!-- DO NOT CHANGE THE ID -->
<com.android.launcher3.Workspace
+2
View File
@@ -33,6 +33,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/gradient_scrim" />
<!-- The workspace contains 5 screens of cells -->
<!-- DO NOT CHANGE THE ID -->
<com.android.launcher3.Workspace
+2
View File
@@ -32,6 +32,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/gradient_scrim" />
<!-- The workspace contains 5 screens of cells -->
<!-- DO NOT CHANGE THE ID -->
<com.android.launcher3.Workspace
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.android.launcher3.graphics.RadialGradientView
android:id="@+id/gradient_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
app:layout_ignoreInsets="true"/>
<com.android.launcher3.graphics.ScrimView
android:id="@+id/scrim_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
app:layout_ignoreInsets="true"/>
</merge>
+7 -1
View File
@@ -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) {
+3 -1
View File
@@ -466,7 +466,9 @@ public class Launcher extends BaseActivity
@Override
public void onExtractedColorsChanged() {
loadExtractedColorsAndColorItems();
if (mAllAppsController != null) {
mAllAppsController.onExtractedColorsChanged();
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onExtractedColorsChanged();
}
+25
View File
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
@@ -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);
}
}
}
@@ -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]));
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -38,6 +38,8 @@ public final class FeatureFlags {
public static boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = true;
// When enabled the promise icon is visible in all apps while installation an app.
public static boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = true;
// When enabled uses the AllAppsRadialGradientAndScrimDrawable for all apps
public static boolean LAUNCHER3_GRADIENT_ALL_APPS = false;
// Feature flag to enable moving the QSB on the 0th screen of the workspace.
public static final boolean QSB_ON_FIRST_SCREEN = true;