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

Commit ada6afab authored by helencheuk's avatar helencheuk
Browse files

[Contextual Edu] Change Toast to Dialog

The default style toast is obscured by taskbar in overivew. Toast does not support changing of position or customizing view anymore after Android 11.
This CL changes the displayed component from Toast to Dialog and moves up the dialog with configured bottom margin.
It also faciliates future change to customize the dialog in b/369791926

Bug: 369800039
Test: ContextualEduUiCoordinatorTest
Flag: com.android.systemui.keyboard_touchpad_contextual_education

Change-Id: Idf1c5642d2561fb608824ffd3d1baed214fde828
parent c38c0e4f
Loading
Loading
Loading
Loading
+26 −8
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@

package com.android.systemui.education.domain.ui.view

import android.app.Dialog
import android.app.Notification
import android.app.NotificationManager
import android.content.applicationContext
import android.widget.Toast
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -34,11 +34,13 @@ import com.android.systemui.education.ui.viewmodel.ContextualEduViewModel
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -51,6 +53,7 @@ import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -63,10 +66,12 @@ class ContextualEduUiCoordinatorTest : SysuiTestCase() {
    private val minDurationForNextEdu =
        KeyboardTouchpadEduInteractor.minIntervalBetweenEdu + 1.seconds
    private lateinit var underTest: ContextualEduUiCoordinator
    @Mock private lateinit var toast: Toast
    @Mock private lateinit var dialog: Dialog
    @Mock private lateinit var notificationManager: NotificationManager
    @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
    @get:Rule val mockitoRule = MockitoJUnit.rule()
    private var toastContent = ""
    private val timeoutMillis = 3500L

    @Before
    fun setUp() {
@@ -75,30 +80,35 @@ class ContextualEduUiCoordinatorTest : SysuiTestCase() {
            interactor.updateTouchpadFirstConnectionTime()
        }

        whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any()))
            .thenReturn(timeoutMillis.toInt())

        val viewModel =
            ContextualEduViewModel(
                kosmos.applicationContext.resources,
                kosmos.keyboardTouchpadEduInteractor
                kosmos.keyboardTouchpadEduInteractor,
                accessibilityManagerWrapper,
            )

        underTest =
            ContextualEduUiCoordinator(
                kosmos.applicationCoroutineScope,
                viewModel,
                kosmos.applicationContext,
                notificationManager
            ) { content ->
                toastContent = content
                toast
            ) { model ->
                toastContent = model.message
                dialog
            }
        underTest.start()
        kosmos.keyboardTouchpadEduInteractor.start()
    }

    @Test
    fun showToastOnNewEdu() =
    fun showDialogOnNewEdu() =
        testScope.runTest {
            triggerEducation(BACK)
            verify(toast).show()
            verify(dialog).show()
        }

    @Test
@@ -110,6 +120,14 @@ class ContextualEduUiCoordinatorTest : SysuiTestCase() {
            verify(notificationManager).notifyAsUser(any(), anyInt(), any(), any())
        }

    @Test
    fun dismissDialogAfterTimeout() =
        testScope.runTest {
            triggerEducation(BACK)
            advanceTimeBy(timeoutMillis + 1)
            verify(dialog).dismiss()
        }

    @Test
    fun verifyBackEduToastContent() =
        testScope.runTest {
+2 −0
Original line number Diff line number Diff line
@@ -2039,4 +2039,6 @@
    <!-- SliceView icon size -->
    <dimen name="abc_slice_big_pic_min_height">64dp</dimen>
    <dimen name="abc_slice_big_pic_max_height">64dp</dimen>

    <dimen name="contextual_edu_dialog_bottom_margin">70dp</dimen>
</resources>
+2 −0
Original line number Diff line number Diff line
@@ -3784,6 +3784,8 @@ Action + ESC for this.</string>
    <!-- Main text of the one line view of a redacted notification -->
    <string name="redacted_notification_single_line_text">Unlock to view</string>

    <!-- Content description for contextual education dialog [CHAR LIMIT=NONE] -->
    <string name="contextual_education_dialog_title">Contextual education</string>
    <!-- Education notification title for Back [CHAR_LIMIT=100] -->
    <string name="back_edu_notification_title">Use your touchpad to go back</string>
    <!-- Education notification text for Back [CHAR_LIMIT=100] -->
+6 −0
Original line number Diff line number Diff line
@@ -1720,4 +1720,10 @@
    <style name="ShortcutHelperTheme" parent="@style/ShortcutHelperThemeCommon">
        <item name="android:windowLightNavigationBar">true</item>
    </style>

    <style name="ContextualEduDialog" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
        <!-- To make the dialog wrap to content when the education text is short -->
        <item name="windowMinWidthMajor">0%</item>
        <item name="windowMinWidthMinor">0%</item>
    </style>
</resources>
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright 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.ui.view

import android.app.AlertDialog
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.WindowManager
import android.widget.ToastPresenter
import com.android.systemui.education.ui.viewmodel.ContextualEduToastViewModel
import com.android.systemui.res.R

class ContextualEduDialog(context: Context, private val model: ContextualEduToastViewModel) :
    AlertDialog(context, R.style.ContextualEduDialog) {
    override fun onCreate(savedInstanceState: Bundle?) {
        setUpWindowProperties()
        setWindowPosition()
        // title is used for a11y announcement
        window?.setTitle(context.getString(R.string.contextual_education_dialog_title))
        // TODO: b/369791926 - replace the below toast view with a custom dialog view
        val toastView = ToastPresenter.getTextToastView(context, model.message)
        setView(toastView)
        super.onCreate(savedInstanceState)
    }

    private fun setUpWindowProperties() {
        window?.apply {
            setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG)
            clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
        }
        setCanceledOnTouchOutside(false)
    }

    private fun setWindowPosition() {
        window?.apply {
            setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
            this.attributes =
                WindowManager.LayoutParams().apply {
                    width = WindowManager.LayoutParams.WRAP_CONTENT
                    height = WindowManager.LayoutParams.WRAP_CONTENT
                    copyFrom(attributes)
                    y =
                        context.resources.getDimensionPixelSize(
                            R.dimen.contextual_edu_dialog_bottom_margin
                        )
                }
        }
    }
}
Loading