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

Commit 8cbb0df3 authored by Casey Burkhardt's avatar Casey Burkhardt Committed by Android (Google) Code Review
Browse files

Merge "Adds an accessibility live region to the camera/mic privacy chip" into main

parents d80cd594 ef2b5956
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -155,3 +155,13 @@ flag {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "privacy_dot_live_region"
    namespace: "accessibility"
    description: "Exposes the status bar privacy dot as a live region so it is announced when it appears."
    bug: "197201744"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -2923,7 +2923,7 @@
    <string name="ongoing_privacy_dialog_a11y_title">In use</string>

    <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
    <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
    <string name="ongoing_privacy_chip_content_multiple_apps"><xliff:g id="types_list" example="camera, location">%s</xliff:g> in use.</string>

    <!-- Separator for types. Include spaces before and after if needed [CHAR LIMIT=10] -->
    <string name="ongoing_privacy_dialog_separator">,\u0020</string>
+39 −23
Original line number Diff line number Diff line
@@ -23,18 +23,23 @@ import android.view.Gravity.END
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import com.android.settingslib.Utils
import com.android.systemui.Flags
import com.android.systemui.res.R
import com.android.systemui.statusbar.events.BackgroundAnimatableView
import java.time.Duration

class OngoingPrivacyChip @JvmOverloads constructor(
class OngoingPrivacyChip
@JvmOverloads
constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttrs: Int = 0,
    defStyleRes: Int = 0
    defStyleRes: Int = 0,
) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView {

    private var configuration: Configuration
@@ -64,15 +69,22 @@ class OngoingPrivacyChip @JvmOverloads constructor(
    }

    /**
     * When animating as a chip in the status bar, we want to animate the width for the container
     * of the privacy items. We have to subtract our own top and left offset because the bounds
     * come to us as absolute on-screen bounds, and `iconsContainer` is laid out relative to the
     * frame layout's bounds.
     * When animating as a chip in the status bar, we want to animate the width for the container of
     * the privacy items. We have to subtract our own top and left offset because the bounds come to
     * us as absolute on-screen bounds, and `iconsContainer` is laid out relative to the frame
     * layout's bounds.
     */
    override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
        iconsContainer.setLeftTopRightBottom(l - left, t - top, r - left, b - top)
    }

    override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo) {
        super.onInitializeAccessibilityNodeInfo(info)
        if (Flags.privacyDotLiveRegion()) {
            info.setMinDurationBetweenContentChanges(Duration.ofSeconds(10L))
        }
    }

    // Should only be called if the builder icons or app changed
    private fun updateView(builder: PrivacyChipBuilder) {
        fun setIcons(chipBuilder: PrivacyChipBuilder, iconsContainer: ViewGroup) {
@@ -80,7 +92,8 @@ class OngoingPrivacyChip @JvmOverloads constructor(
            chipBuilder.generateIcons().forEachIndexed { i, it ->
                it.mutate()
                it.setTint(iconColor)
                val image = ImageView(context).apply {
                val image =
                    ImageView(context).apply {
                        setImageDrawable(it)
                        scaleType = ImageView.ScaleType.CENTER_INSIDE
                    }
@@ -92,11 +105,16 @@ class OngoingPrivacyChip @JvmOverloads constructor(
                }
            }
        }

        if (!privacyList.isEmpty()) {
            if (Flags.privacyDotLiveRegion()) {
                accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_POLITE
            }
            generateContentDescription(builder)
            setIcons(builder, iconsContainer)
        } else {
            if (Flags.privacyDotLiveRegion()) {
                accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_NONE
            }
            iconsContainer.removeAllViews()
        }
        requestLayout()
@@ -104,8 +122,8 @@ class OngoingPrivacyChip @JvmOverloads constructor(

    private fun generateContentDescription(builder: PrivacyChipBuilder) {
        val typesText = builder.joinTypes()
        contentDescription = context.getString(
                R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
        contentDescription =
            context.getString(R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
    }

    override fun onConfigurationChanged(newConfig: Configuration?) {
@@ -120,17 +138,15 @@ class OngoingPrivacyChip @JvmOverloads constructor(
    }

    private fun updateResources() {
        iconMargin = context.resources
                .getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
        iconSize = context.resources
                .getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
        iconMargin =
            context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
        iconSize = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
        iconColor =
            Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)

        val height = context.resources
                .getDimensionPixelSize(R.dimen.ongoing_appops_chip_height)
        val padding = context.resources
                .getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
        val height = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_height)
        val padding =
            context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
        iconsContainer.layoutParams.height = height
        iconsContainer.setPaddingRelative(padding, 0, padding, 0)
        iconsContainer.background = context.getDrawable(R.drawable.statusbar_privacy_chip_bg)