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

Commit 91cc1994 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Add a CurrentTilesInteractor" into udc-dev

parents 418fba96 8134ebff
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -26,8 +26,6 @@ import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository;
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.util.leak.GarbageMonitor;

import java.util.ArrayList;
@@ -35,7 +33,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public interface QSHost extends PanelInteractor, CustomTileAddedRepository {
public interface QSHost {
    String TILES_SETTING = Settings.Secure.QS_TILES;
    int POSITION_AT_END = -1;

@@ -75,7 +73,11 @@ public interface QSHost extends PanelInteractor, CustomTileAddedRepository {
     * @see QSFactory#createTileView
     */
    QSTileView createTileView(Context themedContext, QSTile tile, boolean collapsedView);
    /** Create a {@link QSTile} of a {@code tileSpec} type. */
    /** Create a {@link QSTile} of a {@code tileSpec} type.
     *
     * This should only be called by classes that need to create one-off instances of tiles.
     * Do not use to create {@code custom} tiles without explicitly taking care of its lifecycle.
     */
    QSTile createTile(String tileSpec);

    /**
+226 −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.qs

import android.content.ComponentName
import android.content.Context
import androidx.annotation.GuardedBy
import com.android.internal.logging.InstanceId
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.qs.QSTileView
import com.android.systemui.qs.external.TileServiceRequestController
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

/**
 * Adapter to determine what real class to use for classes that depend on [QSHost].
 *
 * * When [Flags.QS_PIPELINE_NEW_HOST] is off, all calls will be routed to [QSTileHost].
 * * When [Flags.QS_PIPELINE_NEW_HOST] is on, calls regarding the current set of tiles will be
 *   routed to [CurrentTilesInteractor]. Other calls (like [warn]) will still be routed to
 *   [QSTileHost].
 *
 * This routing also includes dumps.
 */
@SysUISingleton
class QSHostAdapter
@Inject
constructor(
    private val qsTileHost: QSTileHost,
    private val interactor: CurrentTilesInteractor,
    private val context: Context,
    private val tileServiceRequestControllerBuilder: TileServiceRequestController.Builder,
    @Application private val scope: CoroutineScope,
    private val featureFlags: FeatureFlags,
    dumpManager: DumpManager,
) : QSHost {

    companion object {
        private const val TAG = "QSTileHost"
    }

    private val useNewHost = featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)

    @GuardedBy("callbacksMap") private val callbacksMap = mutableMapOf<QSHost.Callback, Job>()

    init {
        scope.launch { tileServiceRequestControllerBuilder.create(this@QSHostAdapter).init() }
        // Redirect dump to the correct host (needed for CTS tests)
        dumpManager.registerCriticalDumpable(
            TAG,
            if (useNewHost) interactor else qsTileHost
        )
    }

    override fun getTiles(): Collection<QSTile> {
        return if (useNewHost) {
            interactor.currentQSTiles
        } else {
            qsTileHost.getTiles()
        }
    }

    override fun getSpecs(): List<String> {
        return if (useNewHost) {
            interactor.currentTilesSpecs.map { it.spec }
        } else {
            qsTileHost.getSpecs()
        }
    }

    override fun removeTile(spec: String) {
        if (useNewHost) {
            interactor.removeTiles(listOf(TileSpec.create(spec)))
        } else {
            qsTileHost.removeTile(spec)
        }
    }

    override fun addCallback(callback: QSHost.Callback) {
        if (useNewHost) {
            val job =
                scope.launch {
                    interactor.currentTiles.collect { callback.onTilesChanged() }
                }
            synchronized(callbacksMap) { callbacksMap.put(callback, job) }
        } else {
            qsTileHost.addCallback(callback)
        }
    }

    override fun removeCallback(callback: QSHost.Callback) {
        if (useNewHost) {
            synchronized(callbacksMap) { callbacksMap.get(callback)?.cancel() }
        } else {
            qsTileHost.removeCallback(callback)
        }
    }

    override fun removeTiles(specs: Collection<String>) {
        if (useNewHost) {
            interactor.removeTiles(specs.map(TileSpec::create))
        } else {
            qsTileHost.removeTiles(specs)
        }
    }

    override fun removeTileByUser(component: ComponentName) {
        if (useNewHost) {
            interactor.removeTiles(listOf(TileSpec.create(component)))
        } else {
            qsTileHost.removeTileByUser(component)
        }
    }

    override fun addTile(spec: String, position: Int) {
        if (useNewHost) {
            interactor.addTile(TileSpec.create(spec), position)
        } else {
            qsTileHost.addTile(spec, position)
        }
    }

    override fun addTile(component: ComponentName, end: Boolean) {
        if (useNewHost) {
            interactor.addTile(
                TileSpec.create(component),
                if (end) POSITION_AT_END else 0
            )
        } else {
            qsTileHost.addTile(component, end)
        }
    }

    override fun changeTilesByUser(previousTiles: List<String>, newTiles: List<String>) {
        if (useNewHost) {
            interactor.setTiles(newTiles.map(TileSpec::create))
        } else {
            qsTileHost.changeTilesByUser(previousTiles, newTiles)
        }
    }

    override fun warn(message: String?, t: Throwable?) {
        qsTileHost.warn(message, t)
    }

    override fun getContext(): Context {
        return if (useNewHost) {
            context
        } else {
            qsTileHost.context
        }
    }

    override fun getUserContext(): Context {
        return if (useNewHost) {
            interactor.userContext.value
        } else {
            qsTileHost.userContext
        }
    }

    override fun getUserId(): Int {
        return if (useNewHost) {
            interactor.userId.value
        } else {
            qsTileHost.userId
        }
    }

    override fun getUiEventLogger(): UiEventLogger {
        return qsTileHost.uiEventLogger
    }

    override fun createTileView(
        themedContext: Context?,
        tile: QSTile?,
        collapsedView: Boolean
    ): QSTileView {
        return qsTileHost.createTileView(themedContext, tile, collapsedView)
    }

    override fun createTile(tileSpec: String): QSTile? {
        return qsTileHost.createTile(tileSpec)
    }

    override fun addTile(spec: String) {
        return addTile(spec, QSHost.POSITION_AT_END)
    }

    override fun addTile(tile: ComponentName) {
        return addTile(tile, false)
    }

    override fun indexOf(tileSpec: String): Int {
        return specs.indexOf(tileSpec)
    }

    override fun getNewInstanceId(): InstanceId {
        return qsTileHost.newInstanceId
    }
}
+15 −14
Original line number Diff line number Diff line
@@ -37,8 +37,9 @@ import com.android.systemui.ProtoDumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.nano.SystemUIProtoDump;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.qs.QSFactory;
@@ -48,9 +49,10 @@ import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.external.CustomTileStatePersister;
import com.android.systemui.qs.external.TileLifecycleManager;
import com.android.systemui.qs.external.TileServiceKey;
import com.android.systemui.qs.external.TileServiceRequestController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.nano.QsTileState;
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository;
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.settings.UserFileManager;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.AutoTileManager;
@@ -85,7 +87,8 @@ import javax.inject.Provider;
 * This class also provides the interface for adding/removing/changing tiles.
 */
@SysUISingleton
public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, ProtoDumpable {
public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, ProtoDumpable,
        PanelInteractor, CustomTileAddedRepository {
    private static final String TAG = "QSTileHost";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    private static final int MAX_QS_INSTANCE_ID = 1 << 20;
@@ -99,7 +102,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
    private final ArrayList<String> mTileSpecs = new ArrayList<>();
    private final TunerService mTunerService;
    private final PluginManager mPluginManager;
    private final DumpManager mDumpManager;
    private final QSLogger mQSLogger;
    private final UiEventLogger mUiEventLogger;
    private final InstanceIdSequence mInstanceIdSequence;
@@ -122,9 +124,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
    // This is enforced by only cleaning the flag at the end of a successful run of #onTuningChanged
    private boolean mTilesListDirty = true;

    private final TileServiceRequestController mTileServiceRequestController;
    private TileLifecycleManager.Factory mTileLifeCycleManagerFactory;

    private final FeatureFlags mFeatureFlags;

    @Inject
    public QSTileHost(Context context,
            QSFactory defaultFactory,
@@ -132,35 +135,32 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
            PluginManager pluginManager,
            TunerService tunerService,
            Provider<AutoTileManager> autoTiles,
            DumpManager dumpManager,
            Optional<CentralSurfaces> centralSurfacesOptional,
            QSLogger qsLogger,
            UiEventLogger uiEventLogger,
            UserTracker userTracker,
            SecureSettings secureSettings,
            CustomTileStatePersister customTileStatePersister,
            TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
            TileLifecycleManager.Factory tileLifecycleManagerFactory,
            UserFileManager userFileManager
            UserFileManager userFileManager,
            FeatureFlags featureFlags
    ) {
        mContext = context;
        mUserContext = context;
        mTunerService = tunerService;
        mPluginManager = pluginManager;
        mDumpManager = dumpManager;
        mQSLogger = qsLogger;
        mUiEventLogger = uiEventLogger;
        mMainExecutor = mainExecutor;
        mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this);
        mTileLifeCycleManagerFactory = tileLifecycleManagerFactory;
        mUserFileManager = userFileManager;
        mFeatureFlags = featureFlags;

        mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID);
        mCentralSurfacesOptional = centralSurfacesOptional;

        mQsFactories.add(defaultFactory);
        pluginManager.addPluginListener(this, QSFactory.class, true);
        mDumpManager.registerDumpable(TAG, this);
        mUserTracker = userTracker;
        mSecureSettings = secureSettings;
        mCustomTileStatePersister = customTileStatePersister;
@@ -172,7 +172,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
            tunerService.addTunable(this, TILES_SETTING);
            // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
            mAutoTiles = autoTiles.get();
            mTileServiceRequestController.init();
        });
    }

