/*
|
* Copyright (C) 2015 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.allapps;
|
|
import android.animation.ObjectAnimator;
|
import android.content.Context;
|
import android.content.res.Resources;
|
import android.graphics.Canvas;
|
import android.graphics.ColorFilter;
|
import android.graphics.PixelFormat;
|
import android.graphics.Rect;
|
import android.graphics.drawable.Drawable;
|
import android.view.ContextThemeWrapper;
|
import android.view.Gravity;
|
|
import com.android.launcher3.LauncherAnimUtils;
|
import com.android.launcher3.R;
|
import com.android.launcher3.util.Themes;
|
|
/**
|
* This is a custom composite drawable that has a fixed virtual size and dynamically lays out its
|
* children images relatively within its bounds. This way, we can reduce the memory usage of a
|
* single, large sparsely populated image.
|
*/
|
public class AllAppsBackgroundDrawable extends Drawable {
|
|
/**
|
* A helper class to position and orient a drawable to be drawn.
|
*/
|
protected static class TransformedImageDrawable {
|
private Drawable mImage;
|
private float mXPercent;
|
private float mYPercent;
|
private int mGravity;
|
private int mAlpha;
|
|
/**
|
* @param gravity If one of the Gravity center values, the x and y offset will take the width
|
* and height of the image into account to center the image to the offset.
|
*/
|
public TransformedImageDrawable(Context context, int resourceId, float xPct, float yPct,
|
int gravity) {
|
mImage = context.getDrawable(resourceId);
|
mXPercent = xPct;
|
mYPercent = yPct;
|
mGravity = gravity;
|
}
|
|
public void setAlpha(int alpha) {
|
mImage.setAlpha(alpha);
|
mAlpha = alpha;
|
}
|
|
public int getAlpha() {
|
return mAlpha;
|
}
|
|
public void updateBounds(Rect bounds) {
|
int width = mImage.getIntrinsicWidth();
|
int height = mImage.getIntrinsicHeight();
|
int left = bounds.left + (int) (mXPercent * bounds.width());
|
int top = bounds.top + (int) (mYPercent * bounds.height());
|
if ((mGravity & Gravity.CENTER_HORIZONTAL) == Gravity.CENTER_HORIZONTAL) {
|
left -= (width / 2);
|
}
|
if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) {
|
top -= (height / 2);
|
}
|
mImage.setBounds(left, top, left + width, top + height);
|
}
|
|
public void draw(Canvas canvas) {
|
mImage.draw(canvas);
|
}
|
|
public Rect getBounds() {
|
return mImage.getBounds();
|
}
|
}
|
|
protected final TransformedImageDrawable mHand;
|
protected final TransformedImageDrawable[] mIcons;
|
private final int mWidth;
|
private final int mHeight;
|
|
private ObjectAnimator mBackgroundAnim;
|
|
public AllAppsBackgroundDrawable(Context context) {
|
Resources res = context.getResources();
|
mWidth = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_width);
|
mHeight = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_height);
|
|
context = new ContextThemeWrapper(context,
|
Themes.getAttrBoolean(context, R.attr.isMainColorDark)
|
? R.style.AllAppsEmptySearchBackground_Dark
|
: R.style.AllAppsEmptySearchBackground);
|
mHand = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_hand,
|
0.575f, 0.f, Gravity.CENTER_HORIZONTAL);
|
mIcons = new TransformedImageDrawable[4];
|
mIcons[0] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_1,
|
0.375f, 0, Gravity.CENTER_HORIZONTAL);
|
mIcons[1] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_2,
|
0.3125f, 0.2f, Gravity.CENTER_HORIZONTAL);
|
mIcons[2] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_3,
|
0.475f, 0.26f, Gravity.CENTER_HORIZONTAL);
|
mIcons[3] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_4,
|
0.7f, 0.125f, Gravity.CENTER_HORIZONTAL);
|
}
|
|
/**
|
* Animates the background alpha.
|
*/
|
public void animateBgAlpha(float finalAlpha, int duration) {
|
int finalAlphaI = (int) (finalAlpha * 255f);
|
if (getAlpha() != finalAlphaI) {
|
mBackgroundAnim = cancelAnimator(mBackgroundAnim);
|
mBackgroundAnim = ObjectAnimator.ofInt(this, LauncherAnimUtils.DRAWABLE_ALPHA,
|
finalAlphaI);
|
mBackgroundAnim.setDuration(duration);
|
mBackgroundAnim.start();
|
}
|
}
|
|
/**
|
* Sets the background alpha immediately.
|
*/
|
public void setBgAlpha(float finalAlpha) {
|
int finalAlphaI = (int) (finalAlpha * 255f);
|
if (getAlpha() != finalAlphaI) {
|
mBackgroundAnim = cancelAnimator(mBackgroundAnim);
|
setAlpha(finalAlphaI);
|
}
|
}
|
|
@Override
|
public int getIntrinsicWidth() {
|
return mWidth;
|
}
|
|
@Override
|
public int getIntrinsicHeight() {
|
return mHeight;
|
}
|
|
@Override
|
public void draw(Canvas canvas) {
|
mHand.draw(canvas);
|
for (int i = 0; i < mIcons.length; i++) {
|
mIcons[i].draw(canvas);
|
}
|
}
|
|
@Override
|
protected void onBoundsChange(Rect bounds) {
|
super.onBoundsChange(bounds);
|
mHand.updateBounds(bounds);
|
for (int i = 0; i < mIcons.length; i++) {
|
mIcons[i].updateBounds(bounds);
|
}
|
invalidateSelf();
|
}
|
|
@Override
|
public void setAlpha(int alpha) {
|
mHand.setAlpha(alpha);
|
for (int i = 0; i < mIcons.length; i++) {
|
mIcons[i].setAlpha(alpha);
|
}
|
invalidateSelf();
|
}
|
|
@Override
|
public int getAlpha() {
|
return mHand.getAlpha();
|
}
|
|
@Override
|
public void setColorFilter(ColorFilter colorFilter) {
|
// Do nothing
|
}
|
|
@Override
|
public int getOpacity() {
|
return PixelFormat.TRANSLUCENT;
|
}
|
|
private ObjectAnimator cancelAnimator(ObjectAnimator animator) {
|
if (animator != null) {
|
animator.cancel();
|
}
|
return null;
|
}
|
}
|