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

Commit 36439176 authored by Brad Hinegardner's avatar Brad Hinegardner Committed by Automerger Merge Worker
Browse files

Merge "Add Do Not disturb custom quick affordance" into tm-qpr-dev am: 591c0079 am: 3b46e3c0

parents febbdf17 3b46e3c0
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line 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.
  -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="24dp"
    android:width="24dp"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">

    <path
        android:fillColor="#ffffff"
        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM7,11h10v2L7,13z"/>
</vector>
+3 −0
Original line number Original line Diff line number Diff line
@@ -2091,6 +2091,9 @@
    <!-- Label for when Do not disturb is off in QS detail panel [CHAR LIMIT=NONE] -->
    <!-- Label for when Do not disturb is off in QS detail panel [CHAR LIMIT=NONE] -->
    <string name="dnd_is_off">Do Not Disturb is off</string>
    <string name="dnd_is_off">Do Not Disturb is off</string>


    <!-- Label for when Do not disturb is on in lockscreen quick affordance [CHAR LIMIT=NONE] -->
    <string name="dnd_is_on">Do Not Disturb is on</string>

    <!-- Prompt for when Do not disturb is on from automatic rule in QS [CHAR LIMIT=NONE] -->
    <!-- Prompt for when Do not disturb is on from automatic rule in QS [CHAR LIMIT=NONE] -->
    <string name="qs_dnd_prompt_auto_rule">Do Not Disturb was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>).</string>
    <string name="qs_dnd_prompt_auto_rule">Do Not Disturb was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>).</string>


+1 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ package com.android.systemui.keyguard.data.quickaffordance
object BuiltInKeyguardQuickAffordanceKeys {
object BuiltInKeyguardQuickAffordanceKeys {
    // Please keep alphabetical order of const names to simplify future maintenance.
    // Please keep alphabetical order of const names to simplify future maintenance.
    const val CAMERA = "camera"
    const val CAMERA = "camera"
    const val DO_NOT_DISTURB = "do_not_disturb"
    const val FLASHLIGHT = "flashlight"
    const val FLASHLIGHT = "flashlight"
    const val HOME_CONTROLS = "home"
    const val HOME_CONTROLS = "home"
    const val QR_CODE_SCANNER = "qr_code_scanner"
    const val QR_CODE_SCANNER = "qr_code_scanner"
+190 −0
Original line number Original line 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.net.Uri
import android.provider.Settings
import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
import android.provider.Settings.Global.ZEN_MODE_OFF
import android.provider.Settings.Secure.ZEN_DURATION_FOREVER
import android.provider.Settings.Secure.ZEN_DURATION_PROMPT
import android.service.notification.ZenModeConfig
import com.android.settingslib.notification.EnableZenModeDialog
import com.android.settingslib.notification.ZenModeDialogMetricsLogger
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
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.dagger.qualifiers.Background
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.ZenModeController
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import javax.inject.Inject

@SysUISingleton
class DoNotDisturbQuickAffordanceConfig constructor(
    private val context: Context,
    private val controller: ZenModeController,
    private val secureSettings: SecureSettings,
    private val userTracker: UserTracker,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val testConditionId: Uri?,
    testDialog: EnableZenModeDialog?,
): KeyguardQuickAffordanceConfig {

    @Inject
    constructor(
        context: Context,
        controller: ZenModeController,
        secureSettings: SecureSettings,
        userTracker: UserTracker,
        @Background backgroundDispatcher: CoroutineDispatcher,
    ) : this(context, controller, secureSettings, userTracker, backgroundDispatcher, null, null)

    private var dndMode: Int = 0
    private var isAvailable = false
    private var settingsValue: Int = 0

    private val conditionUri: Uri
        get() =
            testConditionId ?: ZenModeConfig.toTimeCondition(
                context,
                settingsValue,
                userTracker.userId,
                true, /* shortVersion */
            ).id

    private val dialog: EnableZenModeDialog by lazy {
        testDialog ?: EnableZenModeDialog(
            context,
            R.style.Theme_SystemUI_Dialog,
            true, /* cancelIsNeutral */
            ZenModeDialogMetricsLogger(context),
        )
    }

    override val key: String = BuiltInKeyguardQuickAffordanceKeys.DO_NOT_DISTURB

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

    override val pickerIconResourceId: Int = R.drawable.ic_do_not_disturb

    override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> = combine(
        conflatedCallbackFlow {
            val callback = object: ZenModeController.Callback {
                override fun onZenChanged(zen: Int) {
                    dndMode = zen
                    trySendWithFailureLogging(updateState(), TAG)
                }

                override fun onZenAvailableChanged(available: Boolean) {
                    isAvailable = available
                    trySendWithFailureLogging(updateState(), TAG)
                }
            }

            dndMode = controller.zen
            isAvailable = controller.isZenAvailable
            trySendWithFailureLogging(updateState(), TAG)

            controller.addCallback(callback)

            awaitClose { controller.removeCallback(callback) }
        },
        secureSettings
            .observerFlow(Settings.Secure.ZEN_DURATION)
            .onStart { emit(Unit) }
            .map { secureSettings.getInt(Settings.Secure.ZEN_DURATION, ZEN_MODE_OFF) }
            .flowOn(backgroundDispatcher)
            .distinctUntilChanged()
            .onEach { settingsValue = it }
    ) { callbackFlowValue, _ -> callbackFlowValue }

    override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
        return if (controller.isZenAvailable) {
            KeyguardQuickAffordanceConfig.PickerScreenState.Default
        } else {
            KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
        }
    }

