Loading packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduDialogTest.kt 0 → 100644 +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]) } } packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt +28 −2 Original line number Diff line number Diff line Loading @@ -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() Loading @@ -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) } Loading @@ -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) } Loading packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduDialogTest.kt 0 → 100644 +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]) } }
packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt +28 −2 Original line number Diff line number Diff line Loading @@ -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() Loading @@ -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) } Loading @@ -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) } Loading
packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading