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

Commit b89998c8 authored by Fabián Kozynski's avatar Fabián Kozynski Committed by Automerger Merge Worker
Browse files
parents 7a7be17a 2c770a94
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.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
}
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.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
    }
}
+54 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.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"
}
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.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)
}
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.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)"
}
Loading