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;
265931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyalimport android.view.ContextThemeWrapper;
27fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport android.view.Gravity;
28260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal
292d89ea84530559e2002a3a4009a50bac1e568507Jon Mirandaimport com.android.launcher3.LauncherAnimUtils;
30fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winsonimport com.android.launcher3.R;
315931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyalimport com.android.launcher3.util.Themes;
32fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
33fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson/**
34260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal * This is a custom composite drawable that has a fixed virtual size and dynamically lays out its
35260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal * children images relatively within its bounds.  This way, we can reduce the memory usage of a
36260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal * single, large sparsely populated image.
37fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson */
38260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyalpublic class AllAppsBackgroundDrawable extends Drawable {
39fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
40fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    /**
415931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal     * A helper class to position and orient a drawable to be drawn.
42fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson     */
43260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal    protected static class TransformedImageDrawable {
44260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        private Drawable mImage;
45260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        private float mXPercent;
46260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        private float mYPercent;
47260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        private int mGravity;
48260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        private int mAlpha;
49fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
50260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        /**
51260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal         * @param gravity If one of the Gravity center values, the x and y offset will take the width
52260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal         *                and height of the image into account to center the image to the offset.
53260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal         */
545931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        public TransformedImageDrawable(Context context, int resourceId, float xPct, float yPct,
55260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal                int gravity) {
565931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal            mImage = context.getDrawable(resourceId);
57260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            mXPercent = xPct;
58260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            mYPercent = yPct;
59260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            mGravity = gravity;
60260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        }
61fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
62260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        public void setAlpha(int alpha) {
63260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            mImage.setAlpha(alpha);
64260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            mAlpha = alpha;
65260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        }
66fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
67260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        public int getAlpha() {
68260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            return mAlpha;
69fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
70260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal
71260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        public void updateBounds(Rect bounds) {
72260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            int width = mImage.getIntrinsicWidth();
73260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            int height = mImage.getIntrinsicHeight();
74260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            int left = bounds.left + (int) (mXPercent * bounds.width());
75260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            int top = bounds.top + (int) (mYPercent * bounds.height());
76260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            if ((mGravity & Gravity.CENTER_HORIZONTAL) == Gravity.CENTER_HORIZONTAL) {
77260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal                left -= (width / 2);
78260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            }
79260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) {
80260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal                top -= (height / 2);
81260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            }
82260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            mImage.setBounds(left, top, left + width, top + height);
83fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
84fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
85260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        public void draw(Canvas canvas) {
86260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            mImage.draw(canvas);
87260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        }
88fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
89260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        public Rect getBounds() {
90260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal            return mImage.getBounds();
91260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal        }
92260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal    }
93fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
94260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal    protected final TransformedImageDrawable mHand;
95260b07fa86865481ab3e1c6d4fec3ef52ba0a621Sunny Goyal    protected final TransformedImageDrawable[] mIcons;
96fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    private final int mWidth;
97fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    private final int mHeight;
98fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
99fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    private ObjectAnimator mBackgroundAnim;
100fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
101fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public AllAppsBackgroundDrawable(Context context) {
102fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        Resources res = context.getResources();
1035931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        mWidth = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_width);
1045931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        mHeight = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_height);
1055931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal
1065931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        context = new ContextThemeWrapper(context,
1075931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal                Themes.getAttrBoolean(context, R.attr.isMainColorDark)
1085931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal                        ? R.style.AllAppsEmptySearchBackground_Dark
1095931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal                        : R.style.AllAppsEmptySearchBackground);
1105931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        mHand = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_hand,
11157b4006d523d9522dc20a3170c1df73907687d21Sunny Goyal                0.575f, 0.f, Gravity.CENTER_HORIZONTAL);
112fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        mIcons = new TransformedImageDrawable[4];
1135931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        mIcons[0] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_1,
114fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson                0.375f, 0, Gravity.CENTER_HORIZONTAL);
1155931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        mIcons[1] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_2,
11657b4006d523d9522dc20a3170c1df73907687d21Sunny Goyal                0.3125f, 0.2f, Gravity.CENTER_HORIZONTAL);
1175931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        mIcons[2] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_3,
11857b4006d523d9522dc20a3170c1df73907687d21Sunny Goyal                0.475f, 0.26f, Gravity.CENTER_HORIZONTAL);
1195931ca04155a7fcdfc1dc0665011a44101afda5fSunny Goyal        mIcons[3] = new TransformedImageDrawable(context, R.drawable.ic_all_apps_bg_icon_4,
120fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson                0.7f, 0.125f, Gravity.CENTER_HORIZONTAL);
121fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
122fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
123fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    /**
124fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson     * Animates the background alpha.
125fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson     */
126fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public void animateBgAlpha(float finalAlpha, int duration) {
127fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        int finalAlphaI = (int) (finalAlpha * 255f);
128fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        if (getAlpha() != finalAlphaI) {
129fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            mBackgroundAnim = cancelAnimator(mBackgroundAnim);
1302d89ea84530559e2002a3a4009a50bac1e568507Jon Miranda            mBackgroundAnim = ObjectAnimator.ofInt(this, LauncherAnimUtils.DRAWABLE_ALPHA,
1312d89ea84530559e2002a3a4009a50bac1e568507Jon Miranda                    finalAlphaI);
132fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            mBackgroundAnim.setDuration(duration);
133fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            mBackgroundAnim.start();
134fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
135fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
136fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
137fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    /**
138fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson     * Sets the background alpha immediately.
139fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson     */
140fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public void setBgAlpha(float finalAlpha) {
141fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        int finalAlphaI = (int) (finalAlpha * 255f);
142fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        if (getAlpha() != finalAlphaI) {
143fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            mBackgroundAnim = cancelAnimator(mBackgroundAnim);
144fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            setAlpha(finalAlphaI);
145fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
146fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
147fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
148fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
149fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public int getIntrinsicWidth() {
150fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        return mWidth;
151fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
152fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
153fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
154fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public int getIntrinsicHeight() {
155fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        return mHeight;
156fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
157fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
158fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
159fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public void draw(Canvas canvas) {
160fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        mHand.draw(canvas);
161fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        for (int i = 0; i < mIcons.length; i++) {
162fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            mIcons[i].draw(canvas);
163fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
164fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
165fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
166fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
167fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    protected void onBoundsChange(Rect bounds) {
168fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        super.onBoundsChange(bounds);
169fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        mHand.updateBounds(bounds);
170fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        for (int i = 0; i < mIcons.length; i++) {
171fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            mIcons[i].updateBounds(bounds);
172fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
173fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        invalidateSelf();
174fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
175fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
176fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
177fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public void setAlpha(int alpha) {
178fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        mHand.setAlpha(alpha);
179fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        for (int i = 0; i < mIcons.length; i++) {
180fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            mIcons[i].setAlpha(alpha);
181fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
182fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        invalidateSelf();
183fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
184fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
185fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
186fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public int getAlpha() {
187fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        return mHand.getAlpha();
188fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
189fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
190fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
191fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public void setColorFilter(ColorFilter colorFilter) {
192fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        // Do nothing
193fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
194fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
195fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    @Override
196fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    public int getOpacity() {
197fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        return PixelFormat.TRANSLUCENT;
198fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
199fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson
200fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    private ObjectAnimator cancelAnimator(ObjectAnimator animator) {
201fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        if (animator != null) {
202fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson            animator.cancel();
203fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        }
204fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson        return null;
205fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson    }
206fee206f2419a0ffa90abf4f9f3f9e0b6d0b74906Winson}
207