Add AutoAddables
AutoAddable encapsulates a particular tile that can be auto-added to Quick Settings and the triggers needed for it. Test: atest com.android.systemui.qs.pipeline.interactor.autoaddable Bug: 278577795 Change-Id: I99d3856c2b71a8604c586e8b6df2306e726168e9
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.dagger
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.AutoAddableSetting
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.AutoAddableSettingList
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.CastAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.DataSaverAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.DeviceControlsAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.HotspotAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.NightDisplayAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.ReduceBrightColorsAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.WalletAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.WorkTileAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.multibindings.ElementsIntoSet
|
||||||
|
import dagger.multibindings.IntoSet
|
||||||
|
|
||||||
|
@Module
|
||||||
|
interface BaseAutoAddableModule {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Provides
|
||||||
|
@ElementsIntoSet
|
||||||
|
fun providesAutoAddableSetting(
|
||||||
|
@Main resources: Resources,
|
||||||
|
autoAddableSettingFactory: AutoAddableSetting.Factory
|
||||||
|
): Set<AutoAddable> {
|
||||||
|
return AutoAddableSettingList.parseSettingsResource(
|
||||||
|
resources,
|
||||||
|
autoAddableSettingFactory
|
||||||
|
)
|
||||||
|
.toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Binds @IntoSet fun bindCastAutoAddable(impl: CastAutoAddable): AutoAddable
|
||||||
|
|
||||||
|
@Binds @IntoSet fun bindDataSaverAutoAddable(impl: DataSaverAutoAddable): AutoAddable
|
||||||
|
|
||||||
|
@Binds @IntoSet fun bindDeviceControlsAutoAddable(impl: DeviceControlsAutoAddable): AutoAddable
|
||||||
|
|
||||||
|
@Binds @IntoSet fun bindHotspotAutoAddable(impl: HotspotAutoAddable): AutoAddable
|
||||||
|
|
||||||
|
@Binds @IntoSet fun bindNightDisplayAutoAddable(impl: NightDisplayAutoAddable): AutoAddable
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoSet
|
||||||
|
fun bindReduceBrightColorsAutoAddable(impl: ReduceBrightColorsAutoAddable): AutoAddable
|
||||||
|
|
||||||
|
@Binds @IntoSet fun bindWalletAutoAddable(impl: WalletAutoAddable): AutoAddable
|
||||||
|
|
||||||
|
@Binds @IntoSet fun bindWorkModeAutoAddable(impl: WorkTileAutoAddable): AutoAddable
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.util.settings.SecureSettings
|
||||||
|
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import java.util.Objects
|
||||||
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It tracks a specific `Secure` int [setting] and when its value changes to non-zero, it will emit
|
||||||
|
* a [AutoAddSignal.Add] for [spec].
|
||||||
|
*/
|
||||||
|
class AutoAddableSetting
|
||||||
|
@AssistedInject
|
||||||
|
constructor(
|
||||||
|
private val secureSettings: SecureSettings,
|
||||||
|
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||||
|
@Assisted private val setting: String,
|
||||||
|
@Assisted private val spec: TileSpec,
|
||||||
|
) : AutoAddable {
|
||||||
|
|
||||||
|
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return secureSettings
|
||||||
|
.observerFlow(userId, setting)
|
||||||
|
.onStart { emit(Unit) }
|
||||||
|
.map { secureSettings.getIntForUser(setting, 0, userId) != 0 }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.filter { it }
|
||||||
|
.map { AutoAddSignal.Add(spec) }
|
||||||
|
.flowOn(bgDispatcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking = AutoAddTracking.IfNotAdded(spec)
|
||||||
|
|
||||||
|
override val description = "AutoAddableSetting: $setting:$spec ($autoAddTracking)"
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return other is AutoAddableSetting && spec == other.spec && setting == other.setting
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return Objects.hash(spec, setting)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return description
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(setting: String, spec: TileSpec): AutoAddableSetting
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.util.Log
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
|
||||||
|
object AutoAddableSettingList {
|
||||||
|
|
||||||
|
/** Parses [R.array.config_quickSettingsAutoAdd] into a collection of [AutoAddableSetting]. */
|
||||||
|
fun parseSettingsResource(
|
||||||
|
resources: Resources,
|
||||||
|
autoAddableSettingFactory: AutoAddableSetting.Factory,
|
||||||
|
): Iterable<AutoAddable> {
|
||||||
|
val autoAddList = resources.getStringArray(R.array.config_quickSettingsAutoAdd)
|
||||||
|
return autoAddList.mapNotNull {
|
||||||
|
val elements = it.split(SETTING_SEPARATOR, limit = 2)
|
||||||
|
if (elements.size == 2) {
|
||||||
|
val setting = elements[0]
|
||||||
|
val spec = elements[1]
|
||||||
|
val tileSpec = TileSpec.create(spec)
|
||||||
|
if (tileSpec == TileSpec.Invalid) {
|
||||||
|
Log.w(TAG, "Malformed item in array: $it")
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
autoAddableSettingFactory.create(setting, TileSpec.create(spec))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Malformed item in array: $it")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val SETTING_SEPARATOR = ":"
|
||||||
|
private const val TAG = "AutoAddableSettingList"
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.statusbar.policy.CallbackController
|
||||||
|
import kotlinx.coroutines.channels.ProducerScope
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
/** Generic [AutoAddable] for tiles that are added based on a signal from a [CallbackController]. */
|
||||||
|
abstract class CallbackControllerAutoAddable<
|
||||||
|
Callback : Any, Controller : CallbackController<Callback>>(
|
||||||
|
private val controller: Controller,
|
||||||
|
) : AutoAddable {
|
||||||
|
|
||||||
|
/** [TileSpec] for the tile to add. */
|
||||||
|
protected abstract val spec: TileSpec
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to be used to determine when to add the tile. When the callback determines that the
|
||||||
|
* feature has been enabled, it should call [sendAdd].
|
||||||
|
*/
|
||||||
|
protected abstract fun ProducerScope<AutoAddSignal>.getCallback(): Callback
|
||||||
|
|
||||||
|
/** Sends an [AutoAddSignal.Add] for [spec]. */
|
||||||
|
protected fun ProducerScope<AutoAddSignal>.sendAdd() {
|
||||||
|
trySend(AutoAddSignal.Add(spec))
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return conflatedCallbackFlow {
|
||||||
|
val callback = getCallback()
|
||||||
|
controller.addCallback(callback)
|
||||||
|
|
||||||
|
awaitClose { controller.removeCallback(callback) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking: AutoAddTracking
|
||||||
|
get() = AutoAddTracking.IfNotAdded(spec)
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.CastTile
|
||||||
|
import com.android.systemui.statusbar.policy.CastController
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.channels.ProducerScope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [CastTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when there's a casting device connected or connecting.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class CastAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val controller: CastController,
|
||||||
|
) : CallbackControllerAutoAddable<CastController.Callback, CastController>(controller) {
|
||||||
|
|
||||||
|
override val spec: TileSpec
|
||||||
|
get() = TileSpec.create(CastTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun ProducerScope<AutoAddSignal>.getCallback(): CastController.Callback {
|
||||||
|
return CastController.Callback {
|
||||||
|
val isCasting =
|
||||||
|
controller.castDevices.any {
|
||||||
|
it.state == CastController.CastDevice.STATE_CONNECTED ||
|
||||||
|
it.state == CastController.CastDevice.STATE_CONNECTING
|
||||||
|
}
|
||||||
|
if (isCasting) {
|
||||||
|
sendAdd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val description = "CastAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.DataSaverTile
|
||||||
|
import com.android.systemui.statusbar.policy.DataSaverController
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.channels.ProducerScope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [DataSaverTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when data saver is enabled.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class DataSaverAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
dataSaverController: DataSaverController,
|
||||||
|
) :
|
||||||
|
CallbackControllerAutoAddable<DataSaverController.Listener, DataSaverController>(
|
||||||
|
dataSaverController
|
||||||
|
) {
|
||||||
|
|
||||||
|
override val spec
|
||||||
|
get() = TileSpec.create(DataSaverTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun ProducerScope<AutoAddSignal>.getCallback(): DataSaverController.Listener {
|
||||||
|
return DataSaverController.Listener { enabled ->
|
||||||
|
if (enabled) {
|
||||||
|
sendAdd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val description = "DataSaverAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.DeviceControlsTile
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsController
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [DeviceControlsTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when updating to a device that supports device controls. It
|
||||||
|
* will send a signal to remove the tile when the device does not support controls.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class DeviceControlsAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val deviceControlsController: DeviceControlsController,
|
||||||
|
) : AutoAddable {
|
||||||
|
|
||||||
|
private val spec = TileSpec.create(DeviceControlsTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return conflatedCallbackFlow {
|
||||||
|
val callback =
|
||||||
|
object : DeviceControlsController.Callback {
|
||||||
|
override fun onControlsUpdate(position: Int?) {
|
||||||
|
position?.let { trySend(AutoAddSignal.Add(spec, position)) }
|
||||||
|
deviceControlsController.removeCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeControlsAutoTracker() {
|
||||||
|
trySend(AutoAddSignal.Remove(spec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceControlsController.setCallback(callback)
|
||||||
|
|
||||||
|
awaitClose { deviceControlsController.removeCallback() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking: AutoAddTracking
|
||||||
|
get() = AutoAddTracking.Always
|
||||||
|
|
||||||
|
override val description = "DeviceControlsAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.HotspotTile
|
||||||
|
import com.android.systemui.statusbar.policy.HotspotController
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.channels.ProducerScope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [HotspotTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when hotspot is enabled.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class HotspotAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
hotspotController: HotspotController,
|
||||||
|
) :
|
||||||
|
CallbackControllerAutoAddable<HotspotController.Callback, HotspotController>(
|
||||||
|
hotspotController
|
||||||
|
) {
|
||||||
|
|
||||||
|
override val spec
|
||||||
|
get() = TileSpec.create(HotspotTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun ProducerScope<AutoAddSignal>.getCallback(): HotspotController.Callback {
|
||||||
|
return HotspotController.Callback { enabled, _ ->
|
||||||
|
if (enabled) {
|
||||||
|
sendAdd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val description = "HotspotAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.hardware.display.ColorDisplayManager
|
||||||
|
import android.hardware.display.NightDisplayListener
|
||||||
|
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||||
|
import com.android.systemui.dagger.NightDisplayListenerModule
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.NightDisplayTile
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [NightDisplayTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when night display is enabled or when the auto mode changes
|
||||||
|
* to one that supports night display.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class NightDisplayAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val nightDisplayListenerBuilder: NightDisplayListenerModule.Builder,
|
||||||
|
context: Context,
|
||||||
|
) : AutoAddable {
|
||||||
|
|
||||||
|
private val enabled = ColorDisplayManager.isNightDisplayAvailable(context)
|
||||||
|
private val spec = TileSpec.create(NightDisplayTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return conflatedCallbackFlow {
|
||||||
|
val nightDisplayListener = nightDisplayListenerBuilder.setUser(userId).build()
|
||||||
|
|
||||||
|
val callback =
|
||||||
|
object : NightDisplayListener.Callback {
|
||||||
|
override fun onActivated(activated: Boolean) {
|
||||||
|
if (activated) {
|
||||||
|
sendAdd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutoModeChanged(autoMode: Int) {
|
||||||
|
if (
|
||||||
|
autoMode == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME ||
|
||||||
|
autoMode == ColorDisplayManager.AUTO_MODE_TWILIGHT
|
||||||
|
) {
|
||||||
|
sendAdd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendAdd() {
|
||||||
|
trySend(AutoAddSignal.Add(spec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nightDisplayListener.setCallback(callback)
|
||||||
|
|
||||||
|
awaitClose { nightDisplayListener.setCallback(null) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking =
|
||||||
|
if (enabled) {
|
||||||
|
AutoAddTracking.IfNotAdded(spec)
|
||||||
|
} else {
|
||||||
|
AutoAddTracking.Disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
override val description = "NightDisplayAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.ReduceBrightColorsController
|
||||||
|
import com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.ReduceBrightColorsTile
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Named
|
||||||
|
import kotlinx.coroutines.channels.ProducerScope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [ReduceBrightColorsTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when reduce bright colors is enabled.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class ReduceBrightColorsAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
controller: ReduceBrightColorsController,
|
||||||
|
@Named(RBC_AVAILABLE) private val available: Boolean,
|
||||||
|
) :
|
||||||
|
CallbackControllerAutoAddable<
|
||||||
|
ReduceBrightColorsController.Listener, ReduceBrightColorsController
|
||||||
|
>(controller) {
|
||||||
|
|
||||||
|
override val spec: TileSpec
|
||||||
|
get() = TileSpec.create(ReduceBrightColorsTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun ProducerScope<AutoAddSignal>.getCallback(): ReduceBrightColorsController.Listener {
|
||||||
|
return object : ReduceBrightColorsController.Listener {
|
||||||
|
override fun onActivated(activated: Boolean) {
|
||||||
|
if (activated) {
|
||||||
|
sendAdd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking
|
||||||
|
get() =
|
||||||
|
if (available) {
|
||||||
|
super.autoAddTracking
|
||||||
|
} else {
|
||||||
|
AutoAddTracking.Disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
override val description = "ReduceBrightColorsAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.text.TextUtils
|
||||||
|
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
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.statusbar.policy.SafetyController
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for the safety tile.
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when the feature is enabled, indicating the component
|
||||||
|
* corresponding to the tile. If the feature is disabled, it will send a signal to remove the tile.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class SafetyCenterAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val safetyController: SafetyController,
|
||||||
|
private val packageManager: PackageManager,
|
||||||
|
@Main private val resources: Resources,
|
||||||
|
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||||
|
) : AutoAddable {
|
||||||
|
|
||||||
|
private suspend fun getSpec(): TileSpec? {
|
||||||
|
val specClass = resources.getString(R.string.safety_quick_settings_tile_class)
|
||||||
|
return if (TextUtils.isEmpty(specClass)) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
val packageName =
|
||||||
|
withContext(bgDispatcher) { packageManager.permissionControllerPackageName }
|
||||||
|
TileSpec.create(ComponentName(packageName, specClass))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return conflatedCallbackFlow {
|
||||||
|
val spec = getSpec()
|
||||||
|
if (spec != null) {
|
||||||
|
// If not added, we always try to add it
|
||||||
|
trySend(AutoAddSignal.Add(spec))
|
||||||
|
val listener =
|
||||||
|
SafetyController.Listener { isSafetyCenterEnabled ->
|
||||||
|
if (isSafetyCenterEnabled) {
|
||||||
|
trySend(AutoAddSignal.Add(spec))
|
||||||
|
} else {
|
||||||
|
trySend(AutoAddSignal.Remove(spec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
safetyController.addCallback(listener)
|
||||||
|
|
||||||
|
awaitClose { safetyController.removeCallback(listener) }
|
||||||
|
} else {
|
||||||
|
awaitClose {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking: AutoAddTracking
|
||||||
|
get() = AutoAddTracking.Always
|
||||||
|
|
||||||
|
override val description = "SafetyCenterAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.QuickAccessWalletTile
|
||||||
|
import com.android.systemui.statusbar.policy.WalletController
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [QuickAccessWalletTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will always try to add the tile if [WalletController.getWalletPosition] is non-null.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class WalletAutoAddable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val walletController: WalletController,
|
||||||
|
) : AutoAddable {
|
||||||
|
|
||||||
|
private val spec = TileSpec.create(QuickAccessWalletTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return flow {
|
||||||
|
val position = walletController.getWalletPosition()
|
||||||
|
if (position != null) {
|
||||||
|
emit(AutoAddSignal.Add(spec, position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking: AutoAddTracking
|
||||||
|
get() = AutoAddTracking.IfNotAdded(spec)
|
||||||
|
|
||||||
|
override val description = "WalletAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.content.pm.UserInfo
|
||||||
|
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.WorkModeTile
|
||||||
|
import com.android.systemui.settings.UserTracker
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [AutoAddable] for [WorkModeTile.TILE_SPEC].
|
||||||
|
*
|
||||||
|
* It will send a signal to add the tile when there is a managed profile for the current user, and a
|
||||||
|
* signal to remove it if there is not.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class WorkTileAutoAddable @Inject constructor(private val userTracker: UserTracker) : AutoAddable {
|
||||||
|
|
||||||
|
private val spec = TileSpec.create(WorkModeTile.TILE_SPEC)
|
||||||
|
|
||||||
|
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return conflatedCallbackFlow {
|
||||||
|
fun maybeSend(profiles: List<UserInfo>) {
|
||||||
|
if (profiles.any { it.id == userId }) {
|
||||||
|
// We are looking at the profiles of the correct user.
|
||||||
|
if (profiles.any { it.isManagedProfile }) {
|
||||||
|
trySend(AutoAddSignal.Add(spec))
|
||||||
|
} else {
|
||||||
|
trySend(AutoAddSignal.Remove(spec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val callback =
|
||||||
|
object : UserTracker.Callback {
|
||||||
|
override fun onProfilesChanged(profiles: List<UserInfo>) {
|
||||||
|
maybeSend(profiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
userTracker.addCallback(callback) { it.run() }
|
||||||
|
maybeSend(userTracker.userProfiles)
|
||||||
|
|
||||||
|
awaitClose { userTracker.removeCallback(callback) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val autoAddTracking = AutoAddTracking.Always
|
||||||
|
|
||||||
|
override val description = "WorkTileAutoAddable ($autoAddTracking)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.model
|
||||||
|
|
||||||
|
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
|
||||||
|
/** Signal indicating when a tile needs to be auto-added or removed */
|
||||||
|
sealed interface AutoAddSignal {
|
||||||
|
/** Tile for this object */
|
||||||
|
val spec: TileSpec
|
||||||
|
|
||||||
|
/** Signal for auto-adding a tile at [position]. */
|
||||||
|
data class Add(
|
||||||
|
override val spec: TileSpec,
|
||||||
|
val position: Int = POSITION_AT_END,
|
||||||
|
) : AutoAddSignal
|
||||||
|
|
||||||
|
/** Signal for removing a tile. */
|
||||||
|
data class Remove(
|
||||||
|
override val spec: TileSpec,
|
||||||
|
) : AutoAddSignal
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.model
|
||||||
|
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
|
||||||
|
/** Strategy for when to track a particular [AutoAddable]. */
|
||||||
|
sealed interface AutoAddTracking {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the signals from the associated [AutoAddable] should all be collected and
|
||||||
|
* reacted accordingly. It may have [AutoAddSignal.Add] and [AutoAddSignal.Remove].
|
||||||
|
*/
|
||||||
|
object Always : AutoAddTracking {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Always"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the associated [AutoAddable] is [Disabled] and doesn't need to be collected.
|
||||||
|
*/
|
||||||
|
object Disabled : AutoAddTracking {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Disabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only the first [AutoAddSignal.Add] for each flow of signals needs to be collected, and only
|
||||||
|
* if the tile hasn't been auto-added yet. The associated [AutoAddable] will only emit
|
||||||
|
* [AutoAddSignal.Add].
|
||||||
|
*/
|
||||||
|
data class IfNotAdded(val spec: TileSpec) : AutoAddTracking
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.model
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks conditions for auto-adding or removing specific tiles.
|
||||||
|
*
|
||||||
|
* When creating a new [AutoAddable], it needs to be registered in a [Module] like
|
||||||
|
* [BaseAutoAddableModule], for example:
|
||||||
|
* ```
|
||||||
|
* @Binds
|
||||||
|
* @IntoSet
|
||||||
|
* fun providesMyAutoAddable(autoAddable: MyAutoAddable): AutoAddable
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
interface AutoAddable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals associated with a particular user indicating whether a particular tile needs to be
|
||||||
|
* auto-added or auto-removed.
|
||||||
|
*/
|
||||||
|
fun autoAddSignal(userId: Int): Flow<AutoAddSignal>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle for this object. It indicates in which cases [autoAddSignal] should be collected
|
||||||
|
*/
|
||||||
|
val autoAddTracking: AutoAddTracking
|
||||||
|
|
||||||
|
/** Human readable description */
|
||||||
|
val description: String
|
||||||
|
}
|
||||||
@@ -52,7 +52,11 @@ sealed class TileSpec private constructor(open val spec: String) {
|
|||||||
internal constructor(
|
internal constructor(
|
||||||
override val spec: String,
|
override val spec: String,
|
||||||
val componentName: ComponentName,
|
val componentName: ComponentName,
|
||||||
) : TileSpec(spec)
|
) : TileSpec(spec) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "CustomTileSpec(${componentName.toShortString()})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/** Create a [TileSpec] from the string [spec]. */
|
/** Create a [TileSpec] from the string [spec]. */
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class AutoAddableSettingListTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private val factory =
|
||||||
|
object : AutoAddableSetting.Factory {
|
||||||
|
override fun create(setting: String, spec: TileSpec): AutoAddableSetting {
|
||||||
|
return AutoAddableSetting(
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
setting,
|
||||||
|
spec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun correctLines_correctAutoAddables() {
|
||||||
|
val setting1 = "setting1"
|
||||||
|
val setting2 = "setting2"
|
||||||
|
val spec1 = TileSpec.create("spec1")
|
||||||
|
val spec2 = TileSpec.create(ComponentName("pkg", "cls"))
|
||||||
|
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_quickSettingsAutoAdd,
|
||||||
|
arrayOf(toStringLine(setting1, spec1), toStringLine(setting2, spec2))
|
||||||
|
)
|
||||||
|
|
||||||
|
val autoAddables = AutoAddableSettingList.parseSettingsResource(context.resources, factory)
|
||||||
|
|
||||||
|
assertThat(autoAddables)
|
||||||
|
.containsExactly(factory.create(setting1, spec1), factory.create(setting2, spec2))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun malformedLine_ignored() {
|
||||||
|
val setting = "setting"
|
||||||
|
val spec = TileSpec.create("spec")
|
||||||
|
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_quickSettingsAutoAdd,
|
||||||
|
arrayOf(toStringLine(setting, spec), "bad_line")
|
||||||
|
)
|
||||||
|
|
||||||
|
val autoAddables = AutoAddableSettingList.parseSettingsResource(context.resources, factory)
|
||||||
|
|
||||||
|
assertThat(autoAddables).containsExactly(factory.create(setting, spec))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun invalidSpec_ignored() {
|
||||||
|
val setting = "setting"
|
||||||
|
val spec = TileSpec.create("spec")
|
||||||
|
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_quickSettingsAutoAdd,
|
||||||
|
arrayOf(toStringLine(setting, spec), "invalid:")
|
||||||
|
)
|
||||||
|
|
||||||
|
val autoAddables = AutoAddableSettingList.parseSettingsResource(context.resources, factory)
|
||||||
|
|
||||||
|
assertThat(autoAddables).containsExactly(factory.create(setting, spec))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun toStringLine(setting: String, spec: TileSpec) =
|
||||||
|
"$setting$SETTINGS_SEPARATOR${spec.spec}"
|
||||||
|
private const val SETTINGS_SEPARATOR = ":"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.coroutines.collectValues
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.util.settings.FakeSettings
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class AutoAddableSettingTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private val testDispatcher = StandardTestDispatcher()
|
||||||
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
|
private val secureSettings = FakeSettings()
|
||||||
|
private val underTest =
|
||||||
|
AutoAddableSetting(
|
||||||
|
secureSettings,
|
||||||
|
testDispatcher,
|
||||||
|
SETTING,
|
||||||
|
SPEC,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun settingNotSet_noSignal() =
|
||||||
|
testScope.runTest {
|
||||||
|
val userId = 0
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(userId))
|
||||||
|
|
||||||
|
assertThat(signal).isNull() // null means no emitted value
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun settingSetTo0_noSignal() =
|
||||||
|
testScope.runTest {
|
||||||
|
val userId = 0
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(userId))
|
||||||
|
|
||||||
|
secureSettings.putIntForUser(SETTING, 0, userId)
|
||||||
|
|
||||||
|
assertThat(signal).isNull() // null means no emitted value
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun settingSetToNon0_signal() =
|
||||||
|
testScope.runTest {
|
||||||
|
val userId = 0
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(userId))
|
||||||
|
|
||||||
|
secureSettings.putIntForUser(SETTING, 42, userId)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun settingSetForUser_onlySignalInThatUser() =
|
||||||
|
testScope.runTest {
|
||||||
|
val signal0 by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
val signal1 by collectLastValue(underTest.autoAddSignal(1))
|
||||||
|
|
||||||
|
secureSettings.putIntForUser(SETTING, /* value */ 42, /* userHandle */ 1)
|
||||||
|
|
||||||
|
assertThat(signal0).isNull()
|
||||||
|
assertThat(signal1).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleNonZeroChanges_onlyOneSignal() =
|
||||||
|
testScope.runTest {
|
||||||
|
val userId = 0
|
||||||
|
val signals by collectValues(underTest.autoAddSignal(userId))
|
||||||
|
|
||||||
|
secureSettings.putIntForUser(SETTING, 1, userId)
|
||||||
|
secureSettings.putIntForUser(SETTING, 2, userId)
|
||||||
|
|
||||||
|
assertThat(signals.size).isEqualTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun strategyIfNotAdded() {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SETTING = "setting"
|
||||||
|
private val SPEC = TileSpec.create("spec")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.statusbar.policy.CallbackController
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.channels.ProducerScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class CallbackControllerAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun callbackAddedAndRemoved() = runTest {
|
||||||
|
val controller = TestableController()
|
||||||
|
val callback = object : TestableController.Callback {}
|
||||||
|
val underTest =
|
||||||
|
object :
|
||||||
|
CallbackControllerAutoAddable<TestableController.Callback, TestableController>(
|
||||||
|
controller
|
||||||
|
) {
|
||||||
|
override val description: String = ""
|
||||||
|
override val spec: TileSpec
|
||||||
|
get() = SPEC
|
||||||
|
|
||||||
|
override fun ProducerScope<AutoAddSignal>.getCallback():
|
||||||
|
TestableController.Callback {
|
||||||
|
return callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val job = launch { underTest.autoAddSignal(0).collect {} }
|
||||||
|
runCurrent()
|
||||||
|
assertThat(controller.callbacks).containsExactly(callback)
|
||||||
|
job.cancel()
|
||||||
|
runCurrent()
|
||||||
|
assertThat(controller.callbacks).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun sendAddFromCallback() = runTest {
|
||||||
|
val controller = TestableController()
|
||||||
|
val underTest =
|
||||||
|
object :
|
||||||
|
CallbackControllerAutoAddable<TestableController.Callback, TestableController>(
|
||||||
|
controller
|
||||||
|
) {
|
||||||
|
override val description: String = ""
|
||||||
|
|
||||||
|
override val spec: TileSpec
|
||||||
|
get() = SPEC
|
||||||
|
|
||||||
|
override fun ProducerScope<AutoAddSignal>.getCallback():
|
||||||
|
TestableController.Callback {
|
||||||
|
return object : TestableController.Callback {
|
||||||
|
override fun change() {
|
||||||
|
sendAdd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
|
||||||
|
controller.callbacks.first().change()
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun strategyIfNotAdded() {
|
||||||
|
val underTest =
|
||||||
|
object :
|
||||||
|
CallbackControllerAutoAddable<TestableController.Callback, TestableController>(
|
||||||
|
TestableController()
|
||||||
|
) {
|
||||||
|
override val description: String = ""
|
||||||
|
override val spec: TileSpec
|
||||||
|
get() = SPEC
|
||||||
|
|
||||||
|
override fun ProducerScope<AutoAddSignal>.getCallback():
|
||||||
|
TestableController.Callback {
|
||||||
|
return object : TestableController.Callback {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestableController : CallbackController<TestableController.Callback> {
|
||||||
|
|
||||||
|
val callbacks = mutableSetOf<Callback>()
|
||||||
|
|
||||||
|
override fun addCallback(listener: Callback) {
|
||||||
|
callbacks.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeCallback(listener: Callback) {
|
||||||
|
callbacks.remove(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun change() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create("test")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.CastTile
|
||||||
|
import com.android.systemui.statusbar.policy.CastController
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class CastAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var castController: CastController
|
||||||
|
@Captor private lateinit var callbackCaptor: ArgumentCaptor<CastController.Callback>
|
||||||
|
|
||||||
|
private lateinit var underTest: CastAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
underTest = CastAutoAddable(castController)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onCastDevicesChanged_noDevices_noSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(castController).addCallback(capture(callbackCaptor))
|
||||||
|
|
||||||
|
callbackCaptor.value.onCastDevicesChanged()
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onCastDevicesChanged_deviceNotConnectedOrConnecting_noSignal() = runTest {
|
||||||
|
val device =
|
||||||
|
CastController.CastDevice().apply {
|
||||||
|
state = CastController.CastDevice.STATE_DISCONNECTED
|
||||||
|
}
|
||||||
|
whenever(castController.castDevices).thenReturn(listOf(device))
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(castController).addCallback(capture(callbackCaptor))
|
||||||
|
|
||||||
|
callbackCaptor.value.onCastDevicesChanged()
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onCastDevicesChanged_someDeviceConnecting_addSignal() = runTest {
|
||||||
|
val disconnectedDevice =
|
||||||
|
CastController.CastDevice().apply {
|
||||||
|
state = CastController.CastDevice.STATE_DISCONNECTED
|
||||||
|
}
|
||||||
|
val connectingDevice =
|
||||||
|
CastController.CastDevice().apply { state = CastController.CastDevice.STATE_CONNECTING }
|
||||||
|
whenever(castController.castDevices)
|
||||||
|
.thenReturn(listOf(disconnectedDevice, connectingDevice))
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(castController).addCallback(capture(callbackCaptor))
|
||||||
|
|
||||||
|
callbackCaptor.value.onCastDevicesChanged()
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onCastDevicesChanged_someDeviceConnected_addSignal() = runTest {
|
||||||
|
val disconnectedDevice =
|
||||||
|
CastController.CastDevice().apply {
|
||||||
|
state = CastController.CastDevice.STATE_DISCONNECTED
|
||||||
|
}
|
||||||
|
val connectedDevice =
|
||||||
|
CastController.CastDevice().apply { state = CastController.CastDevice.STATE_CONNECTED }
|
||||||
|
whenever(castController.castDevices).thenReturn(listOf(disconnectedDevice, connectedDevice))
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(castController).addCallback(capture(callbackCaptor))
|
||||||
|
|
||||||
|
callbackCaptor.value.onCastDevicesChanged()
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(CastTile.TILE_SPEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.DataSaverTile
|
||||||
|
import com.android.systemui.statusbar.policy.DataSaverController
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class DataSaverAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var dataSaverController: DataSaverController
|
||||||
|
@Captor private lateinit var callbackCaptor: ArgumentCaptor<DataSaverController.Listener>
|
||||||
|
|
||||||
|
private lateinit var underTest: DataSaverAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
underTest = DataSaverAutoAddable(dataSaverController)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dataSaverNotEnabled_NoSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(dataSaverController).addCallback(capture(callbackCaptor))
|
||||||
|
|
||||||
|
callbackCaptor.value.onDataSaverChanged(false)
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dataSaverEnabled_addSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(dataSaverController).addCallback(capture(callbackCaptor))
|
||||||
|
|
||||||
|
callbackCaptor.value.onDataSaverChanged(true)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(DataSaverTile.TILE_SPEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.DeviceControlsTile
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsController
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class DeviceControlsAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var deviceControlsController: DeviceControlsController
|
||||||
|
@Captor private lateinit var callbackCaptor: ArgumentCaptor<DeviceControlsController.Callback>
|
||||||
|
|
||||||
|
private lateinit var underTest: DeviceControlsAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
underTest = DeviceControlsAutoAddable(deviceControlsController)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun strategyAlways() {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onControlsUpdate_position_addSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
val position = 5
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(deviceControlsController).setCallback(capture(callbackCaptor))
|
||||||
|
callbackCaptor.value.onControlsUpdate(position)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC, position))
|
||||||
|
verify(deviceControlsController).removeCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onControlsUpdate_nullPosition_noAddSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(deviceControlsController).setCallback(capture(callbackCaptor))
|
||||||
|
callbackCaptor.value.onControlsUpdate(null)
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
verify(deviceControlsController).removeCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onRemoveControlsAutoTracker_removeSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(deviceControlsController).setCallback(capture(callbackCaptor))
|
||||||
|
callbackCaptor.value.removeControlsAutoTracker()
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Remove(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun flowCancelled_removeCallback() = runTest {
|
||||||
|
val job = launch { underTest.autoAddSignal(0).collect() }
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
runCurrent()
|
||||||
|
verify(deviceControlsController).removeCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(DeviceControlsTile.TILE_SPEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.HotspotTile
|
||||||
|
import com.android.systemui.statusbar.policy.HotspotController
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class HotspotAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var hotspotController: HotspotController
|
||||||
|
@Captor private lateinit var callbackCaptor: ArgumentCaptor<HotspotController.Callback>
|
||||||
|
|
||||||
|
private lateinit var underTest: HotspotAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
underTest = HotspotAutoAddable(hotspotController)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun enabled_addSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(hotspotController).addCallback(capture(callbackCaptor))
|
||||||
|
callbackCaptor.value.onHotspotChanged(/* enabled = */ true, /* numDevices = */ 5)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun notEnabled_noSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(hotspotController).addCallback(capture(callbackCaptor))
|
||||||
|
callbackCaptor.value.onHotspotChanged(/* enabled = */ false, /* numDevices = */ 0)
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(HotspotTile.TILE_SPEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.hardware.display.NightDisplayListener
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.dagger.NightDisplayListenerModule
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.NightDisplayTile
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.TestResult
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Answers
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.inOrder
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class NightDisplayAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_SELF)
|
||||||
|
private lateinit var nightDisplayListenerBuilder: NightDisplayListenerModule.Builder
|
||||||
|
@Mock private lateinit var nightDisplayListener: NightDisplayListener
|
||||||
|
@Captor private lateinit var callbackCaptor: ArgumentCaptor<NightDisplayListener.Callback>
|
||||||
|
|
||||||
|
private lateinit var underTest: NightDisplayAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
whenever(nightDisplayListenerBuilder.build()).thenReturn(nightDisplayListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun disabled_strategyDisabled() =
|
||||||
|
testWithFeatureAvailability(enabled = false) {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun enabled_strategyIfNotAdded() = testWithFeatureAvailability {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun listenerCreatedForCorrectUser() = testWithFeatureAvailability {
|
||||||
|
val user = 42
|
||||||
|
backgroundScope.launch { underTest.autoAddSignal(user).collect() }
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
val inOrder = inOrder(nightDisplayListenerBuilder)
|
||||||
|
inOrder.verify(nightDisplayListenerBuilder).setUser(user)
|
||||||
|
inOrder.verify(nightDisplayListenerBuilder).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onCancelFlow_removeCallback() = testWithFeatureAvailability {
|
||||||
|
val job = launch { underTest.autoAddSignal(0).collect() }
|
||||||
|
runCurrent()
|
||||||
|
job.cancel()
|
||||||
|
runCurrent()
|
||||||
|
verify(nightDisplayListener).setCallback(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onActivatedTrue_addSignal() = testWithFeatureAvailability {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(nightDisplayListener).setCallback(capture(callbackCaptor))
|
||||||
|
callbackCaptor.value.onActivated(true)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testWithFeatureAvailability(
|
||||||
|
enabled: Boolean = true,
|
||||||
|
body: suspend TestScope.() -> TestResult
|
||||||
|
) = runTest {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
com.android.internal.R.bool.config_nightDisplayAvailable,
|
||||||
|
enabled
|
||||||
|
)
|
||||||
|
underTest = NightDisplayAutoAddable(nightDisplayListenerBuilder, context)
|
||||||
|
body()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(NightDisplayTile.TILE_SPEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.ReduceBrightColorsController
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.ReduceBrightColorsTile
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.TestResult
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var reduceBrightColorsController: ReduceBrightColorsController
|
||||||
|
@Captor
|
||||||
|
private lateinit var reduceBrightColorsListenerCaptor:
|
||||||
|
ArgumentCaptor<ReduceBrightColorsController.Listener>
|
||||||
|
|
||||||
|
private lateinit var underTest: ReduceBrightColorsAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun notAvailable_strategyDisabled() =
|
||||||
|
testWithFeatureAvailability(available = false) {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun available_strategyIfNotAdded() =
|
||||||
|
testWithFeatureAvailability(available = true) {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun activated_addSignal() = testWithFeatureAvailability {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(reduceBrightColorsController).addCallback(capture(reduceBrightColorsListenerCaptor))
|
||||||
|
|
||||||
|
reduceBrightColorsListenerCaptor.value.onActivated(true)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun notActivated_noSignal() = testWithFeatureAvailability {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(reduceBrightColorsController).addCallback(capture(reduceBrightColorsListenerCaptor))
|
||||||
|
|
||||||
|
reduceBrightColorsListenerCaptor.value.onActivated(false)
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testWithFeatureAvailability(
|
||||||
|
available: Boolean = true,
|
||||||
|
body: suspend TestScope.() -> TestResult
|
||||||
|
) = runTest {
|
||||||
|
underTest = ReduceBrightColorsAutoAddable(reduceBrightColorsController, available)
|
||||||
|
body()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(ReduceBrightColorsTile.TILE_SPEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.coroutines.collectValues
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.statusbar.policy.SafetyController
|
||||||
|
import com.android.systemui.util.mockito.any
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class SafetyCenterAutoAddableTest : SysuiTestCase() {
|
||||||
|
private val testDispatcher = StandardTestDispatcher()
|
||||||
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
|
@Mock private lateinit var safetyController: SafetyController
|
||||||
|
@Mock private lateinit var packageManager: PackageManager
|
||||||
|
@Captor
|
||||||
|
private lateinit var safetyControllerListenerCaptor: ArgumentCaptor<SafetyController.Listener>
|
||||||
|
|
||||||
|
private lateinit var underTest: SafetyCenterAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
context.ensureTestableResources()
|
||||||
|
|
||||||
|
// Set these by default, will also test special cases
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.string.safety_quick_settings_tile_class,
|
||||||
|
SAFETY_TILE_CLASS_NAME
|
||||||
|
)
|
||||||
|
whenever(packageManager.permissionControllerPackageName)
|
||||||
|
.thenReturn(PERMISSION_CONTROLLER_PACKAGE_NAME)
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
SafetyCenterAutoAddable(
|
||||||
|
safetyController,
|
||||||
|
packageManager,
|
||||||
|
context.resources,
|
||||||
|
testDispatcher,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun strategyAlwaysTrack() =
|
||||||
|
testScope.runTest {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun tileAlwaysAdded() =
|
||||||
|
testScope.runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun safetyCenterDisabled_removeSignal() =
|
||||||
|
testScope.runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(safetyController).addCallback(capture(safetyControllerListenerCaptor))
|
||||||
|
safetyControllerListenerCaptor.value.onSafetyCenterEnableChanged(false)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Remove(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun safetyCenterEnabled_newAddSignal() =
|
||||||
|
testScope.runTest {
|
||||||
|
val signals by collectValues(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(safetyController).addCallback(capture(safetyControllerListenerCaptor))
|
||||||
|
safetyControllerListenerCaptor.value.onSafetyCenterEnableChanged(true)
|
||||||
|
|
||||||
|
assertThat(signals.size).isEqualTo(2)
|
||||||
|
assertThat(signals.last()).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun flowCancelled_removeListener() =
|
||||||
|
testScope.runTest {
|
||||||
|
val job = launch { underTest.autoAddSignal(0).collect() }
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(safetyController).addCallback(capture(safetyControllerListenerCaptor))
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
runCurrent()
|
||||||
|
verify(safetyController).removeCallback(safetyControllerListenerCaptor.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun emptyClassName_noSignals() =
|
||||||
|
testScope.runTest {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.string.safety_quick_settings_tile_class,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(safetyController, never()).addCallback(any())
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SAFETY_TILE_CLASS_NAME = "cls"
|
||||||
|
private const val PERMISSION_CONTROLLER_PACKAGE_NAME = "pkg"
|
||||||
|
private val SPEC =
|
||||||
|
TileSpec.create(
|
||||||
|
ComponentName(PERMISSION_CONTROLLER_PACKAGE_NAME, SAFETY_TILE_CLASS_NAME)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.QuickAccessWalletTile
|
||||||
|
import com.android.systemui.statusbar.policy.WalletController
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class WalletAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var walletController: WalletController
|
||||||
|
|
||||||
|
private lateinit var underTest: WalletAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
underTest = WalletAutoAddable(walletController)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun strategyIfNotAdded() {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun walletPositionNull_noSignal() = runTest {
|
||||||
|
whenever(walletController.getWalletPosition()).thenReturn(null)
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
assertThat(signal).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun walletPositionNumber_addedInThatPosition() = runTest {
|
||||||
|
val position = 4
|
||||||
|
whenever(walletController.getWalletPosition()).thenReturn(4)
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC, position))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(QuickAccessWalletTile.TILE_SPEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import android.content.pm.UserInfo
|
||||||
|
import android.content.pm.UserInfo.FLAG_FULL
|
||||||
|
import android.content.pm.UserInfo.FLAG_MANAGED_PROFILE
|
||||||
|
import android.content.pm.UserInfo.FLAG_PRIMARY
|
||||||
|
import android.content.pm.UserInfo.FLAG_PROFILE
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.tiles.WorkModeTile
|
||||||
|
import com.android.systemui.settings.FakeUserTracker
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class WorkTileAutoAddableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private lateinit var userTracker: FakeUserTracker
|
||||||
|
|
||||||
|
private lateinit var underTest: WorkTileAutoAddable
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
userTracker =
|
||||||
|
FakeUserTracker(
|
||||||
|
_userId = USER_INFO_0.id,
|
||||||
|
_userInfo = USER_INFO_0,
|
||||||
|
_userProfiles = listOf(USER_INFO_0)
|
||||||
|
)
|
||||||
|
|
||||||
|
underTest = WorkTileAutoAddable(userTracker)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun changeInProfiles_hasManagedProfile_sendsAddSignal() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun changeInProfiles_noManagedProfile_sendsRemoveSignal() = runTest {
|
||||||
|
userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
userTracker.set(listOf(USER_INFO_0), selectedUserIndex = 0)
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Remove(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startingWithManagedProfile_sendsAddSignal() = runTest {
|
||||||
|
userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
|
||||||
|
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userChangeToUserWithProfile_noSignalForOriginalUser() = runTest {
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
userTracker.set(listOf(USER_INFO_1, USER_INFO_WORK), selectedUserIndex = 0)
|
||||||
|
|
||||||
|
assertThat(signal).isNotEqualTo(AutoAddSignal.Add(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userChangeToUserWithoutProfile_noSignalForOriginalUser() = runTest {
|
||||||
|
userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
|
||||||
|
val signal by collectLastValue(underTest.autoAddSignal(0))
|
||||||
|
|
||||||
|
userTracker.set(listOf(USER_INFO_1), selectedUserIndex = 0)
|
||||||
|
|
||||||
|
assertThat(signal).isNotEqualTo(AutoAddSignal.Remove(SPEC))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun strategyAlways() {
|
||||||
|
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create(WorkModeTile.TILE_SPEC)
|
||||||
|
private val USER_INFO_0 = UserInfo(0, "", FLAG_PRIMARY or FLAG_FULL)
|
||||||
|
private val USER_INFO_1 = UserInfo(1, "", FLAG_FULL)
|
||||||
|
private val USER_INFO_WORK = UserInfo(10, "", FLAG_PROFILE or FLAG_MANAGED_PROFILE)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.pipeline.domain.autoaddable
|
||||||
|
|
||||||
|
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
|
|
||||||
|
class FakeAutoAddable(
|
||||||
|
private val spec: TileSpec,
|
||||||
|
override val autoAddTracking: AutoAddTracking,
|
||||||
|
) : AutoAddable {
|
||||||
|
|
||||||
|
private val signalsPerUser = mutableMapOf<Int, MutableStateFlow<AutoAddSignal?>>()
|
||||||
|
private fun getFlow(userId: Int): MutableStateFlow<AutoAddSignal?> =
|
||||||
|
signalsPerUser.getOrPut(userId) { MutableStateFlow(null) }
|
||||||
|
|
||||||
|
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
|
||||||
|
return getFlow(userId).asStateFlow().filterNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun sendRemoveSignal(userId: Int) {
|
||||||
|
getFlow(userId).value = AutoAddSignal.Remove(spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun sendAddSignal(userId: Int, position: Int = POSITION_AT_END) {
|
||||||
|
getFlow(userId).value = AutoAddSignal.Add(spec, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val description: String
|
||||||
|
get() = "FakeAutoAddable($spec)"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user