1fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson/* 2fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * Copyright (C) 2015 The Android Open Source Project 3fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * 4fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * Licensed under the Apache License, Version 2.0 (the "License"); 5fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * you may not use this file except in compliance with the License. 6fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * You may obtain a copy of the License at 7fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * 8fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * http://www.apache.org/licenses/LICENSE-2.0 9fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * 10fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * Unless required by applicable law or agreed to in writing, software 11fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * distributed under the License is distributed on an "AS IS" BASIS, 12fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * See the License for the specific language governing permissions and 14fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * limitations under the License. 15fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson */ 16fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonpackage com.android.launcher3.allapps; 17fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 18fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.animation.ObjectAnimator; 19fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.content.Context; 20fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.content.res.Resources; 21fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.graphics.Canvas; 22fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.graphics.ColorFilter; 23fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.graphics.PixelFormat; 24fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.graphics.Rect; 25fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.graphics.drawable.Drawable; 26fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 27fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.view.Gravity; 28fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport com.android.launcher3.R; 29fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 30fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson/** 31fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * A helper class to positon and orient a drawable to be drawn. 32fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson */ 33fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonclass TransformedImageDrawable { 34fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private Drawable mImage; 35fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private float mXPercent; 36fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private float mYPercent; 37fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private int mGravity; 38fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 39fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson /** 40fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * @param gravity If one of the Gravity center values, the x and y offset will take the width 41fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * and height of the image into account to center the image to the offset. 42fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson */ 43fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public TransformedImageDrawable(Resources res, int resourceId, float xPct, float yPct, 44fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int gravity) { 45fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mImage = res.getDrawable(resourceId); 46fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mXPercent = xPct; 47fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mYPercent = yPct; 48fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mGravity = gravity; 49fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 50fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 51fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void setAlpha(int alpha) { 52fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mImage.setAlpha(alpha); 53fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 54fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 55fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public int getAlpha() { 56fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson return mImage.getAlpha(); 57fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 58fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 59fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void updateBounds(Rect bounds) { 60fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int width = mImage.getIntrinsicWidth(); 61fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int height = mImage.getIntrinsicHeight(); 62fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int left = bounds.left + (int) (mXPercent * bounds.width()); 63fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int top = bounds.top + (int) (mYPercent * bounds.height()); 64fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson if ((mGravity & Gravity.CENTER_HORIZONTAL) == Gravity.CENTER_HORIZONTAL) { 65fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson left -= (width / 2); 66fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 67fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) { 68fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson top -= (height / 2); 69fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 70fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mImage.setBounds(left, top, left + width, top + height); 71fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 72fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 73fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void draw(Canvas canvas) { 74fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int c = canvas.save(Canvas.MATRIX_SAVE_FLAG); 75fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mImage.draw(canvas); 76fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson canvas.restoreToCount(c); 77fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 78fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson} 79fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 80fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson/** 81fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * This is a custom composite drawable that has a fixed virtual size and dynamically lays out its 82fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * children images relatively within its bounds. This way, we can reduce the memory usage of a 83fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * single, large sparsely populated image. 84fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson */ 85fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonpublic class AllAppsBackgroundDrawable extends Drawable { 86fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 87fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private final TransformedImageDrawable mHand; 88fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private final TransformedImageDrawable[] mIcons; 89fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private final int mWidth; 90fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private final int mHeight; 91fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 92fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private ObjectAnimator mBackgroundAnim; 93fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 94fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public AllAppsBackgroundDrawable(Context context) { 95fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson Resources res = context.getResources(); 96fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mHand = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_hand, 97fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 0.575f, 0.1f, Gravity.CENTER_HORIZONTAL); 98fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons = new TransformedImageDrawable[4]; 99fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons[0] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_1, 100fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 0.375f, 0, Gravity.CENTER_HORIZONTAL); 101fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons[1] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_2, 102fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 0.3125f, 0.25f, Gravity.CENTER_HORIZONTAL); 103fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons[2] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_3, 104fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 0.475f, 0.4f, Gravity.CENTER_HORIZONTAL); 105fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons[3] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_4, 106fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 0.7f, 0.125f, Gravity.CENTER_HORIZONTAL); 107fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mWidth = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_width); 108fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mHeight = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_height); 109fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 110fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 111fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson /** 112fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * Animates the background alpha. 113fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson */ 114fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void animateBgAlpha(float finalAlpha, int duration) { 115fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int finalAlphaI = (int) (finalAlpha * 255f); 116fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson if (getAlpha() != finalAlphaI) { 117fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mBackgroundAnim = cancelAnimator(mBackgroundAnim); 118fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mBackgroundAnim = ObjectAnimator.ofInt(this, "alpha", finalAlphaI); 119fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mBackgroundAnim.setDuration(duration); 120fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mBackgroundAnim.start(); 121fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 122fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 123fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 124fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson /** 125fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson * Sets the background alpha immediately. 126fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson */ 127fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void setBgAlpha(float finalAlpha) { 128fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson int finalAlphaI = (int) (finalAlpha * 255f); 129fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson if (getAlpha() != finalAlphaI) { 130fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mBackgroundAnim = cancelAnimator(mBackgroundAnim); 131fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson setAlpha(finalAlphaI); 132fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 133fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 134fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 135fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 136fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public int getIntrinsicWidth() { 137fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson return mWidth; 138fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 139fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 140fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 141fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public int getIntrinsicHeight() { 142fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson return mHeight; 143fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 144fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 145fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 146fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void draw(Canvas canvas) { 147fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mHand.draw(canvas); 148fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson for (int i = 0; i < mIcons.length; i++) { 149fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons[i].draw(canvas); 150fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 151fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 152fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 153fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 154fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson protected void onBoundsChange(Rect bounds) { 155fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson super.onBoundsChange(bounds); 156fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mHand.updateBounds(bounds); 157fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson for (int i = 0; i < mIcons.length; i++) { 158fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons[i].updateBounds(bounds); 159fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 160fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson invalidateSelf(); 161fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 162fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 163fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 164fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void setAlpha(int alpha) { 165fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mHand.setAlpha(alpha); 166fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson for (int i = 0; i < mIcons.length; i++) { 167fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson mIcons[i].setAlpha(alpha); 168fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 169fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson invalidateSelf(); 170fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 171fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 172fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 173fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public int getAlpha() { 174fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson return mHand.getAlpha(); 175fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 176fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 177fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 178fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public void setColorFilter(ColorFilter colorFilter) { 179fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson // Do nothing 180fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 181fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 182fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson @Override 183fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson public int getOpacity() { 184fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson return PixelFormat.TRANSLUCENT; 185fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 186fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson 187fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson private ObjectAnimator cancelAnimator(ObjectAnimator animator) { 188fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson if (animator != null) { 189fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson animator.removeAllListeners(); 190fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson animator.cancel(); 191fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 192fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson return null; 193fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson } 194fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson} 195