Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 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.systemui.statusbar.policy; |
| 18 | |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 19 | import android.animation.ArgbEvaluator; |
| 20 | import android.annotation.ColorInt; |
| 21 | import android.annotation.DrawableRes; |
Matthew Ng | 25593cc | 2018-09-12 16:05:41 -0700 | [diff] [blame] | 22 | import android.annotation.NonNull; |
Matthew Ng | eb5ce83 | 2018-05-15 17:50:37 -0700 | [diff] [blame] | 23 | import android.content.Context; |
| 24 | import android.content.res.Resources; |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 25 | import android.graphics.Bitmap; |
| 26 | import android.graphics.BlurMaskFilter; |
| 27 | import android.graphics.BlurMaskFilter.Blur; |
| 28 | import android.graphics.Canvas; |
Matthew Ng | eb5ce83 | 2018-05-15 17:50:37 -0700 | [diff] [blame] | 29 | import android.graphics.Color; |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 30 | import android.graphics.ColorFilter; |
| 31 | import android.graphics.Paint; |
| 32 | import android.graphics.PixelFormat; |
| 33 | import android.graphics.PorterDuff.Mode; |
| 34 | import android.graphics.PorterDuffColorFilter; |
| 35 | import android.graphics.Rect; |
| 36 | import android.graphics.drawable.AnimatedVectorDrawable; |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 37 | import android.graphics.drawable.Drawable; |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 38 | import android.util.FloatProperty; |
Matthew Ng | 25593cc | 2018-09-12 16:05:41 -0700 | [diff] [blame] | 39 | import android.view.ContextThemeWrapper; |
Gus Prevas | ab33679 | 2018-11-14 13:52:20 -0500 | [diff] [blame] | 40 | |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 41 | import com.android.settingslib.Utils; |
Matthew Ng | eb5ce83 | 2018-05-15 17:50:37 -0700 | [diff] [blame] | 42 | import com.android.systemui.R; |
Matthew Ng | eb5ce83 | 2018-05-15 17:50:37 -0700 | [diff] [blame] | 43 | |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 44 | /** |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 45 | * Drawable for {@link KeyButtonView}s that supports tinting between two colors, rotation and shows |
| 46 | * a shadow. AnimatedVectorDrawable will only support tinting from intensities but has no support |
| 47 | * for shadows nor rotations. |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 48 | */ |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 49 | public class KeyButtonDrawable extends Drawable { |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 50 | |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 51 | public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_ROTATE = |
| 52 | new FloatProperty<KeyButtonDrawable>("KeyButtonRotation") { |
| 53 | @Override |
| 54 | public void setValue(KeyButtonDrawable drawable, float degree) { |
| 55 | drawable.setRotation(degree); |
| 56 | } |
| 57 | |
| 58 | @Override |
| 59 | public Float get(KeyButtonDrawable drawable) { |
| 60 | return drawable.getRotation(); |
| 61 | } |
| 62 | }; |
| 63 | |
| 64 | public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_TRANSLATE_Y = |
| 65 | new FloatProperty<KeyButtonDrawable>("KeyButtonTranslateY") { |
| 66 | @Override |
| 67 | public void setValue(KeyButtonDrawable drawable, float y) { |
| 68 | drawable.setTranslationY(y); |
| 69 | } |
| 70 | |
| 71 | @Override |
| 72 | public Float get(KeyButtonDrawable drawable) { |
| 73 | return drawable.getTranslationY(); |
| 74 | } |
| 75 | }; |
| 76 | |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 77 | private final Paint mIconPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); |
| 78 | private final Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); |
| 79 | private final ShadowDrawableState mState; |
| 80 | private AnimatedVectorDrawable mAnimatedDrawable; |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 81 | |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 82 | public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor) { |
| 83 | this(d, new ShadowDrawableState(lightColor, darkColor, |
| 84 | d instanceof AnimatedVectorDrawable)); |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 85 | } |
| 86 | |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 87 | private KeyButtonDrawable(Drawable d, ShadowDrawableState state) { |
| 88 | mState = state; |
| 89 | if (d != null) { |
| 90 | mState.mBaseHeight = d.getIntrinsicHeight(); |
| 91 | mState.mBaseWidth = d.getIntrinsicWidth(); |
| 92 | mState.mChangingConfigurations = d.getChangingConfigurations(); |
| 93 | mState.mChildState = d.getConstantState(); |
Jason Monk | 5b3b485 | 2017-03-27 17:40:56 -0400 | [diff] [blame] | 94 | } |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 95 | if (canAnimate()) { |
| 96 | mAnimatedDrawable = (AnimatedVectorDrawable) mState.mChildState.newDrawable().mutate(); |
| 97 | setDrawableBounds(mAnimatedDrawable); |
| 98 | } |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | public void setDarkIntensity(float intensity) { |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 102 | mState.mDarkIntensity = intensity; |
| 103 | final int color = (int) ArgbEvaluator.getInstance() |
| 104 | .evaluate(intensity, mState.mLightColor, mState.mDarkColor); |
| 105 | updateShadowAlpha(); |
| 106 | setColorFilter(new PorterDuffColorFilter(color, Mode.SRC_ATOP)); |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 107 | } |
Matthew Ng | eb5ce83 | 2018-05-15 17:50:37 -0700 | [diff] [blame] | 108 | |
| 109 | public void setRotation(float degrees) { |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 110 | if (canAnimate()) { |
| 111 | // AnimatedVectorDrawables will not support rotation |
| 112 | return; |
Matthew Ng | eb5ce83 | 2018-05-15 17:50:37 -0700 | [diff] [blame] | 113 | } |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 114 | if (mState.mRotateDegrees != degrees) { |
| 115 | mState.mRotateDegrees = degrees; |
| 116 | invalidateSelf(); |
Matthew Ng | eb5ce83 | 2018-05-15 17:50:37 -0700 | [diff] [blame] | 117 | } |
| 118 | } |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 119 | |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 120 | public void setTranslationX(float x) { |
| 121 | setTranslation(x, mState.mTranslationY); |
| 122 | } |
| 123 | |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 124 | public void setTranslationY(float y) { |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 125 | setTranslation(mState.mTranslationX, y); |
| 126 | } |
| 127 | |
| 128 | public void setTranslation(float x, float y) { |
| 129 | if (mState.mTranslationX != x || mState.mTranslationY != y) { |
| 130 | mState.mTranslationX = x; |
| 131 | mState.mTranslationY = y; |
| 132 | invalidateSelf(); |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 133 | } |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | public void setShadowProperties(int x, int y, int size, int color) { |
| 137 | if (canAnimate()) { |
| 138 | // AnimatedVectorDrawables will not support shadows |
| 139 | return; |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 140 | } |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 141 | if (mState.mShadowOffsetX != x || mState.mShadowOffsetY != y |
| 142 | || mState.mShadowSize != size || mState.mShadowColor != color) { |
| 143 | mState.mShadowOffsetX = x; |
| 144 | mState.mShadowOffsetY = y; |
| 145 | mState.mShadowSize = size; |
| 146 | mState.mShadowColor = color; |
| 147 | mShadowPaint.setColorFilter( |
| 148 | new PorterDuffColorFilter(mState.mShadowColor, Mode.SRC_ATOP)); |
| 149 | updateShadowAlpha(); |
| 150 | invalidateSelf(); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | @Override |
| 155 | public void setAlpha(int alpha) { |
| 156 | mState.mAlpha = alpha; |
| 157 | mIconPaint.setAlpha(alpha); |
| 158 | updateShadowAlpha(); |
| 159 | invalidateSelf(); |
| 160 | } |
| 161 | |
| 162 | @Override |
| 163 | public void setColorFilter(ColorFilter colorFilter) { |
| 164 | mIconPaint.setColorFilter(colorFilter); |
| 165 | if (mAnimatedDrawable != null) { |
| 166 | mAnimatedDrawable.setColorFilter(colorFilter); |
| 167 | } |
| 168 | invalidateSelf(); |
| 169 | } |
| 170 | |
| 171 | public float getDarkIntensity() { |
| 172 | return mState.mDarkIntensity; |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | public float getRotation() { |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 176 | return mState.mRotateDegrees; |
| 177 | } |
| 178 | |
| 179 | public float getTranslationX() { |
| 180 | return mState.mTranslationX; |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 181 | } |
| 182 | |
| 183 | public float getTranslationY() { |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 184 | return mState.mTranslationY; |
| 185 | } |
| 186 | |
| 187 | @Override |
| 188 | public ConstantState getConstantState() { |
| 189 | return mState; |
| 190 | } |
| 191 | |
| 192 | @Override |
| 193 | public int getOpacity() { |
| 194 | return PixelFormat.TRANSLUCENT; |
| 195 | } |
| 196 | |
| 197 | @Override |
| 198 | public int getIntrinsicHeight() { |
| 199 | return mState.mBaseHeight + (mState.mShadowSize + Math.abs(mState.mShadowOffsetY)) * 2; |
| 200 | } |
| 201 | |
| 202 | @Override |
| 203 | public int getIntrinsicWidth() { |
| 204 | return mState.mBaseWidth + (mState.mShadowSize + Math.abs(mState.mShadowOffsetX)) * 2; |
| 205 | } |
| 206 | |
| 207 | public boolean canAnimate() { |
| 208 | return mState.mSupportsAnimation; |
| 209 | } |
| 210 | |
| 211 | public void startAnimation() { |
| 212 | if (mAnimatedDrawable != null) { |
| 213 | mAnimatedDrawable.start(); |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 214 | } |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 215 | } |
| 216 | |
| 217 | public void resetAnimation() { |
| 218 | if (mAnimatedDrawable != null) { |
| 219 | mAnimatedDrawable.reset(); |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 220 | } |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | public void clearAnimationCallbacks() { |
| 224 | if (mAnimatedDrawable != null) { |
| 225 | mAnimatedDrawable.clearAnimationCallbacks(); |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | @Override |
| 230 | public void draw(Canvas canvas) { |
| 231 | Rect bounds = getBounds(); |
| 232 | if (bounds.isEmpty()) { |
| 233 | return; |
| 234 | } |
| 235 | |
| 236 | if (mAnimatedDrawable != null) { |
| 237 | mAnimatedDrawable.draw(canvas); |
| 238 | } else { |
| 239 | // If no cache or previous cached bitmap is hardware/software acceleration does not |
| 240 | // match the current canvas on draw then regenerate |
| 241 | boolean hwBitmapChanged = mState.mIsHardwareBitmap != canvas.isHardwareAccelerated(); |
| 242 | if (hwBitmapChanged) { |
| 243 | mState.mIsHardwareBitmap = canvas.isHardwareAccelerated(); |
| 244 | } |
| 245 | if (mState.mLastDrawnIcon == null || hwBitmapChanged) { |
| 246 | regenerateBitmapIconCache(); |
| 247 | } |
| 248 | canvas.save(); |
| 249 | canvas.translate(mState.mTranslationX, mState.mTranslationY); |
| 250 | canvas.rotate(mState.mRotateDegrees, getIntrinsicWidth() / 2, getIntrinsicHeight() / 2); |
| 251 | |
| 252 | if (mState.mShadowSize > 0) { |
| 253 | if (mState.mLastDrawnShadow == null || hwBitmapChanged) { |
| 254 | regenerateBitmapShadowCache(); |
| 255 | } |
| 256 | |
| 257 | // Translate (with rotation offset) before drawing the shadow |
| 258 | final float radians = (float) (mState.mRotateDegrees * Math.PI / 180); |
| 259 | final float shadowOffsetX = (float) (Math.sin(radians) * mState.mShadowOffsetY |
| 260 | + Math.cos(radians) * mState.mShadowOffsetX) - mState.mTranslationX; |
| 261 | final float shadowOffsetY = (float) (Math.cos(radians) * mState.mShadowOffsetY |
| 262 | - Math.sin(radians) * mState.mShadowOffsetX) - mState.mTranslationY; |
| 263 | canvas.drawBitmap(mState.mLastDrawnShadow, shadowOffsetX, shadowOffsetY, |
| 264 | mShadowPaint); |
| 265 | } |
| 266 | canvas.drawBitmap(mState.mLastDrawnIcon, null, bounds, mIconPaint); |
| 267 | canvas.restore(); |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | @Override |
| 272 | public boolean canApplyTheme() { |
| 273 | return mState.canApplyTheme(); |
| 274 | } |
| 275 | |
| 276 | private void regenerateBitmapIconCache() { |
| 277 | final int width = getIntrinsicWidth(); |
| 278 | final int height = getIntrinsicHeight(); |
| 279 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); |
| 280 | final Canvas canvas = new Canvas(bitmap); |
| 281 | |
| 282 | // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared. |
| 283 | final Drawable d = mState.mChildState.newDrawable().mutate(); |
| 284 | setDrawableBounds(d); |
| 285 | d.draw(canvas); |
| 286 | |
| 287 | if (mState.mIsHardwareBitmap) { |
| 288 | bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false); |
| 289 | } |
| 290 | mState.mLastDrawnIcon = bitmap; |
| 291 | } |
| 292 | |
| 293 | private void regenerateBitmapShadowCache() { |
| 294 | if (mState.mShadowSize == 0) { |
| 295 | // No shadow |
| 296 | mState.mLastDrawnIcon = null; |
| 297 | return; |
| 298 | } |
| 299 | |
| 300 | final int width = getIntrinsicWidth(); |
| 301 | final int height = getIntrinsicHeight(); |
| 302 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); |
| 303 | Canvas canvas = new Canvas(bitmap); |
| 304 | |
| 305 | // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared. |
| 306 | final Drawable d = mState.mChildState.newDrawable().mutate(); |
| 307 | setDrawableBounds(d); |
| 308 | d.draw(canvas); |
| 309 | |
| 310 | // Draws the shadow from original drawable |
| 311 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); |
| 312 | paint.setMaskFilter(new BlurMaskFilter(mState.mShadowSize, Blur.NORMAL)); |
| 313 | int[] offset = new int[2]; |
| 314 | final Bitmap shadow = bitmap.extractAlpha(paint, offset); |
| 315 | paint.setMaskFilter(null); |
| 316 | bitmap.eraseColor(Color.TRANSPARENT); |
| 317 | canvas.drawBitmap(shadow, offset[0], offset[1], paint); |
| 318 | |
| 319 | if (mState.mIsHardwareBitmap) { |
| 320 | bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false); |
| 321 | } |
| 322 | mState.mLastDrawnShadow = bitmap; |
| 323 | } |
| 324 | |
| 325 | /** |
| 326 | * Set the alpha of the shadow. As dark intensity increases, drop the alpha of the shadow since |
| 327 | * dark color and shadow should not be visible at the same time. |
| 328 | */ |
| 329 | private void updateShadowAlpha() { |
| 330 | // Update the color from the original color's alpha as the max |
| 331 | int alpha = Color.alpha(mState.mShadowColor); |
| 332 | mShadowPaint.setAlpha( |
| 333 | Math.round(alpha * (mState.mAlpha / 255f) * (1 - mState.mDarkIntensity))); |
| 334 | } |
| 335 | |
| 336 | /** |
| 337 | * Prevent shadow clipping by offsetting the drawable bounds by the shadow and its offset |
| 338 | * @param d the drawable to set the bounds |
| 339 | */ |
| 340 | private void setDrawableBounds(Drawable d) { |
| 341 | final int offsetX = mState.mShadowSize + Math.abs(mState.mShadowOffsetX); |
| 342 | final int offsetY = mState.mShadowSize + Math.abs(mState.mShadowOffsetY); |
| 343 | d.setBounds(offsetX, offsetY, getIntrinsicWidth() - offsetX, |
| 344 | getIntrinsicHeight() - offsetY); |
| 345 | } |
| 346 | |
| 347 | private static class ShadowDrawableState extends ConstantState { |
| 348 | int mChangingConfigurations; |
| 349 | int mBaseWidth; |
| 350 | int mBaseHeight; |
| 351 | float mRotateDegrees; |
| 352 | float mTranslationX; |
| 353 | float mTranslationY; |
| 354 | int mShadowOffsetX; |
| 355 | int mShadowOffsetY; |
| 356 | int mShadowSize; |
| 357 | int mShadowColor; |
| 358 | float mDarkIntensity; |
| 359 | int mAlpha; |
| 360 | |
| 361 | boolean mIsHardwareBitmap; |
| 362 | Bitmap mLastDrawnIcon; |
| 363 | Bitmap mLastDrawnShadow; |
| 364 | ConstantState mChildState; |
| 365 | |
| 366 | final int mLightColor; |
| 367 | final int mDarkColor; |
| 368 | final boolean mSupportsAnimation; |
| 369 | |
| 370 | public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor, |
| 371 | boolean animated) { |
| 372 | mLightColor = lightColor; |
| 373 | mDarkColor = darkColor; |
| 374 | mSupportsAnimation = animated; |
| 375 | mAlpha = 255; |
| 376 | } |
| 377 | |
| 378 | @Override |
| 379 | public Drawable newDrawable() { |
| 380 | return new KeyButtonDrawable(null, this); |
| 381 | } |
| 382 | |
| 383 | @Override |
| 384 | public int getChangingConfigurations() { |
| 385 | return mChangingConfigurations; |
| 386 | } |
| 387 | |
| 388 | @Override |
| 389 | public boolean canApplyTheme() { |
| 390 | return true; |
| 391 | } |
| 392 | } |
| 393 | |
Matthew Ng | 25593cc | 2018-09-12 16:05:41 -0700 | [diff] [blame] | 394 | /** |
| 395 | * Creates a KeyButtonDrawable with a shadow given its icon. The tint applied to the drawable |
| 396 | * is determined by the dark and light theme given by the context. |
| 397 | * @param ctx Context to get the drawable and determine the dark and light theme |
| 398 | * @param icon the icon resource id |
| 399 | * @param hasShadow if a shadow will appear with the drawable |
| 400 | * @return KeyButtonDrawable |
| 401 | */ |
| 402 | public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon, |
| 403 | boolean hasShadow) { |
| 404 | final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme); |
| 405 | final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme); |
| 406 | Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme); |
| 407 | Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme); |
| 408 | return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow); |
| 409 | } |
| 410 | |
Matthew Ng | d6865ba | 2018-08-27 17:58:41 -0700 | [diff] [blame] | 411 | public static KeyButtonDrawable create(Context lightContext, Context darkContext, |
| 412 | @DrawableRes int iconResId, boolean hasShadow) { |
| 413 | return create(lightContext, |
| 414 | Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor), |
| 415 | Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor), |
| 416 | iconResId, hasShadow); |
| 417 | } |
| 418 | |
| 419 | public static KeyButtonDrawable create(Context context, @ColorInt int lightColor, |
| 420 | @ColorInt int darkColor, @DrawableRes int iconResId, boolean hasShadow) { |
| 421 | final KeyButtonDrawable drawable = new KeyButtonDrawable(context.getDrawable(iconResId), |
| 422 | lightColor, darkColor); |
| 423 | if (hasShadow) { |
| 424 | final Resources res = context.getResources(); |
| 425 | int offsetX = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_x); |
| 426 | int offsetY = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_y); |
| 427 | int radius = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_radius); |
| 428 | int color = context.getColor(R.color.nav_key_button_shadow_color); |
| 429 | drawable.setShadowProperties(offsetX, offsetY, radius, color); |
| 430 | } |
| 431 | return drawable; |
Matthew Ng | ca4592b | 2018-08-06 14:12:37 -0700 | [diff] [blame] | 432 | } |
Jorim Jaggi | 40db029 | 2016-06-27 17:58:03 -0700 | [diff] [blame] | 433 | } |