Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ccd1312 authored by Chandru S's avatar Chandru S
Browse files

Fixes color contrast issue for KeyguardIndicationTextView

Summary of changes:
 1. Use wallpaperTextColor instead of color.White or the current top indication's color
 2. Update indication text color whenever there is any configuration change, this is a superset of changes that includes changes to themes as well
 3. Encapsulate access to the color through get/set methods so that the child classes don't change the color field
 4. Make KeyguardIndicationTextView extend DoubleShadowTextView to add double shadow to improve contrast
 5. Apply the double shadow text style when text is not too dark.

Bug: 349297241
Test: everything builds, verified manually
Flag: com.android.systemui.indication_text_a11y_fix
Change-Id: Ia9ad78c7425631eb5231df56ccbe05c854813165
parent 6d99ea54
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -159,6 +159,17 @@
        <item name="android:shadowRadius">?attr/shadowRadius</item>
    </style>

    <style name="TextAppearance.Keyguard.BottomArea.DoubleShadow">
        <item name="keyShadowBlur">0.5dp</item>
        <item name="keyShadowOffsetX">0.5dp</item>
        <item name="keyShadowOffsetY">0.5dp</item>
        <item name="keyShadowAlpha">0.8</item>
        <item name="ambientShadowBlur">0.5dp</item>
        <item name="ambientShadowOffsetX">0.5dp</item>
        <item name="ambientShadowOffsetY">0.5dp</item>
        <item name="ambientShadowAlpha">0.6</item>
    </style>

    <style name="TextAppearance.Keyguard.BottomArea.Button">
        <item name="android:shadowRadius">0</item>
    </style>
+21 −9
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui.shared.shadow

