| /* |
| * 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; |
| } |
| } |