1 /* 2 * Copyright (C) 2021 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.util 18 19 import android.content.pm.ActivityInfo 20 import android.content.res.Resources 21 import android.graphics.Rect 22 import android.graphics.drawable.Drawable 23 import android.graphics.drawable.DrawableWrapper 24 import android.graphics.drawable.InsetDrawable 25 26 /** 27 * [DrawableWrapper] to use in the progress of a slider. 28 * 29 * This drawable is used to change the bounds of the enclosed drawable depending on the level to 30 * simulate a sliding progress, instead of using clipping or scaling. That way, the shape of the 31 * edges is maintained. 32 * 33 * Meant to be used with a rounded ends background, it will also prevent deformation when the slider 34 * is meant to be smaller than the rounded corner. The background should have rounded corners that 35 * are half of the height. 36 */ 37 class RoundedCornerProgressDrawable @JvmOverloads constructor( 38 drawable: Drawable? = null 39 ) : InsetDrawable(drawable, 0) { 40 41 companion object { 42 private const val MAX_LEVEL = 10000 // Taken from Drawable 43 } 44 onLayoutDirectionChangednull45 override fun onLayoutDirectionChanged(layoutDirection: Int): Boolean { 46 onLevelChange(level) 47 return super.onLayoutDirectionChanged(layoutDirection) 48 } 49 onBoundsChangenull50 override fun onBoundsChange(bounds: Rect) { 51 super.onBoundsChange(bounds) 52 onLevelChange(level) 53 } 54 onLevelChangenull55 override fun onLevelChange(level: Int): Boolean { 56 val db = drawable?.bounds!! 57 // On 0, the width is bounds.height (a circle), and on MAX_LEVEL, the width is bounds.width 58 val width = bounds.height() + (bounds.width() - bounds.height()) * level / MAX_LEVEL 59 drawable?.setBounds(bounds.left, db.top, bounds.left + width, db.bottom) 60 return super.onLevelChange(level) 61 } 62 getConstantStatenull63 override fun getConstantState(): ConstantState { 64 // This should not be null as it was created with a state in the constructor. 65 return RoundedCornerState(super.getConstantState()!!) 66 } 67 getChangingConfigurationsnull68 override fun getChangingConfigurations(): Int { 69 return super.getChangingConfigurations() or ActivityInfo.CONFIG_DENSITY 70 } 71 72 private class RoundedCornerState(private val wrappedState: ConstantState) : ConstantState() { newDrawablenull73 override fun newDrawable(): Drawable { 74 return newDrawable(null, null) 75 } 76 newDrawablenull77 override fun newDrawable(res: Resources?, theme: Resources.Theme?): Drawable { 78 val wrapper = wrappedState.newDrawable(res, theme) as DrawableWrapper 79 return RoundedCornerProgressDrawable(wrapper.drawable) 80 } 81 getChangingConfigurationsnull82 override fun getChangingConfigurations(): Int { 83 return wrappedState.changingConfigurations 84 } 85 } 86 }