    override fun onTriggered(expandable: Expandable?):
            KeyguardQuickAffordanceConfig.OnTriggeredResult {
        return when {
            !isAvailable ->
                KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            dndMode != ZEN_MODE_OFF -> {
                controller.setZen(ZEN_MODE_OFF, null, TAG)
                KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            }
            settingsValue == ZEN_DURATION_PROMPT ->
                KeyguardQuickAffordanceConfig.OnTriggeredResult.ShowDialog(
                        dialog.createDialog(),
                        expandable
                )
            settingsValue == ZEN_DURATION_FOREVER -> {
                controller.setZen(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG)
                KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            }
            else -> {
                controller.setZen(ZEN_MODE_IMPORTANT_INTERRUPTIONS, conditionUri, TAG)
                KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            }
        }
    }

    private fun updateState(): KeyguardQuickAffordanceConfig.LockScreenState {
        return if (!isAvailable) {
            KeyguardQuickAffordanceConfig.LockScreenState.Hidden
        } else if (dndMode == ZEN_MODE_OFF) {
            KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                Icon.Resource(
                    R.drawable.qs_dnd_icon_off,
                    ContentDescription.Resource(R.string.dnd_is_off),
                ),
                ActivationState.Inactive,
            )
        } else {
            KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                Icon.Resource(
                    R.drawable.qs_dnd_icon_on,
                    ContentDescription.Resource(R.string.dnd_is_on),
                ),
                ActivationState.Active,
            )
        }
    }

    companion object {
        const val TAG = "DoNotDisturbQuickAffordanceConfig"
    }
}
 No newline at end of file
+2 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ interface KeyguardDataQuickAffordanceModule {
        @Provides
        @Provides
        @ElementsIntoSet
        @ElementsIntoSet
        fun quickAffordanceConfigs(
        fun quickAffordanceConfigs(
            doNotDisturb: DoNotDisturbQuickAffordanceConfig,
            flashlight: FlashlightQuickAffordanceConfig,
            flashlight: FlashlightQuickAffordanceConfig,
            home: HomeControlsKeyguardQuickAffordanceConfig,
            home: HomeControlsKeyguardQuickAffordanceConfig,
            quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
            quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
@@ -41,6 +42,7 @@ interface KeyguardDataQuickAffordanceModule {
        ): Set<KeyguardQuickAffordanceConfig> {
        ): Set<KeyguardQuickAffordanceConfig> {
            return setOf(
            return setOf(
                camera,
                camera,
                doNotDisturb,
                flashlight,
                flashlight,
                home,
                home,
                quickAccessWallet,
                quickAccessWallet,
Loading