1c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam/*
2c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * Copyright (C) 2015 The Android Open Source Project
3c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam *
4c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * Licensed under the Apache License, Version 2.0 (the "License");
5c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * you may not use this file except in compliance with the License.
6c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * You may obtain a copy of the License at
7c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam *
8c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam *      http://www.apache.org/licenses/LICENSE-2.0
9c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam *
10c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * Unless required by applicable law or agreed to in writing, software
11c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * distributed under the License is distributed on an "AS IS" BASIS,
12c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * See the License for the specific language governing permissions and
14c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam * limitations under the License.
15c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam */
16c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
17c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lampackage com.android.setupwizardlib;
18c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
19c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.annotation.SuppressLint;
20c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.content.Context;
21c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.content.res.TypedArray;
22a2f04916533b900d3661c9e8c9d98b71276fde13Maurice Lamimport android.graphics.Bitmap;
23c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.graphics.Canvas;
24c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.graphics.Color;
25c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.graphics.ColorFilter;
26515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lamimport android.graphics.ColorMatrixColorFilter;
27c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.graphics.Paint;
28c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.graphics.Path;
296e0e22635d5fa943f72251e534f37527d3b3468cMaurice Lamimport android.graphics.PixelFormat;
30515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lamimport android.graphics.PorterDuff;
31515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lamimport android.graphics.PorterDuffXfermode;
32c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.graphics.Rect;
33c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.graphics.drawable.Drawable;
34c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lamimport android.os.Build;
354482fde98ebad2700ec1f8de5397abb90402b8b8Maurice Lamimport android.support.annotation.NonNull;
36903f83af5ba54075275b455a24c4273143fcb86aMaurice Lamimport android.support.annotation.VisibleForTesting;
37c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
38515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lamimport java.lang.ref.SoftReference;
39515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
40515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam/**
41515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam * This class draws the GLIF pattern used as the status bar background for phones and background for
42515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam * tablets in GLIF layout.
43515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam */
44c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lampublic class GlifPatternDrawable extends Drawable {
45515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    /*
46515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     * This class essentially implements a simple SVG in Java code, with some special handling of
47515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     * scaling when given different bounds.
48515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     */
49c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
50c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    /* static section */
51c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
52c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    @SuppressLint("InlinedApi")
53c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    private static final int[] ATTRS_PRIMARY_COLOR = new int[]{ android.R.attr.colorPrimary };
54c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
55c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    private static final float VIEWBOX_HEIGHT = 768f;
56c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    private static final float VIEWBOX_WIDTH = 1366f;
57515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // X coordinate of scale focus, as a fraction of of the width. (Range is 0 - 1)
58515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static final float SCALE_FOCUS_X = .146f;
59515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // Y coordinate of scale focus, as a fraction of of the height. (Range is 0 - 1)
60515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static final float SCALE_FOCUS_Y = .228f;
61515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
62515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // Alpha component of the color to be drawn, on top of the grayscale pattern. (Range is 0 - 1)
63515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static final float COLOR_ALPHA = .8f;
64515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // Int version of COLOR_ALPHA. (Range is 0 - 255)
65515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static final int COLOR_ALPHA_INT = (int) (COLOR_ALPHA * 255);
66515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
67515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // Cap the bitmap size, such that it won't hurt the performance too much
68515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // and it won't crash due to a very large scale.
69515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // The drawable will look blurry above this size.
70515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // This is a multiplier applied on top of the viewbox size.
71515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    // Resulting max cache size = (1.5 x 1366, 1.5 x 768) = (2049, 1152)
72515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static final float MAX_CACHED_BITMAP_SCALE = 1.5f;
73515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
74515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static final int NUM_PATHS = 7;
75515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
76515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static SoftReference<Bitmap> sBitmapCache;
77515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static Path[] sPatternPaths;
78515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private static int[] sPatternLightness;
79c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
80c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    public static GlifPatternDrawable getDefault(Context context) {
81c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        int colorPrimary = 0;
82c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
83c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam            final TypedArray a = context.obtainStyledAttributes(ATTRS_PRIMARY_COLOR);
84c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam            colorPrimary = a.getColor(0, Color.BLACK);
85c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam            a.recycle();
86c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        }
87c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        return new GlifPatternDrawable(colorPrimary);
88c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
89c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
90515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    @VisibleForTesting
91515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    public static void invalidatePattern() {
92515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        sBitmapCache = null;
93515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    }
94515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
95c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    /* non-static section */
96c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
97c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    private int mColor;
98515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private Paint mTempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
99515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private ColorFilter mColorFilter;
100c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
101c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    public GlifPatternDrawable(int color) {
102c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        setColor(color);
103c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
104c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
105c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    @Override
1064482fde98ebad2700ec1f8de5397abb90402b8b8Maurice Lam    public void draw(@NonNull Canvas canvas) {
107515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        final Rect bounds = getBounds();
108515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        int drawableWidth = bounds.width();
109515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        int drawableHeight = bounds.height();
110515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        Bitmap bitmap = null;
111515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        if (sBitmapCache != null) {
112515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            bitmap = sBitmapCache.get();
113515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        }
114515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        if (bitmap != null) {
115515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            final int bitmapWidth = bitmap.getWidth();
116515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            final int bitmapHeight = bitmap.getHeight();
117515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Invalidate the cache if this drawable is bigger and we can still create a bigger
118515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // cache.
119515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            if (drawableWidth > bitmapWidth
120515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                    && bitmapWidth < VIEWBOX_WIDTH * MAX_CACHED_BITMAP_SCALE) {
121515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                bitmap = null;
122515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            } else if (drawableHeight > bitmapHeight
123515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                    && bitmapHeight < VIEWBOX_HEIGHT * MAX_CACHED_BITMAP_SCALE) {
124515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                bitmap = null;
125515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            }
126515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        }
127515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
128515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        if (bitmap == null) {
129515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Reset the paint so it can be used to draw the paths in renderOnCanvas
130515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            mTempPaint.reset();
131515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
132515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            bitmap = createBitmapCache(drawableWidth, drawableHeight);
133515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            sBitmapCache = new SoftReference<>(bitmap);
134515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
135515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Reset the paint to so it can be used to draw the bitmap
136515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            mTempPaint.reset();
137a2f04916533b900d3661c9e8c9d98b71276fde13Maurice Lam        }
138515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
139081551e44a801f439f0e0f30008303dd765c118fMaurice Lam        canvas.save();
140515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        canvas.clipRect(bounds);
141515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
142515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        scaleCanvasToBounds(canvas, bitmap, bounds);
143515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
144515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                && canvas.isHardwareAccelerated()) {
145515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            mTempPaint.setColorFilter(mColorFilter);
146515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            canvas.drawBitmap(bitmap, 0, 0, mTempPaint);
147515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        } else {
148515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Software renderer doesn't work properly with ColorMatrix filter on ALPHA_8 bitmaps.
149515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            canvas.drawColor(Color.BLACK);
150515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            mTempPaint.setColor(Color.WHITE);
151515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            canvas.drawBitmap(bitmap, 0, 0, mTempPaint);
152515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            canvas.drawColor(mColor);
153515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        }
154515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
155081551e44a801f439f0e0f30008303dd765c118fMaurice Lam        canvas.restore();
156a2f04916533b900d3661c9e8c9d98b71276fde13Maurice Lam    }
157a2f04916533b900d3661c9e8c9d98b71276fde13Maurice Lam
158515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    @VisibleForTesting
159515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    public Bitmap createBitmapCache(int drawableWidth, int drawableHeight) {
160515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        float scaleX = drawableWidth / VIEWBOX_WIDTH;
161515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        float scaleY = drawableHeight / VIEWBOX_HEIGHT;
162515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        float scale = Math.max(scaleX, scaleY);
163515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        scale = Math.min(MAX_CACHED_BITMAP_SCALE, scale);
164515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
165515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
166515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        int scaledWidth = (int) (VIEWBOX_WIDTH * scale);
167515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        int scaledHeight = (int) (VIEWBOX_HEIGHT * scale);
168515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
169515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        // Use ALPHA_8 mask to save memory, since the pattern is grayscale only anyway.
170515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        Bitmap bitmap = Bitmap.createBitmap(
171515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                scaledWidth,
172515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                scaledHeight,
173515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                Bitmap.Config.ALPHA_8);
174515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        Canvas bitmapCanvas = new Canvas(bitmap);
175515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        renderOnCanvas(bitmapCanvas, scale);
176515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        return bitmap;
177515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    }
178515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
179515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    private void renderOnCanvas(Canvas canvas, float scale) {
180c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        canvas.save();
181515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        canvas.scale(scale, scale);
182c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
183515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        mTempPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
184c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
185c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        // Draw the pattern by creating the paths, adjusting the colors and drawing them. The path
186c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        // values are extracted from the SVG of the pattern file.
187c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
188515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        if (sPatternPaths == null) {
189515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            sPatternPaths = new Path[NUM_PATHS];
190515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Lightness values of the pattern, range 0 - 255
191515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            sPatternLightness = new int[] { 10, 40, 51, 66, 91, 112, 130 };
192515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
193515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            Path p = sPatternPaths[0] = new Path();
194515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(1029.4f, 357.5f);
195515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(1366f, 759.1f);
196515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(1366f, 0f);
197515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(1137.7f, 0f);
198515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.close();
199515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
200515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p = sPatternPaths[1] = new Path();
201515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(1138.1f, 0f);
202515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.rLineTo(-144.8f, 768f);
203515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.rLineTo(372.7f, 0f);
204515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.rLineTo(0f, -524f);
205515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.cubicTo(1290.7f, 121.6f, 1219.2f, 41.1f, 1178.7f, 0f);
206515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.close();
207515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
208515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p = sPatternPaths[2] = new Path();
209515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(949.8f, 768f);
210515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.rCubicTo(92.6f, -170.6f, 213f, -440.3f, 269.4f, -768f);
211515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(585f, 0f);
212515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.rLineTo(2.1f, 766f);
213515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.close();
214515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
215515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p = sPatternPaths[3] = new Path();
216515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(471.1f, 768f);
217515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.rMoveTo(704.5f, 0f);
218515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.cubicTo(1123.6f, 563.3f, 1027.4f, 275.2f, 856.2f, 0f);
219515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(476.4f, 0f);
220515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.rLineTo(-5.3f, 768f);
221515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.close();
222515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
223515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p = sPatternPaths[4] = new Path();
224515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(323.1f, 768f);
225515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(777.5f, 768f);
226515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.cubicTo(661.9f, 348.8f, 427.2f, 21.4f, 401.2f, 25.4f);
227515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(323.1f, 768f);
228515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.close();
229515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
230515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p = sPatternPaths[5] = new Path();
231515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(178.44286f, 766.85714f);
232515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(308.7f, 768f);
233515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.cubicTo(381.7f, 604.6f, 481.6f, 344.3f, 562.2f, 0f);
234515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(0f, 0f);
235515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.close();
236515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
237515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p = sPatternPaths[6] = new Path();
238515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.moveTo(146f, 0f);
239515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(0f, 0f);
240515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(0f, 768f);
241515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.lineTo(394.2f, 768f);
242515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.cubicTo(327.7f, 475.3f, 228.5f, 201f, 146f, 0f);
243515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            p.close();
244515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        }
245515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam
246515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        for (int i = 0; i < NUM_PATHS; i++) {
247515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Color is 0xAARRGGBB, so alpha << 24 will create a color with (alpha)% black.
248515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Although the color components don't really matter, since the backing bitmap cache is
249515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // ALPHA_8.
250515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            mTempPaint.setColor(sPatternLightness[i] << 24);
251515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            canvas.drawPath(sPatternPaths[i], mTempPaint);
252515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        }
253c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
254c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        canvas.restore();
255515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        mTempPaint.reset();
256c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
257c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
258c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    @VisibleForTesting
259515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    public void scaleCanvasToBounds(Canvas canvas, Bitmap bitmap, Rect drawableBounds) {
260515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        int bitmapWidth = bitmap.getWidth();
261515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        int bitmapHeight = bitmap.getHeight();
262515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        float scaleX = drawableBounds.width() / (float) bitmapWidth;
263515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        float scaleY = drawableBounds.height() / (float) bitmapHeight;
264c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
265c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        // First scale both sides to fit independently.
266c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        canvas.scale(scaleX, scaleY);
267c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        if (scaleY > scaleX) {
268515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Adjust x-scale to maintain aspect ratio using the pivot, so that more of the texture
269515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // and less of the blank space on the left edge is seen.
270515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            canvas.scale(scaleY / scaleX, 1f, SCALE_FOCUS_X * bitmapWidth, 0f);
271515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        } else if (scaleX > scaleY) {
272515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // Adjust y-scale to maintain aspect ratio using the pivot, so that an intersection of
273515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            // two "circles" can always be seen.
274515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam            canvas.scale(1f, scaleX / scaleY, 0f, SCALE_FOCUS_Y * bitmapHeight);
275c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        }
276c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
277c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
278c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    @Override
279c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    public void setAlpha(int i) {
280c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        // Ignore
281c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
282c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
283c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    @Override
284c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    public void setColorFilter(ColorFilter colorFilter) {
285c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        // Ignore
286c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
287c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
288c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    @Override
289c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    public int getOpacity() {
2906e0e22635d5fa943f72251e534f37527d3b3468cMaurice Lam        return PixelFormat.UNKNOWN;
291c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
292c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
293515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    /**
294515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     * Sets the color used as the base color of this pattern drawable. The alpha component of the
295515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     * color will be ignored.
296515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     */
297c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    public void setColor(int color) {
298515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        final int r = Color.red(color);
299515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        final int g = Color.green(color);
300515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        final int b = Color.blue(color);
301515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        mColor = Color.argb(COLOR_ALPHA_INT, r, g, b);
302515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        mColorFilter = new ColorMatrixColorFilter(new float[] {
303515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                0, 0, 0, 1 - COLOR_ALPHA, r * COLOR_ALPHA,
304515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                0, 0, 0, 1 - COLOR_ALPHA, g * COLOR_ALPHA,
305515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                0, 0, 0, 1 - COLOR_ALPHA, b * COLOR_ALPHA,
306515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam                0, 0, 0,               0,             255
307515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        });
308c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam        invalidateSelf();
309c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
310c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam
311515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam    /**
312515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     * @return The color used as the base color of this pattern drawable. The alpha component of
313515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     * this is always 255.
314515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam     */
315c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    public int getColor() {
316515c0b156d03f7ea348303c75e37ee4c16d90557Maurice Lam        return Color.argb(255, Color.red(mColor), Color.green(mColor), Color.blue(mColor));
317c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam    }
318c3eebe9f664af4b77e5948a14bf266b25dc25cc8Maurice Lam}
319