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

Commit 07b7d227 authored by Fabián Kozynski's avatar Fabián Kozynski Committed by Fabian Kozynski
Browse files

Adds Retail mode repository

If the device is in retail mode, tiles are set to a different list and
cannot be edited.

Fixes: 277776030
Test: manual, device in demo mode
Test: atest TileSpecSettingsRepositoryTest
Test: atest RetailModeSettingsRepositoryTest
Test: atest QSFooterViewControllerTest
Change-Id: Ie3102bab7f658482ee4b128ec0689f19f69c1945
parent 01b56bb0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ import com.android.systemui.qs.FgsManagerControllerImpl;
import com.android.systemui.qs.QSFragmentStartableModule;
import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.retail.dagger.RetailModeModule;
import com.android.systemui.screenrecord.ScreenRecordModule;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.security.data.repository.SecurityRepositoryModule;
@@ -170,6 +171,7 @@ import javax.inject.Named;
            PrivacyModule.class,
            QRCodeScannerModule.class,
            QSFragmentStartableModule.class,
            RetailModeModule.class,
            ScreenshotModule.class,
            SensorModule.class,
            SecurityRepositoryModule.class,
+8 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.retail.domain.interactor.RetailModeInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.ViewController;

@@ -45,18 +46,22 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
    private final View mEditButton;
    private final FalsingManager mFalsingManager;
    private final ActivityStarter mActivityStarter;
    private final RetailModeInteractor mRetailModeInteractor;

    @Inject
    QSFooterViewController(QSFooterView view,
            UserTracker userTracker,
            FalsingManager falsingManager,
            ActivityStarter activityStarter,
            QSPanelController qsPanelController) {
            QSPanelController qsPanelController,
            RetailModeInteractor retailModeInteractor
    ) {
        super(view);
        mUserTracker = userTracker;
        mQsPanelController = qsPanelController;
        mFalsingManager = falsingManager;
        mActivityStarter = activityStarter;
        mRetailModeInteractor = retailModeInteractor;

        mBuildText = mView.findViewById(R.id.build);
        mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
@@ -96,6 +101,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
    @Override
    public void setVisibility(int visibility) {
        mView.setVisibility(visibility);
        mEditButton
                .setVisibility(mRetailModeInteractor.isInRetailMode() ? View.GONE : View.VISIBLE);
        mEditButton.setClickable(visibility == View.VISIBLE);
    }

+34 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.UserIdInt
import android.content.res.Resources
import android.database.ContentObserver
import android.provider.Settings
import com.android.systemui.R
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -27,12 +28,16 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import com.android.systemui.retail.data.repository.RetailModeRepository
import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -84,6 +89,9 @@ interface TileSpecRepository {
 * [Settings.Secure.QS_TILES].
 *
 * All operations against [Settings] will be performed in a background thread.
 *
 * If the device is in retail mode, the tiles are fixed to the value of
 * [R.string.quick_settings_tiles_retail_mode].
 */
@SysUISingleton
class TileSpecSettingsRepository
@@ -92,9 +100,31 @@ constructor(
    private val secureSettings: SecureSettings,
    @Main private val resources: Resources,
    private val logger: QSPipelineLogger,
    private val retailModeRepository: RetailModeRepository,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) : TileSpecRepository {

    private val retailModeTiles by lazy {
        resources
            .getString(R.string.quick_settings_tiles_retail_mode)
            .split(DELIMITER)
            .map(TileSpec::create)
            .filter { it !is TileSpec.Invalid }
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    override fun tilesSpecs(userId: Int): Flow<List<TileSpec>> {
        return retailModeRepository.retailMode.flatMapLatest { inRetailMode ->
            if (inRetailMode) {
                logger.logUsingRetailTiles()
                flowOf(retailModeTiles)
            } else {
                settingsTiles(userId)
            }
        }
    }

    private fun settingsTiles(userId: Int): Flow<List<TileSpec>> {
        return conflatedCallbackFlow {
                val observer =
                    object : ContentObserver(null) {
@@ -157,6 +187,10 @@ constructor(
    }

    private suspend fun storeTiles(@UserIdInt forUser: Int, tiles: List<TileSpec>) {
        if (retailModeRepository.inRetailMode) {
            // No storing tiles when in retail mode
            return
        }
        val toStore =
            tiles
                .filter { it !is TileSpec.Invalid }
+4 −0
Original line number Diff line number Diff line
@@ -120,6 +120,10 @@ constructor(
        )
    }

    fun logUsingRetailTiles() {
        tileListLogBuffer.log(TILE_LIST_TAG, LogLevel.DEBUG, {}, { "Using retail tiles" })
    }

    /** Reasons for destroying an existing tile. */
    enum class TileDestroyedReason(val readable: String) {
        TILE_REMOVED("Tile removed from  current set"),
+34 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.retail.dagger

import com.android.systemui.retail.data.repository.RetailModeRepository
import com.android.systemui.retail.data.repository.RetailModeSettingsRepository
import com.android.systemui.retail.domain.interactor.RetailModeInteractor
import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl
import dagger.Binds
import dagger.Module

@Module
abstract class RetailModeModule {

    @Binds
    abstract fun bindsRetailModeRepository(impl: RetailModeSettingsRepository): RetailModeRepository

    @Binds
    abstract fun bindsRetailModeInteractor(impl: RetailModeInteractorImpl): RetailModeInteractor
}
Loading