import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.AttributeSet
@@ -31,19 +32,23 @@ constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0
    defStyleRes: Int = 0,
) : TextView(context, attrs, defStyleAttr, defStyleRes) {
    private val mKeyShadowInfo: ShadowInfo
    private val mAmbientShadowInfo: ShadowInfo
    private lateinit var mKeyShadowInfo: ShadowInfo
    private lateinit var mAmbientShadowInfo: ShadowInfo

    init {
        val attributes =
        updateShadowDrawables(
            context.obtainStyledAttributes(
                attrs,
                R.styleable.DoubleShadowTextView,
                defStyleAttr,
                defStyleRes
                defStyleRes,
            )
        )
    }

    private fun updateShadowDrawables(attributes: TypedArray) {
        val drawableSize: Int
        val drawableInsetSize: Int
        try {
@@ -70,17 +75,17 @@ constructor(
                    ambientShadowBlur,
                    ambientShadowOffsetX,
                    ambientShadowOffsetY,
                    ambientShadowAlpha
                    ambientShadowAlpha,
                )
            drawableSize =
                attributes.getDimensionPixelSize(
                    R.styleable.DoubleShadowTextView_drawableIconSize,
                    0
                    0,
                )
            drawableInsetSize =
                attributes.getDimensionPixelSize(
                    R.styleable.DoubleShadowTextView_drawableIconInsetSize,
                    0
                    0,
                )
        } finally {
            attributes.recycle()
@@ -95,12 +100,19 @@ constructor(
                    mAmbientShadowInfo,
                    drawable,
                    drawableSize,
                    drawableInsetSize
                    drawableInsetSize,
                )
        }
        setCompoundDrawablesRelative(drawables[0], drawables[1], drawables[2], drawables[3])
    }

    override fun setTextAppearance(resId: Int) {
        super.setTextAppearance(resId)
        updateShadowDrawables(
            context.obtainStyledAttributes(resId, R.styleable.DoubleShadowTextView)
        )
    }

    public override fun onDraw(canvas: Canvas) {
        applyShadows(mKeyShadowInfo, mAmbientShadowInfo, this, canvas) { super.onDraw(canvas) }
    }
+5 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Flags
import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
@@ -73,7 +74,6 @@ object KeyguardIndicationAreaBinder {
        disposables +=
            view.repeatWhenAttached {
                repeatOnLifecycle(Lifecycle.State.STARTED) {

                    launch("$TAG#viewModel.indicationAreaTranslationX") {
                        viewModel.indicationAreaTranslationX.collect { translationX ->
                            view.translationX = translationX
@@ -119,6 +119,9 @@ object KeyguardIndicationAreaBinder {
                    launch("$TAG#viewModel.configurationChange") {
                        viewModel.configurationChange.collect {
                            configurationBasedDimensions.value = loadFromResources(view)
                            if (Flags.indicationTextA11yFix()) {
                                indicationController.onConfigurationChanged()
                            }
                        }
                    }

@@ -140,7 +143,7 @@ object KeyguardIndicationAreaBinder {
                view.resources.getDimensionPixelOffset(R.dimen.keyguard_indication_area_padding),
            indicationTextSizePx =
                view.resources.getDimensionPixelSize(
                    com.android.internal.R.dimen.text_size_small_material,
                    com.android.internal.R.dimen.text_size_small_material
                ),
        )
    }
+56 −18
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.Flags;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
import com.android.systemui.biometrics.FaceHelpMessageDeferralFactory;
@@ -199,7 +200,7 @@ public class KeyguardIndicationController {
    private CharSequence mBiometricMessage;
    private CharSequence mBiometricMessageFollowUp;
    private BiometricSourceType mBiometricMessageSource;
    protected ColorStateList mInitialTextColorState;
    private ColorStateList mInitialTextColorState;
    private boolean mVisible;
    private boolean mOrganizationOwnedDevice;

@@ -393,13 +394,27 @@ public class KeyguardIndicationController {
        return mIndicationArea;
    }

    /**
     * Notify controller about configuration changes.
     */
    public void onConfigurationChanged() {
        // Get new text color in case theme has changed
        if (Flags.indicationTextA11yFix()) {
            setIndicationColorToThemeColor();
        }
    }

    public void setIndicationArea(ViewGroup indicationArea) {
        mIndicationArea = indicationArea;
        mTopIndicationView = indicationArea.findViewById(R.id.keyguard_indication_text);
        mLockScreenIndicationView = indicationArea.findViewById(
                R.id.keyguard_indication_text_bottom);
        mInitialTextColorState = mTopIndicationView != null
                ? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
        if (Flags.indicationTextA11yFix()) {
            setIndicationColorToThemeColor();
        } else {
            setIndicationTextColor(mTopIndicationView != null
                    ? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE));
        }
        if (mRotateTextViewController != null) {
            mRotateTextViewController.destroy();
        }
@@ -436,6 +451,12 @@ public class KeyguardIndicationController {
                mIsLogoutEnabledCallback);
    }

    @NonNull
    private ColorStateList wallpaperTextColor() {
        return ColorStateList.valueOf(
                Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor));
    }

    /**
     * Cleanup
     */
@@ -513,7 +534,7 @@ public class KeyguardIndicationController {
                            .setMessage(mContext.getResources().getString(
                                    com.android.systemui.res.R.string.dismissible_keyguard_swipe)
                            )
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    /* updateImmediately */ true);
        } else {
@@ -533,7 +554,7 @@ public class KeyguardIndicationController {
                              INDICATION_TYPE_DISCLOSURE,
                              new KeyguardIndication.Builder()
                                      .setMessage(disclosure)
                                      .setTextColor(mInitialTextColorState)
                                      .setTextColor(getInitialTextColorState())
                                      .build(),
                              /* updateImmediately */ false);
                    }
@@ -602,7 +623,7 @@ public class KeyguardIndicationController {
                            INDICATION_TYPE_OWNER_INFO,
                            new KeyguardIndication.Builder()
                                    .setMessage(finalInfo)
                                    .setTextColor(mInitialTextColorState)
                                    .setTextColor(getInitialTextColorState())
                                    .build(),
                            false);
                } else {
@@ -624,7 +645,7 @@ public class KeyguardIndicationController {
                    INDICATION_TYPE_BATTERY,
                    new KeyguardIndication.Builder()
                            .setMessage(powerIndication)
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    animate);
        } else {
@@ -645,7 +666,7 @@ public class KeyguardIndicationController {
                    new KeyguardIndication.Builder()
                            .setMessage(mContext.getResources().getText(
                                    com.android.internal.R.string.lockscreen_storage_locked))
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    false);
        } else {
@@ -666,7 +687,7 @@ public class KeyguardIndicationController {
                            .setMessage(mBiometricMessage)
                            .setForceAccessibilityLiveRegionAssertive()
                            .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    true
            );
@@ -680,7 +701,7 @@ public class KeyguardIndicationController {
                    new KeyguardIndication.Builder()
                            .setMessage(mBiometricMessageFollowUp)
                            .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    true
            );
@@ -711,7 +732,7 @@ public class KeyguardIndicationController {
                    INDICATION_TYPE_TRUST,
                    new KeyguardIndication.Builder()
                            .setMessage(trustGrantedIndication)
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    true);
            hideBiometricMessage();
@@ -722,7 +743,7 @@ public class KeyguardIndicationController {
                    INDICATION_TYPE_TRUST,
                    new KeyguardIndication.Builder()
                            .setMessage(trustManagedIndication)
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    false);
        } else {
@@ -751,7 +772,7 @@ public class KeyguardIndicationController {
                    INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE,
                    new KeyguardIndication.Builder()
                            .setMessage(mPersistentUnlockMessage)
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    true);
        } else {
@@ -792,7 +813,7 @@ public class KeyguardIndicationController {
                    new KeyguardIndication.Builder()
                            .setMessage(mContext.getString(
                                    R.string.keyguard_indication_after_adaptive_auth_lock))
                            .setTextColor(mInitialTextColorState)
                            .setTextColor(getInitialTextColorState())
                            .build(),
                    true);
        } else {
@@ -1179,7 +1200,8 @@ public class KeyguardIndicationController {
                } else {
                    message = mContext.getString(R.string.keyguard_retry);
                }
                mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState,
                mStatusBarKeyguardViewManager.setKeyguardMessage(message,
                        getInitialTextColorState(),
                        null);
            }
        } else {
@@ -1232,7 +1254,7 @@ public class KeyguardIndicationController {

    public void dump(PrintWriter pw, String[] args) {
        pw.println("KeyguardIndicationController:");
        pw.println("  mInitialTextColorState: " + mInitialTextColorState);
        pw.println("  mInitialTextColorState: " + getInitialTextColorState());
        pw.println("  mPowerPluggedInWired: " + mPowerPluggedInWired);
        pw.println("  mPowerPluggedIn: " + mPowerPluggedIn);
        pw.println("  mPowerCharged: " + mPowerCharged);
@@ -1253,6 +1275,22 @@ public class KeyguardIndicationController {
        mRotateTextViewController.dump(pw, args);
    }

    protected ColorStateList getInitialTextColorState() {
        return mInitialTextColorState;
    }

    private void setIndicationColorToThemeColor() {
        mInitialTextColorState = wallpaperTextColor();
    }

    /**
     * @deprecated Use {@link #setIndicationColorToThemeColor}
     */
    @Deprecated
    private void setIndicationTextColor(ColorStateList color) {
        mInitialTextColorState = color;
    }

    protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
        @Override
        public void onTimeChanged() {
@@ -1358,7 +1396,7 @@ public class KeyguardIndicationController {
                    mBouncerMessageInteractor.setFaceAcquisitionMessage(helpString);
                }
                mStatusBarKeyguardViewManager.setKeyguardMessage(helpString,
                        mInitialTextColorState, biometricSourceType);
                        getInitialTextColorState(), biometricSourceType);
            } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) {
                    showBiometricMessage(
@@ -1655,7 +1693,7 @@ public class KeyguardIndicationController {
    private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg,
            BiometricSourceType biometricSourceType) {
        if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
            mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState,
            mStatusBarKeyguardViewManager.setKeyguardMessage(errString, getInitialTextColorState(),
                    biometricSourceType);
        } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
            showBiometricMessage(errString, followUpMsg, biometricSourceType);
+17 −3
Original line number Diff line number Diff line
@@ -26,24 +26,31 @@ import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.StyleRes;
import androidx.core.graphics.ColorUtils;

import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Flags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.res.R;
import com.android.systemui.shared.shadow.DoubleShadowTextView;

/**
 * A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
 */
public class KeyguardIndicationTextView extends TextView {
public class KeyguardIndicationTextView extends DoubleShadowTextView {
    // Minimum luminance for texts to receive shadows.
    private static final float MIN_TEXT_SHADOW_LUMINANCE = 0.5f;
    public static final long Y_IN_DURATION = 600L;

    @StyleRes
    private static int sStyleId = R.style.TextAppearance_Keyguard_BottomArea;
    @StyleRes
    private static int sStyleWithDoubleShadowTextId =
            R.style.TextAppearance_Keyguard_BottomArea_DoubleShadow;
    @StyleRes
    private static int sButtonStyleId = R.style.TextAppearance_Keyguard_BottomArea_Button;

    private boolean mAnimationsEnabled = true;
@@ -225,9 +232,16 @@ public class KeyguardIndicationTextView extends TextView {
            // If a background is set on the text, we don't want shadow on the text
            if (mKeyguardIndicationInfo.getBackground() != null) {
                setTextAppearance(sButtonStyleId);
            } else {
                // If text is transparent or dark color, don't draw any shadow
                if (Flags.indicationTextA11yFix() && ColorUtils.calculateLuminance(
                        mKeyguardIndicationInfo.getTextColor().getDefaultColor())
                        > MIN_TEXT_SHADOW_LUMINANCE) {
                    setTextAppearance(sStyleWithDoubleShadowTextId);
                } else {
                    setTextAppearance(sStyleId);
                }
            }
            setBackground(mKeyguardIndicationInfo.getBackground());
            setTextColor(mKeyguardIndicationInfo.getTextColor());
            setOnClickListener(mKeyguardIndicationInfo.getClickListener());