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

Commit bbc7ae07 authored by Helen Cheuk's avatar Helen Cheuk Committed by Android (Google) Code Review
Browse files

Merge "[Contextual Edu] Accessibility - Not change focus when...

Merge "[Contextual Edu] Accessibility - Not change focus when ContextualEduDialog is shown" into main
parents 4e1317ff 06444312
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.education.domain.ui.view

import android.testing.TestableLooper
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityManager
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.activity.EmptyTestActivity
import com.android.systemui.education.ui.view.ContextualEduDialog
import com.android.systemui.education.ui.viewmodel.ContextualEduToastViewModel
import kotlin.test.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.firstValue
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ContextualEduDialogTest : SysuiTestCase() {
    @Rule
    @JvmField
    val activityRule: ActivityScenarioRule<EmptyTestActivity> =
        ActivityScenarioRule(EmptyTestActivity::class.java)
    @get:Rule val mockitoRule = MockitoJUnit.rule()

    @Mock private lateinit var accessibilityManager: AccessibilityManager
    private lateinit var underTest: ContextualEduDialog

    @Before
    fun setUp() {
        whenever(accessibilityManager.isEnabled).thenReturn(true)
    }

    @Test
    fun sendAccessibilityInfo() {
        val message = "Testing message"
        val viewModel = ContextualEduToastViewModel(message, icon = 0, userId = 0)
        activityRule.scenario.onActivity {
            underTest = ContextualEduDialog(context, viewModel, accessibilityManager)
            underTest.show()
        }

        val eventCaptor = ArgumentCaptor.forClass(AccessibilityEvent::class.java)
        verify(accessibilityManager).sendAccessibilityEvent(eventCaptor.capture())
        assertEquals(message, eventCaptor.firstValue.text[0])
    }
}
+28 −2
Original line number Diff line number Diff line
@@ -22,13 +22,18 @@ import android.os.Bundle
import android.view.Gravity
import android.view.Window
import android.view.WindowManager
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityManager
import android.widget.ImageView
import android.widget.TextView
import com.android.systemui.education.ui.viewmodel.ContextualEduToastViewModel
import com.android.systemui.res.R

class ContextualEduDialog(context: Context, private val model: ContextualEduToastViewModel) :
    Dialog(context) {
class ContextualEduDialog(
    context: Context,
    private val model: ContextualEduToastViewModel,
    private val accessibilityManager: AccessibilityManager,
) : Dialog(context) {
    override fun onCreate(savedInstanceState: Bundle?) {
        setUpWindowProperties()
        setWindowPosition()
@@ -36,6 +41,7 @@ class ContextualEduDialog(context: Context, private val model: ContextualEduToas
        window?.setTitle(context.getString(R.string.contextual_education_dialog_title))
        setContentView(R.layout.contextual_edu_dialog)
        setContent()
        sendAccessibilityEvent()
        super.onCreate(savedInstanceState)
    }

@@ -44,10 +50,30 @@ class ContextualEduDialog(context: Context, private val model: ContextualEduToas
        findViewById<ImageView>(R.id.edu_icon)?.let { it.setImageResource(model.icon) }
    }

    private fun sendAccessibilityEvent() {
        if (!accessibilityManager.isEnabled) {
            return
        }

        // It is a toast-like dialog which is unobtrusive and not focusable. So it needs to call
        // accessibilityManager.sendAccessibilityEvent explicitly to announce the message.
        accessibilityManager.sendAccessibilityEvent(
            AccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT).apply {
                text.add(model.message)
            }
        )
    }

    private fun setUpWindowProperties() {
        window?.apply {
            requestFeature(Window.FEATURE_NO_TITLE)
            setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG)
            // NOT_TOUCH_MODAL allows users to interact with background elements and NOT_FOCUSABLE
            // avoids changing the existing focus when dialog is shown.
            addFlags(
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            )
            clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
            setBackgroundDrawableResource(android.R.color.transparent)
        }
+3 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.UserHandle
import android.view.accessibility.AccessibilityManager
import androidx.core.app.NotificationCompat
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
@@ -64,12 +65,13 @@ constructor(
        context: Context,
        viewModel: ContextualEduViewModel,
        notificationManager: NotificationManager,
        accessibilityManager: AccessibilityManager,
    ) : this(
        applicationScope,
        viewModel,
        context,
        notificationManager,
        createDialog = { model -> ContextualEduDialog(context, model) },
        createDialog = { model -> ContextualEduDialog(context, model, accessibilityManager) },
    )

    var dialog: Dialog? = null