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

Commit f286ff4a authored by Olivier St-Onge's avatar Olivier St-Onge Committed by Android (Google) Code Review
Browse files

Merge "Add tooltip for QS edit button" into main

parents 4e1002ff 1e549f62
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1042,6 +1042,16 @@ flag {
    bug: "325099249"
}

flag {
    name: "qs_edit_mode_tooltip"
    namespace: "systemui"
    description: "Displays an educational tooltip on the edit mode icon from the expanded shade. This flag depends on qs_ui_refactor_compose_fragment flag."
    bug: "403596182"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
  name: "remove_dream_overlay_hide_on_touch"
  namespace: "systemui"
+47 −12
Original line number Diff line number Diff line
@@ -25,11 +25,12 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.fakeFalsingManager
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.plugins.activityStarter
import com.android.systemui.qs.panels.data.repository.qsPreferencesRepository
import com.android.systemui.qs.panels.ui.viewmodel.toolbar.EditModeButtonViewModel
import com.android.systemui.qs.panels.ui.viewmodel.toolbar.editModeButtonViewModelFactory
import com.android.systemui.testKosmos
@@ -46,7 +47,7 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@SmallTest
class EditModeButtonViewModelTest : SysuiTestCase() {
    val kosmos = testKosmos()
    val kosmos = testKosmos().useUnconfinedTestDispatcher()

    // NOTE: cannot instantiate EditModeButtonViewModel here because it would hydrate
    // showEditButton before the value on fakeHeadlessSystemUserMode is set
@@ -69,7 +70,6 @@ class EditModeButtonViewModelTest : SysuiTestCase() {
            fakeFalsingManager.setFalseTap(true)

            underTest.onButtonClick()
            runCurrent()

            assertThat(isEditing).isFalse()
        }
@@ -83,7 +83,6 @@ class EditModeButtonViewModelTest : SysuiTestCase() {
            fakeFalsingManager.setFalseTap(false)

            underTest.onButtonClick()
            runCurrent()

            assertThat(isEditing).isTrue()
        }
@@ -94,8 +93,6 @@ class EditModeButtonViewModelTest : SysuiTestCase() {
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel(false)

            runCurrent()

            assertThat(underTest.isEditButtonVisible).isTrue()
        }

@@ -105,8 +102,6 @@ class EditModeButtonViewModelTest : SysuiTestCase() {
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel(true)

            runCurrent()

            assertThat(underTest.isEditButtonVisible).isTrue()
        }

@@ -116,8 +111,6 @@ class EditModeButtonViewModelTest : SysuiTestCase() {
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel(false)

            runCurrent()

            assertThat(underTest.isEditButtonVisible).isTrue()
        }

@@ -127,11 +120,53 @@ class EditModeButtonViewModelTest : SysuiTestCase() {
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel(true)

            runCurrent()

            assertThat(underTest.isEditButtonVisible).isFalse()
        }

    @Test
    @EnableFlags(Flags.FLAG_QS_EDIT_MODE_TOOLTIP)
    fun showTooltip_tooltipWasAlreadyShown_shouldNotBeVisible() =
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel()
            qsPreferencesRepository.writeEditTooltipShown(true)

            assertThat(underTest.showTooltip).isFalse()
        }

    @Test
    @EnableFlags(Flags.FLAG_QS_EDIT_MODE_TOOLTIP)
    fun showTooltip_tooltipWasNotShown_shouldBeVisible() =
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel()
            qsPreferencesRepository.writeEditTooltipShown(false)

            assertThat(underTest.showTooltip).isTrue()
        }

    @Test
    @EnableFlags(Flags.FLAG_QS_EDIT_MODE_TOOLTIP)
    fun showTooltip_tooltipWasDismissed_shouldBeMarkedAsShown() =
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel()
            qsPreferencesRepository.writeEditTooltipShown(false)

            assertThat(underTest.showTooltip).isTrue()

            underTest.onTooltipDisposed()

            assertThat(underTest.showTooltip).isFalse()
        }

    @Test
    @DisableFlags(Flags.FLAG_QS_EDIT_MODE_TOOLTIP)
    fun showTooltip_flagDisabled_shouldNotBeVisible() =
        kosmos.runTest {
            val underTest = createEditModeButtonViewModel()
            qsPreferencesRepository.writeEditTooltipShown(false)

            assertThat(underTest.showTooltip).isFalse()
        }

    private fun Kosmos.createEditModeButtonViewModel(
        isHeadlessSystemUser: Boolean = false
    ): EditModeButtonViewModel {
+3 −0
Original line number Diff line number Diff line
@@ -2616,6 +2616,9 @@
    <!-- Title for QS Edit mode screen [CHAR LIMIT=30] -->
    <string name="qs_edit_tiles">Edit tiles</string>

    <!-- Tooltip for the edit mode button indicating that tiles can be resized [CHAR LIMIT=60] -->
    <string name="qs_edit_mode_tooltip">Resize Quick Settings tiles</string>

    <!-- SysUI Tuner: Options for how clock is displayed [CHAR LIMIT=NONE] -->
    <string name="tuner_time">Time</string>

+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.qs.flags

import com.android.systemui.Flags
import com.android.systemui.flags.RefactorFlagUtils

/** Object to help check if the QS edit mode tooltip is enabled. */
@Suppress("NOTHING_TO_INLINE")
object QSEditModeTooltip {
    /** The aconfig flag name */
    const val FLAG_NAME = Flags.FLAG_QS_EDIT_MODE_TOOLTIP

    /** Is the tooltip enabled */
    @JvmStatic
    inline val isEnabled
        get() = Flags.qsEditModeTooltip()

    /**
     * Called to ensure code is only run when the flag is enabled. This protects users from the
     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
     * build to ensure that the refactor author catches issues in testing.
     */
    @JvmStatic
    inline fun isUnexpectedlyInLegacyMode() =
        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)

    /**
     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
     * the flag is enabled to ensure that the refactor author catches issues in testing.
     */
    @JvmStatic
    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
}
+25 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.qs.panels.data.repository
import android.content.Context
import android.content.IntentFilter
import android.content.SharedPreferences
import androidx.core.content.edit
import com.android.systemui.backup.BackupHelper
import com.android.systemui.backup.BackupHelper.Companion.ACTION_RESTORE_FINISHED
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -26,6 +27,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.qs.flags.QSEditModeTooltip
import com.android.systemui.qs.panels.shared.model.PanelsLog
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.pipeline.shared.TilesUpgradePath
@@ -35,6 +37,7 @@ import com.android.systemui.util.kotlin.SharedPreferencesExt.observe
import com.android.systemui.util.kotlin.emitOnStart
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
@@ -43,6 +46,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach

