blob: 3830a9333dd9b75f0a668daf682ef65d03120305 [file] [log] [blame]
/*
* 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;
}
}