1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.setupwizardlib; 18 19 import android.annotation.SuppressLint; 20 import android.content.Context; 21 import android.content.res.TypedArray; 22 import android.graphics.Bitmap; 23 import android.graphics.Canvas; 24 import android.graphics.Color; 25 import android.graphics.ColorFilter; 26 import android.graphics.Paint; 27 import android.graphics.Path; 28 import android.graphics.Rect; 29 import android.graphics.drawable.Drawable; 30 import android.os.Build; 31 32 import com.android.setupwizardlib.annotations.VisibleForTesting; 33 34 public class GlifPatternDrawable extends Drawable { 35 36 /* static section */ 37 38 @SuppressLint("InlinedApi") 39 private static final int[] ATTRS_PRIMARY_COLOR = new int[]{ android.R.attr.colorPrimary }; 40 41 private static final float VIEWBOX_HEIGHT = 768f; 42 private static final float VIEWBOX_WIDTH = 1366f; 43 private static final float SCALE_FOCUS_X = 200f; 44 private static final float SCALE_FOCUS_Y = 175f; 45 46 public static GlifPatternDrawable getDefault(Context context) { 47 int colorPrimary = 0; 48 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 49 final TypedArray a = context.obtainStyledAttributes(ATTRS_PRIMARY_COLOR); 50 colorPrimary = a.getColor(0, Color.BLACK); 51 a.recycle(); 52 } 53 return new GlifPatternDrawable(colorPrimary); 54 } 55 56 /* non-static section */ 57 58 private int mColor; 59 private Paint mPaint; 60 private float[] mTempHsv = new float[3]; 61 private Path mTempPath = new Path(); 62 private Bitmap mBitmap; 63 64 public GlifPatternDrawable(int color) { 65 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 66 setColor(color); 67 } 68 69 @Override 70 public void draw(Canvas canvas) { 71 if (mBitmap == null) { 72 mBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), 73 Bitmap.Config.ARGB_8888); 74 Canvas bitmapCanvas = new Canvas(mBitmap); 75 renderOnCanvas(bitmapCanvas); 76 } 77 canvas.drawBitmap(mBitmap, 0, 0, null); 78 } 79 80 private void renderOnCanvas(Canvas canvas) { 81 canvas.save(); 82 canvas.clipRect(getBounds()); 83 84 Color.colorToHSV(mColor, mTempHsv); 85 scaleCanvasToBounds(canvas); 86 87 // Draw the pattern by creating the paths, adjusting the colors and drawing them. The path 88 // values are extracted from the SVG of the pattern file. 89 90 mTempHsv[2] = 0.753f; 91 Path p = mTempPath; 92 p.reset(); 93 p.moveTo(1029.4f, 357.5f); 94 p.lineTo(1366f, 759.1f); 95 p.lineTo(1366f, 0f); 96 p.lineTo(1137.7f, 0f); 97 p.close(); 98 drawPath(canvas, p, mTempHsv); 99 100 mTempHsv[2] = 0.78f; 101 p.reset(); 102 p.moveTo(1138.1f, 0f); 103 p.rLineTo(-144.8f, 768f); 104 p.rLineTo(372.7f, 0f); 105 p.rLineTo(0f, -524f); 106 p.cubicTo(1290.7f, 121.6f, 1219.2f, 41.1f, 1178.7f, 0f); 107 p.close(); 108 drawPath(canvas, p, mTempHsv); 109 110 mTempHsv[2] = 0.804f; 111 p.reset(); 112 p.moveTo(949.8f, 768f); 113 p.rCubicTo(92.6f, -170.6f, 213f, -440.3f, 269.4f, -768f); 114 p.lineTo(585f, 0f); 115 p.rLineTo(2.1f, 766f); 116 p.close(); 117 drawPath(canvas, p, mTempHsv); 118 119 mTempHsv[2] = 0.827f; 120 p.reset(); 121 p.moveTo(471.1f, 768f); 122 p.rMoveTo(704.5f, 0f); 123 p.cubicTo(1123.6f, 563.3f, 1027.4f, 275.2f, 856.2f, 0f); 124 p.lineTo(476.4f, 0f); 125 p.rLineTo(-5.3f, 768f); 126 p.close(); 127 drawPath(canvas, p, mTempHsv); 128 129 mTempHsv[2] = 0.867f; 130 p.reset(); 131 p.moveTo(323.1f, 768f); 132 p.moveTo(777.5f, 768f); 133 p.cubicTo(661.9f, 348.8f, 427.2f, 21.4f, 401.2f, 25.4f); 134 p.lineTo(323.1f, 768f); 135 p.close(); 136 drawPath(canvas, p, mTempHsv); 137 138 mTempHsv[2] = 0.894f; 139 p.reset(); 140 p.moveTo(178.44286f, 766.85714f); 141 p.lineTo(308.7f, 768f); 142 p.cubicTo(381.7f, 604.6f, 481.6f, 344.3f, 562.2f, 0f); 143 p.lineTo(0f, 0f); 144 p.close(); 145 drawPath(canvas, p, mTempHsv); 146 147 mTempHsv[2] = 0.929f; 148 p.reset(); 149 p.moveTo(146f, 0f); 150 p.lineTo(0f, 0f); 151 p.lineTo(0f, 768f); 152 p.lineTo(394.2f, 768f); 153 p.cubicTo(327.7f, 475.3f, 228.5f, 201f, 146f, 0f); 154 p.close(); 155 drawPath(canvas, p, mTempHsv); 156 157 canvas.restore(); 158 } 159 160 @VisibleForTesting 161 public void scaleCanvasToBounds(Canvas canvas) { 162 final Rect bounds = getBounds(); 163 final int height = bounds.height(); 164 final int width = bounds.width(); 165 166 float scaleY = height / VIEWBOX_HEIGHT; 167 float scaleX = width / VIEWBOX_WIDTH; 168 // First scale both sides to fit independently. 169 canvas.scale(scaleX, scaleY); 170 if (scaleY > scaleX) { 171 // Adjust x-scale to maintain aspect ratio, but using (200, 0) as the pivot instead, 172 // so that more of the texture and less of the blank space on the left edge is seen. 173 canvas.scale(scaleY / scaleX, 1f, SCALE_FOCUS_X, 0f); 174 } else { 175 // Adjust y-scale to maintain aspect ratio, but using (0, 175) as the pivot instead, 176 // so that an intersection of two "circles" can always be seen. 177 canvas.scale(1f, scaleX / scaleY, 0f, SCALE_FOCUS_Y); 178 } 179 } 180 181 private void drawPath(Canvas canvas, Path path, float[] hsv) { 182 mPaint.setColor(Color.HSVToColor(hsv)); 183 canvas.drawPath(path, mPaint); 184 } 185 186 @Override 187 public void setAlpha(int i) { 188 // Ignore 189 } 190 191 @Override 192 public void setColorFilter(ColorFilter colorFilter) { 193 // Ignore 194 } 195 196 @Override 197 public int getOpacity() { 198 return 0; 199 } 200 201 public void setColor(int color) { 202 mColor = color; 203 mPaint.setColor(color); 204 mBitmap = null; 205 invalidateSelf(); 206 } 207 208 public int getColor() { 209 return mColor; 210 } 211 } 212