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

Commit 2b95a591 authored by Automerger Merge Worker's avatar Automerger Merge Worker Committed by Android (Google) Code Review
Browse files

Merge "Merge "Add Mute custom quick affordance" into tm-qpr-dev am: d886dac3 am: 6318005a"

parents 0babd527 a3c4737f
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import com.android.systemui.dreams.DreamMonitor
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
import com.android.systemui.log.SessionTracker
import com.android.systemui.media.dialog.MediaOutputSwitcherDialogUI
import com.android.systemui.media.RingtonePlayer
@@ -295,6 +296,14 @@ abstract class SystemUICoreStartableModule {
    @ClassKey(StylusUsiPowerStartable::class)
    abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable

    /** Inject into MuteQuickAffordanceCoreStartable*/
    @Binds
    @IntoMap
    @ClassKey(MuteQuickAffordanceCoreStartable::class)
    abstract fun bindMuteQuickAffordanceCoreStartable(
            sysui: MuteQuickAffordanceCoreStartable
    ): CoreStartable

    /**Inject into DreamMonitor */
    @Binds
    @IntoMap
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ object BuiltInKeyguardQuickAffordanceKeys {
    const val DO_NOT_DISTURB = "do_not_disturb"
    const val FLASHLIGHT = "flashlight"
    const val HOME_CONTROLS = "home"
    const val MUTE = "mute"
    const val QR_CODE_SCANNER = "qr_code_scanner"
    const val QUICK_ACCESS_WALLET = "wallet"
    const val VIDEO_CAMERA = "video_camera"
+3 −1
Original line number Diff line number Diff line
@@ -33,12 +33,13 @@ interface KeyguardDataQuickAffordanceModule {
        @Provides
        @ElementsIntoSet
        fun quickAffordanceConfigs(
            camera: CameraQuickAffordanceConfig,
            doNotDisturb: DoNotDisturbQuickAffordanceConfig,
            flashlight: FlashlightQuickAffordanceConfig,
            home: HomeControlsKeyguardQuickAffordanceConfig,
            mute: MuteQuickAffordanceConfig,
            quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
            qrCodeScanner: QrCodeScannerKeyguardQuickAffordanceConfig,
            camera: CameraQuickAffordanceConfig,
            videoCamera: VideoCameraQuickAffordanceConfig,
        ): Set<KeyguardQuickAffordanceConfig> {
            return setOf(
@@ -46,6 +47,7 @@ interface KeyguardDataQuickAffordanceModule {
                doNotDisturb,
                flashlight,
                home,
                mute,
                quickAccessWallet,
                qrCodeScanner,
                videoCamera,
+144 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.keyguard.data.quickaffordance

import android.content.Context
import android.media.AudioManager
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.RingerModeTracker
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import javax.inject.Inject

@SysUISingleton
class MuteQuickAffordanceConfig @Inject constructor(
        context: Context,
        private val userTracker: UserTracker,
        private val userFileManager: UserFileManager,
        private val ringerModeTracker: RingerModeTracker,
        private val audioManager: AudioManager,
) : KeyguardQuickAffordanceConfig {

    private var previousNonSilentMode: Int = DEFAULT_LAST_NON_SILENT_VALUE

    override val key: String = BuiltInKeyguardQuickAffordanceKeys.MUTE

    override val pickerName: String = context.getString(R.string.volume_ringer_status_silent)

    override val pickerIconResourceId: Int = R.drawable.ic_notifications_silence

    override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
        ringerModeTracker.ringerModeInternal.asFlow()
            .onStart { emit(getLastNonSilentRingerMode()) }
            .distinctUntilChanged()
            .onEach { mode ->
                // only remember last non-SILENT ringer mode
                if (mode != null && mode != AudioManager.RINGER_MODE_SILENT) {
                    previousNonSilentMode = mode
                }
            }
            .map { mode ->
                val (activationState, contentDescriptionRes) = when {
                    audioManager.isVolumeFixed ->
                        ActivationState.NotSupported to
                            R.string.volume_ringer_hint_mute
                    mode == AudioManager.RINGER_MODE_SILENT ->
                        ActivationState.Active to
                            R.string.volume_ringer_hint_mute
                    else ->
                        ActivationState.Inactive to
                            R.string.volume_ringer_hint_unmute
                }

                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                    Icon.Resource(
                        R.drawable.ic_notifications_silence,
                        ContentDescription.Resource(contentDescriptionRes),
                    ),
                    activationState,
                )
            }

    override fun onTriggered(
        expandable: Expandable?
    ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
        val newRingerMode: Int
        val currentRingerMode =
                ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
        if (currentRingerMode == AudioManager.RINGER_MODE_SILENT) {
            newRingerMode = previousNonSilentMode
        } else {
            previousNonSilentMode = currentRingerMode
            newRingerMode = AudioManager.RINGER_MODE_SILENT
        }

        if (currentRingerMode != newRingerMode) {
            audioManager.ringerModeInternal = newRingerMode
        }
        return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
    }

    override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState =
        if (audioManager.isVolumeFixed) {
            KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
        } else {
            KeyguardQuickAffordanceConfig.PickerScreenState.Default()
        }

    /**
     * Gets the last non-silent ringer mode from shared-preferences if it exists. This is
     *  cached by [MuteQuickAffordanceCoreStartable] while this affordance is selected
     */
    private fun getLastNonSilentRingerMode(): Int =
        userFileManager.getSharedPreferences(
            MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
            Context.MODE_PRIVATE,
            userTracker.userId
        ).getInt(
            LAST_NON_SILENT_RINGER_MODE_KEY,
            ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
        )

    private fun <T> LiveData<T>.asFlow(): Flow<T?> =
            conflatedCallbackFlow {
                val observer = Observer { value: T -> trySend(value) }
                observeForever(observer)
                send(value)
                awaitClose { removeObserver(observer) }
            }

    companion object {
        const val LAST_NON_SILENT_RINGER_MODE_KEY = "key_last_non_silent_ringer_mode"
        const val MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME = "quick_affordance_mute_ringer_mode_cache"
        private const val DEFAULT_LAST_NON_SILENT_VALUE = AudioManager.RINGER_MODE_NORMAL
    }
}
 No newline at end of file
+86 −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.keyguard.data.quickaffordance

import android.content.Context
import android.media.AudioManager
import androidx.lifecycle.Observer
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.RingerModeTracker
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import javax.inject.Inject

/**
 * Store previous non-silent Ringer Mode into shared prefs to be used for Mute Lockscreen Shortcut
 */
@SysUISingleton
class MuteQuickAffordanceCoreStartable @Inject constructor(
    private val featureFlags: FeatureFlags,
    private val userTracker: UserTracker,
    private val ringerModeTracker: RingerModeTracker,
    private val userFileManager: UserFileManager,
    private val keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository,
    @Application private val coroutineScope: CoroutineScope,
) : CoreStartable {

    private val observer = Observer(this::updateLastNonSilentRingerMode)

    override fun start() {
        if (!featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)) return

        // only listen to ringerModeInternal changes when Mute is one of the selected affordances
        keyguardQuickAffordanceRepository
            .selections
            .map { selections ->
                // determines if Mute is selected in any lockscreen shortcut position
                val muteSelected: Boolean = selections.values.any { configList ->
                    configList.any { config ->
                        config.key == BuiltInKeyguardQuickAffordanceKeys.MUTE
                    }
                }
                if (muteSelected) {
                    ringerModeTracker.ringerModeInternal.observeForever(observer)
                } else {
                    ringerModeTracker.ringerModeInternal.removeObserver(observer)
                }
            }
            .launchIn(coroutineScope)
    }

    private fun updateLastNonSilentRingerMode(lastRingerMode: Int) {
        if (AudioManager.RINGER_MODE_SILENT != lastRingerMode) {
            userFileManager.getSharedPreferences(
                MuteQuickAffordanceConfig.MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
                Context.MODE_PRIVATE,
                userTracker.userId
            )
            .edit()
            .putInt(MuteQuickAffordanceConfig.LAST_NON_SILENT_RINGER_MODE_KEY, lastRingerMode)
            .apply()
        }
    }
}
 No newline at end of file
Loading