diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml index acb47f7a037c7..2d67d95ab17e0 100644 --- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml +++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml @@ -14,8 +14,9 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + android:textSize="@dimen/dream_overlay_complication_clock_time_text_size" + app:keyShadowBlur="@dimen/dream_overlay_clock_key_text_shadow_radius" + app:keyShadowOffsetX="@dimen/dream_overlay_clock_key_text_shadow_dx" + app:keyShadowOffsetY="@dimen/dream_overlay_clock_key_text_shadow_dy" + app:keyShadowAlpha="0.3" + app:ambientShadowBlur="@dimen/dream_overlay_clock_ambient_text_shadow_radius" + app:ambientShadowOffsetX="@dimen/dream_overlay_clock_ambient_text_shadow_dx" + app:ambientShadowOffsetY="@dimen/dream_overlay_clock_ambient_text_shadow_dy" + app:ambientShadowAlpha="0.3" +/> diff --git a/packages/SystemUI/shared/res/values/attrs.xml b/packages/SystemUI/shared/res/values/attrs.xml index f9d66ee583da1..96a58405a764d 100644 --- a/packages/SystemUI/shared/res/values/attrs.xml +++ b/packages/SystemUI/shared/res/values/attrs.xml @@ -25,4 +25,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt new file mode 100644 index 0000000000000..3748eba47be5f --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.shared.shadow + +import android.graphics.BlendMode +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.ColorFilter +import android.graphics.PixelFormat +import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter +import android.graphics.RenderEffect +import android.graphics.RenderNode +import android.graphics.Shader +import android.graphics.drawable.Drawable +import android.graphics.drawable.InsetDrawable +import com.android.systemui.shared.shadow.DoubleShadowTextHelper.ShadowInfo + +/** A component to draw an icon with two layers of shadows. */ +class DoubleShadowIconDrawable( + keyShadowInfo: ShadowInfo, + ambientShadowInfo: ShadowInfo, + iconDrawable: Drawable, + iconSize: Int, + val iconInsetSize: Int +) : Drawable() { + private val mAmbientShadowInfo: ShadowInfo + private val mCanvasSize: Int + private val mKeyShadowInfo: ShadowInfo + private val mIconDrawable: InsetDrawable + private val mDoubleShadowNode: RenderNode + + init { + mCanvasSize = iconSize + iconInsetSize * 2 + mKeyShadowInfo = keyShadowInfo + mAmbientShadowInfo = ambientShadowInfo + setBounds(0, 0, mCanvasSize, mCanvasSize) + mIconDrawable = InsetDrawable(iconDrawable, iconInsetSize) + mIconDrawable.setBounds(0, 0, mCanvasSize, mCanvasSize) + mDoubleShadowNode = createShadowRenderNode() + } + + private fun createShadowRenderNode(): RenderNode { + val renderNode = RenderNode("DoubleShadowNode") + renderNode.setPosition(0, 0, mCanvasSize, mCanvasSize) + // Create render effects + val ambientShadow = + createShadowRenderEffect( + mAmbientShadowInfo.blur, + mAmbientShadowInfo.offsetX, + mAmbientShadowInfo.offsetY, + mAmbientShadowInfo.alpha + ) + val keyShadow = + createShadowRenderEffect( + mKeyShadowInfo.blur, + mKeyShadowInfo.offsetX, + mKeyShadowInfo.offsetY, + mKeyShadowInfo.alpha + ) + val blend = RenderEffect.createBlendModeEffect(ambientShadow, keyShadow, BlendMode.DARKEN) + renderNode.setRenderEffect(blend) + return renderNode + } + + private fun createShadowRenderEffect( + radius: Float, + offsetX: Float, + offsetY: Float, + alpha: Float + ): RenderEffect { + return RenderEffect.createColorFilterEffect( + PorterDuffColorFilter(Color.argb(alpha, 0f, 0f, 0f), PorterDuff.Mode.MULTIPLY), + RenderEffect.createOffsetEffect( + offsetX, + offsetY, + RenderEffect.createBlurEffect(radius, radius, Shader.TileMode.CLAMP) + ) + ) + } + + override fun draw(canvas: Canvas) { + if (canvas.isHardwareAccelerated) { + if (!mDoubleShadowNode.hasDisplayList()) { + // Record render node if its display list is not recorded or discarded + // (which happens when it's no longer drawn by anything). + val recordingCanvas = mDoubleShadowNode.beginRecording() + mIconDrawable.draw(recordingCanvas) + mDoubleShadowNode.endRecording() + } + canvas.drawRenderNode(mDoubleShadowNode) + } + mIconDrawable.draw(canvas) + } + + override fun getOpacity(): Int { + return PixelFormat.TRANSPARENT + } + + override fun setAlpha(alpha: Int) { + mIconDrawable.alpha = alpha + } + + override fun setColorFilter(colorFilter: ColorFilter?) { + mIconDrawable.colorFilter = colorFilter + } + + override fun setTint(color: Int) { + mIconDrawable.setTint(color) + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt new file mode 100644 index 0000000000000..f2db129120e9a --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.shared.shadow + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import android.widget.TextClock +import com.android.systemui.shared.R +import com.android.systemui.shared.shadow.DoubleShadowTextHelper.ShadowInfo +import com.android.systemui.shared.shadow.DoubleShadowTextHelper.applyShadows + +/** Extension of [TextClock] which draws two shadows on the text (ambient and key shadows) */ +class DoubleShadowTextClock +@JvmOverloads +constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : TextClock(context, attrs, defStyleAttr, defStyleRes) { + private val mAmbientShadowInfo: ShadowInfo + private val mKeyShadowInfo: ShadowInfo + + init { + val attributes = + context.obtainStyledAttributes( + attrs, + R.styleable.DoubleShadowTextClock, + defStyleAttr, + defStyleRes + ) + try { + val keyShadowBlur = + attributes.getDimensionPixelSize(R.styleable.DoubleShadowTextClock_keyShadowBlur, 0) + val keyShadowOffsetX = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextClock_keyShadowOffsetX, + 0 + ) + val keyShadowOffsetY = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextClock_keyShadowOffsetY, + 0 + ) + val keyShadowAlpha = + attributes.getFloat(R.styleable.DoubleShadowTextClock_keyShadowAlpha, 0f) + mKeyShadowInfo = + ShadowInfo( + keyShadowBlur.toFloat(), + keyShadowOffsetX.toFloat(), + keyShadowOffsetY.toFloat(), + keyShadowAlpha + ) + val ambientShadowBlur = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextClock_ambientShadowBlur, + 0 + ) + val ambientShadowOffsetX = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextClock_ambientShadowOffsetX, + 0 + ) + val ambientShadowOffsetY = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextClock_ambientShadowOffsetY, + 0 + ) + val ambientShadowAlpha = + attributes.getFloat(R.styleable.DoubleShadowTextClock_ambientShadowAlpha, 0f) + mAmbientShadowInfo = + ShadowInfo( + ambientShadowBlur.toFloat(), + ambientShadowOffsetX.toFloat(), + ambientShadowOffsetY.toFloat(), + ambientShadowAlpha + ) + } finally { + attributes.recycle() + } + } + + public override fun onDraw(canvas: Canvas) { + applyShadows(mKeyShadowInfo, mAmbientShadowInfo, this, canvas) { super.onDraw(canvas) } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextHelper.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextHelper.kt similarity index 77% rename from packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextHelper.kt rename to packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextHelper.kt index b1dc5a2e5deab..eaac93dc2555e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextHelper.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextHelper.kt @@ -14,31 +14,33 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication +package com.android.systemui.shared.shadow import android.graphics.Canvas +import android.graphics.Color import android.widget.TextView -import androidx.annotation.ColorInt -class DoubleShadowTextHelper -constructor( - private val keyShadowInfo: ShadowInfo, - private val ambientShadowInfo: ShadowInfo, -) { +object DoubleShadowTextHelper { data class ShadowInfo( val blur: Float, val offsetX: Float = 0f, val offsetY: Float = 0f, - @ColorInt val color: Int + val alpha: Float ) - fun applyShadows(view: TextView, canvas: Canvas, onDrawCallback: () -> Unit) { + fun applyShadows( + keyShadowInfo: ShadowInfo, + ambientShadowInfo: ShadowInfo, + view: TextView, + canvas: Canvas, + onDrawCallback: () -> Unit + ) { // We enhance the shadow by drawing the shadow twice view.paint.setShadowLayer( ambientShadowInfo.blur, ambientShadowInfo.offsetX, ambientShadowInfo.offsetY, - ambientShadowInfo.color + Color.argb(ambientShadowInfo.alpha, 0f, 0f, 0f) ) onDrawCallback() canvas.save() @@ -53,7 +55,7 @@ constructor( keyShadowInfo.blur, keyShadowInfo.offsetX, keyShadowInfo.offsetY, - keyShadowInfo.color + Color.argb(keyShadowInfo.alpha, 0f, 0f, 0f) ) onDrawCallback() canvas.restore() diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextView.kt new file mode 100644 index 0000000000000..25d272185bc00 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextView.kt @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.shared.shadow + +import android.content.Context +import android.graphics.Canvas +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.widget.TextView +import com.android.systemui.shared.R +import com.android.systemui.shared.shadow.DoubleShadowTextHelper.ShadowInfo +import com.android.systemui.shared.shadow.DoubleShadowTextHelper.applyShadows + +/** Extension of [TextView] which draws two shadows on the text (ambient and key shadows} */ +class DoubleShadowTextView +@JvmOverloads +constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : TextView(context, attrs, defStyleAttr, defStyleRes) { + private val mKeyShadowInfo: ShadowInfo + private val mAmbientShadowInfo: ShadowInfo + + init { + val attributes = + context.obtainStyledAttributes( + attrs, + R.styleable.DoubleShadowTextView, + defStyleAttr, + defStyleRes + ) + val drawableSize: Int + val drawableInsetSize: Int + try { + val keyShadowBlur = + attributes.getDimensionPixelSize(R.styleable.DoubleShadowTextView_keyShadowBlur, 0) + val keyShadowOffsetX = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextView_keyShadowOffsetX, + 0 + ) + val keyShadowOffsetY = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextView_keyShadowOffsetY, + 0 + ) + val keyShadowAlpha = + attributes.getFloat(R.styleable.DoubleShadowTextView_keyShadowAlpha, 0f) + mKeyShadowInfo = + ShadowInfo( + keyShadowBlur.toFloat(), + keyShadowOffsetX.toFloat(), + keyShadowOffsetY.toFloat(), + keyShadowAlpha + ) + val ambientShadowBlur = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextView_ambientShadowBlur, + 0 + ) + val ambientShadowOffsetX = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextView_ambientShadowOffsetX, + 0 + ) + val ambientShadowOffsetY = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextView_ambientShadowOffsetY, + 0 + ) + val ambientShadowAlpha = + attributes.getFloat(R.styleable.DoubleShadowTextView_ambientShadowAlpha, 0f) + mAmbientShadowInfo = + ShadowInfo( + ambientShadowBlur.toFloat(), + ambientShadowOffsetX.toFloat(), + ambientShadowOffsetY.toFloat(), + ambientShadowAlpha + ) + drawableSize = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextView_drawableIconSize, + 0 + ) + drawableInsetSize = + attributes.getDimensionPixelSize( + R.styleable.DoubleShadowTextView_drawableIconInsetSize, + 0 + ) + } finally { + attributes.recycle() + } + + val drawables = arrayOf(null, null, null, null) + for ((index, drawable) in compoundDrawablesRelative.withIndex()) { + if (drawable == null) continue + drawables[index] = + DoubleShadowIconDrawable( + mKeyShadowInfo, + mAmbientShadowInfo, + drawable, + drawableSize, + drawableInsetSize + ) + } + setCompoundDrawablesRelative(drawables[0], drawables[1], drawables[2], drawables[3]) + } + + public override fun onDraw(canvas: Canvas) { + applyShadows(mKeyShadowInfo, mAmbientShadowInfo, this, canvas) { super.onDraw(canvas) } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextClock.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextClock.java deleted file mode 100644 index 789ebc5172714..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextClock.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.dreams.complication; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.util.AttributeSet; -import android.widget.TextClock; - -import com.android.systemui.R; -import com.android.systemui.dreams.complication.DoubleShadowTextHelper.ShadowInfo; - -import kotlin.Unit; - -/** - * Extension of {@link TextClock} which draws two shadows on the text (ambient and key shadows) - */ -public class DoubleShadowTextClock extends TextClock { - private final DoubleShadowTextHelper mShadowHelper; - - public DoubleShadowTextClock(Context context) { - this(context, null); - } - - public DoubleShadowTextClock(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public DoubleShadowTextClock(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - final Resources resources = context.getResources(); - final ShadowInfo keyShadowInfo = new ShadowInfo( - resources.getDimensionPixelSize(R.dimen.dream_overlay_clock_key_text_shadow_radius), - resources.getDimensionPixelSize(R.dimen.dream_overlay_clock_key_text_shadow_dx), - resources.getDimensionPixelSize(R.dimen.dream_overlay_clock_key_text_shadow_dy), - resources.getColor(R.color.dream_overlay_clock_key_text_shadow_color)); - - final ShadowInfo ambientShadowInfo = new ShadowInfo( - resources.getDimensionPixelSize( - R.dimen.dream_overlay_clock_ambient_text_shadow_radius), - resources.getDimensionPixelSize(R.dimen.dream_overlay_clock_ambient_text_shadow_dx), - resources.getDimensionPixelSize(R.dimen.dream_overlay_clock_ambient_text_shadow_dy), - resources.getColor(R.color.dream_overlay_clock_ambient_text_shadow_color)); - mShadowHelper = new DoubleShadowTextHelper(keyShadowInfo, ambientShadowInfo); - } - - @Override - public void onDraw(Canvas canvas) { - mShadowHelper.applyShadows(this, canvas, () -> { - super.onDraw(canvas); - return Unit.INSTANCE; - }); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextView.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextView.java deleted file mode 100644 index cf7e3127dedf7..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DoubleShadowTextView.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.dreams.complication; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.util.AttributeSet; -import android.widget.TextView; - -import com.android.systemui.R; - -import kotlin.Unit; - -/** - * Extension of {@link TextView} which draws two shadows on the text (ambient and key shadows} - */ -public class DoubleShadowTextView extends TextView { - private final DoubleShadowTextHelper mShadowHelper; - - public DoubleShadowTextView(Context context) { - this(context, null); - } - - public DoubleShadowTextView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public DoubleShadowTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - final Resources resources = context.getResources(); - final DoubleShadowTextHelper.ShadowInfo - keyShadowInfo = new DoubleShadowTextHelper.ShadowInfo( - resources.getDimensionPixelSize( - R.dimen.dream_overlay_status_bar_key_text_shadow_radius), - resources.getDimensionPixelSize( - R.dimen.dream_overlay_status_bar_key_text_shadow_dx), - resources.getDimensionPixelSize( - R.dimen.dream_overlay_status_bar_key_text_shadow_dy), - resources.getColor(R.color.dream_overlay_status_bar_key_text_shadow_color)); - - final DoubleShadowTextHelper.ShadowInfo - ambientShadowInfo = new DoubleShadowTextHelper.ShadowInfo( - resources.getDimensionPixelSize( - R.dimen.dream_overlay_status_bar_ambient_text_shadow_radius), - resources.getDimensionPixelSize( - R.dimen.dream_overlay_status_bar_ambient_text_shadow_dx), - resources.getDimensionPixelSize( - R.dimen.dream_overlay_status_bar_ambient_text_shadow_dy), - resources.getColor(R.color.dream_overlay_status_bar_ambient_text_shadow_color)); - mShadowHelper = new DoubleShadowTextHelper(keyShadowInfo, ambientShadowInfo); - } - - @Override - public void onDraw(Canvas canvas) { - mShadowHelper.applyShadows(this, canvas, () -> { - super.onDraw(canvas); - return Unit.INSTANCE; - }); - } -}