@@ -186,8 +185,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
        mAutoTiles.destroy();
        mTunerService.removeTunable(this);
        mPluginManager.removePluginListener(this);
        mDumpManager.unregisterDumpable(TAG);
        mTileServiceRequestController.destroy();
    }

    @Override
@@ -300,6 +297,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
        if (!TILES_SETTING.equals(key)) {
            return;
        }
        // Do not process tiles if the flag is enabled.
        if (mFeatureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
            return;
        }
        if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) {
            newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
        }
+4 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.qs.dagger
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QSHostAdapter
import com.android.systemui.qs.QSTileHost
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedSharedPrefsRepository
@@ -31,7 +32,7 @@ import dagger.Provides
@Module
interface QSHostModule {

    @Binds fun provideQsHost(controllerImpl: QSTileHost): QSHost
    @Binds fun provideQsHost(controllerImpl: QSHostAdapter): QSHost

    @Module
    companion object {
@@ -39,7 +40,7 @@ interface QSHostModule {
        @JvmStatic
        fun providePanelInteractor(
            featureFlags: FeatureFlags,
            qsHost: QSHost,
            qsHost: QSTileHost,
            panelInteractorImpl: PanelInteractorImpl
        ): PanelInteractor {
            return if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
@@ -53,7 +54,7 @@ interface QSHostModule {
        @JvmStatic
        fun provideCustomTileAddedRepository(
            featureFlags: FeatureFlags,
            qsHost: QSHost,
            qsHost: QSTileHost,
            customTileAddedRepository: CustomTileAddedSharedPrefsRepository
        ): CustomTileAddedRepository {
            return if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import com.android.systemui.log.LogBufferFactory
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecSettingsRepository
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractorImpl
import com.android.systemui.qs.pipeline.prototyping.PrototypeCoreStartable
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import dagger.Binds
@@ -37,6 +39,11 @@ abstract class QSPipelineModule {
    @Binds
    abstract fun provideTileSpecRepository(impl: TileSpecSettingsRepository): TileSpecRepository

    @Binds
    abstract fun bindCurrentTilesInteractor(
        impl: CurrentTilesInteractorImpl
    ): CurrentTilesInteractor

    @Binds
    @IntoMap
    @ClassKey(PrototypeCoreStartable::class)
Loading