/** Repository for QS user preferences. */
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class QSPreferencesRepository
@Inject
@@ -75,6 +79,17 @@ constructor(
            }
            .flowOn(backgroundDispatcher)

    /** Whether or not the edit icon tooltip was shown for the current user. */
    val editTooltipShown: Flow<Boolean> =
        combine(backupRestorationEvents, userRepository.selectedUserInfo, ::Pair)
            .flatMapLatest { (_, userInfo) ->
                val prefs = getSharedPrefs(userInfo.id)
                prefs.observe().emitOnStart().map {
                    prefs.getBoolean(EDIT_TOOLTIP_SHOWN_KEY, false)
                }
            }
            .flowOn(backgroundDispatcher)

    /** Sets for the current user the set of [TileSpec] to display as large tiles. */
    fun writeLargeTileSpecs(specs: Set<TileSpec>) {
        with(getSharedPrefs(userRepository.getSelectedUserInfo().id)) {
@@ -92,6 +107,15 @@ constructor(
        }
    }

    /** Sets the value for whether or not the edit icon tooltip was shown for the current user. */
    fun writeEditTooltipShown(value: Boolean) {
        if (QSEditModeTooltip.isEnabled) {
            getSharedPrefs(userRepository.getSelectedUserInfo().id).edit {
                putBoolean(EDIT_TOOLTIP_SHOWN_KEY, value)
            }
        }
    }

    suspend fun deleteLargeTileDataJob() {
        userRepository.selectedUserInfo.collect { userInfo ->
            getSharedPrefs(userInfo.id)
@@ -174,6 +198,7 @@ constructor(
        private const val TAG = "QSPreferencesRepository"
        private const val LARGE_TILES_SPECS_KEY = "large_tiles_specs"
        private const val LARGE_TILES_DEFAULT_KEY = "large_tiles_default"
        private const val EDIT_TOOLTIP_SHOWN_KEY = "edit_tooltip_shown"
        const val FILE_NAME = "quick_settings_prefs"
    }
}
Loading