Merge "Add Do Not disturb custom quick affordance" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
591c007930
25
packages/SystemUI/res/drawable/ic_do_not_disturb.xml
Normal file
25
packages/SystemUI/res/drawable/ic_do_not_disturb.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<!--
|
||||||
|
~ 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>
|
||||||
@@ -2035,6 +2035,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>
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package com.android.systemui.keyguard.data.quickaffordance
|
package com.android.systemui.keyguard.data.quickaffordance
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.android.systemui.animation.Expandable
|
import com.android.systemui.animation.Expandable
|
||||||
import com.android.systemui.common.shared.model.Icon
|
import com.android.systemui.common.shared.model.Icon
|
||||||
@@ -141,6 +142,16 @@ interface KeyguardQuickAffordanceConfig {
|
|||||||
val intent: Intent,
|
val intent: Intent,
|
||||||
val canShowWhileLocked: Boolean,
|
val canShowWhileLocked: Boolean,
|
||||||
) : OnTriggeredResult()
|
) : OnTriggeredResult()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returning this as a result from the [onTriggered] method means that the implementation
|
||||||
|
* has _not_ taken care of the action and the system should show a Dialog using the
|
||||||
|
* given [AlertDialog] and [Expandable].
|
||||||
|
*/
|
||||||
|
data class ShowDialog(
|
||||||
|
val dialog: AlertDialog,
|
||||||
|
val expandable: Expandable?,
|
||||||
|
) : OnTriggeredResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
|
|
||||||
package com.android.systemui.keyguard.domain.interactor
|
package com.android.systemui.keyguard.domain.interactor
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.android.internal.widget.LockPatternUtils
|
import com.android.internal.widget.LockPatternUtils
|
||||||
|
import com.android.systemui.animation.DialogLaunchAnimator
|
||||||
import com.android.systemui.animation.Expandable
|
import com.android.systemui.animation.Expandable
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
@@ -35,15 +37,16 @@ import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAfforda
|
|||||||
import com.android.systemui.plugins.ActivityStarter
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
import com.android.systemui.settings.UserTracker
|
import com.android.systemui.settings.UserTracker
|
||||||
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract
|
import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract
|
||||||
|
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
class KeyguardQuickAffordanceInteractor
|
class KeyguardQuickAffordanceInteractor
|
||||||
@@ -57,6 +60,7 @@ constructor(
|
|||||||
private val activityStarter: ActivityStarter,
|
private val activityStarter: ActivityStarter,
|
||||||
private val featureFlags: FeatureFlags,
|
private val featureFlags: FeatureFlags,
|
||||||
private val repository: Lazy<KeyguardQuickAffordanceRepository>,
|
private val repository: Lazy<KeyguardQuickAffordanceRepository>,
|
||||||
|
private val launchAnimator: DialogLaunchAnimator,
|
||||||
) {
|
) {
|
||||||
private val isUsingRepository: Boolean
|
private val isUsingRepository: Boolean
|
||||||
get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)
|
get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)
|
||||||
@@ -131,6 +135,11 @@ constructor(
|
|||||||
expandable = expandable,
|
expandable = expandable,
|
||||||
)
|
)
|
||||||
is KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled -> Unit
|
is KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled -> Unit
|
||||||
|
is KeyguardQuickAffordanceConfig.OnTriggeredResult.ShowDialog ->
|
||||||
|
showDialog(
|
||||||
|
result.dialog,
|
||||||
|
result.expandable,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +288,19 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showDialog(dialog: AlertDialog, expandable: Expandable?) {
|
||||||
|
expandable?.dialogLaunchController()?.let { controller ->
|
||||||
|
SystemUIDialog.applyFlags(dialog)
|
||||||
|
SystemUIDialog.setShowForAllUsers(dialog, true)
|
||||||
|
SystemUIDialog.registerDismissListener(dialog)
|
||||||
|
SystemUIDialog.setDialogSize(dialog)
|
||||||
|
launchAnimator.show(
|
||||||
|
dialog,
|
||||||
|
controller
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun launchQuickAffordance(
|
private fun launchQuickAffordance(
|
||||||
intent: Intent,
|
intent: Intent,
|
||||||
canShowWhileLocked: Boolean,
|
canShowWhileLocked: Boolean,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.internal.widget.LockPatternUtils
|
import com.android.internal.widget.LockPatternUtils
|
||||||
import com.android.systemui.SystemUIAppComponentFactoryBase
|
import com.android.systemui.SystemUIAppComponentFactoryBase
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.animation.DialogLaunchAnimator
|
||||||
import com.android.systemui.flags.FakeFeatureFlags
|
import com.android.systemui.flags.FakeFeatureFlags
|
||||||
import com.android.systemui.flags.Flags
|
import com.android.systemui.flags.Flags
|
||||||
import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
|
import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
|
||||||
@@ -84,6 +85,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var previewRenderer: KeyguardPreviewRenderer
|
@Mock private lateinit var previewRenderer: KeyguardPreviewRenderer
|
||||||
@Mock private lateinit var backgroundHandler: Handler
|
@Mock private lateinit var backgroundHandler: Handler
|
||||||
@Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
|
@Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
|
||||||
|
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
|
||||||
|
|
||||||
private lateinit var underTest: KeyguardQuickAffordanceProvider
|
private lateinit var underTest: KeyguardQuickAffordanceProvider
|
||||||
|
|
||||||
@@ -170,6 +172,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() {
|
|||||||
set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
|
set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
|
||||||
},
|
},
|
||||||
repository = { quickAffordanceRepository },
|
repository = { quickAffordanceRepository },
|
||||||
|
launchAnimator = launchAnimator,
|
||||||
)
|
)
|
||||||
underTest.previewManager =
|
underTest.previewManager =
|
||||||
KeyguardRemotePreviewManager(
|
KeyguardRemotePreviewManager(
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 androidx.test.filters.SmallTest
|
||||||
|
import com.android.settingslib.notification.EnableZenModeDialog
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.animation.Expandable
|
||||||
|
import com.android.systemui.common.shared.model.ContentDescription
|
||||||
|
import com.android.systemui.common.shared.model.Icon
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
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.mockito.argumentCaptor
|
||||||
|
import com.android.systemui.util.mockito.eq
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.android.systemui.util.settings.FakeSettings
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.TestDispatcher
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
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(JUnit4::class)
|
||||||
|
class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var zenModeController: ZenModeController
|
||||||
|
@Mock private lateinit var userTracker: UserTracker
|
||||||
|
@Mock private lateinit var conditionUri: Uri
|
||||||
|
@Mock private lateinit var enableZenModeDialog: EnableZenModeDialog
|
||||||
|
@Captor private lateinit var spyZenMode: ArgumentCaptor<Int>
|
||||||
|
@Captor private lateinit var spyConditionId: ArgumentCaptor<Uri?>
|
||||||
|
private lateinit var settings: FakeSettings
|
||||||
|
|
||||||
|
private lateinit var underTest: DoNotDisturbQuickAffordanceConfig
|
||||||
|
private lateinit var testDispatcher: TestDispatcher
|
||||||
|
private lateinit var testScope: TestScope
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
testDispatcher = StandardTestDispatcher()
|
||||||
|
testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
|
settings = FakeSettings()
|
||||||
|
|
||||||
|
underTest = DoNotDisturbQuickAffordanceConfig(
|
||||||
|
context,
|
||||||
|
zenModeController,
|
||||||
|
settings,
|
||||||
|
userTracker,
|
||||||
|
testDispatcher,
|
||||||
|
conditionUri,
|
||||||
|
enableZenModeDialog,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dnd not available - picker state hidden`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(false)
|
||||||
|
|
||||||
|
//when
|
||||||
|
val result = underTest.getPickerScreenState()
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertEquals(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dnd available - picker state visible`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(true)
|
||||||
|
|
||||||
|
//when
|
||||||
|
val result = underTest.getPickerScreenState()
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertEquals(KeyguardQuickAffordanceConfig.PickerScreenState.Default, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `onTriggered - dnd mode is not ZEN_MODE_OFF - set to ZEN_MODE_OFF`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(true)
|
||||||
|
whenever(zenModeController.zen).thenReturn(-1)
|
||||||
|
settings.putInt(Settings.Secure.ZEN_DURATION, -2)
|
||||||
|
collectLastValue(underTest.lockScreenState)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
//when
|
||||||
|
val result = underTest.onTriggered(null)
|
||||||
|
verify(zenModeController).setZen(spyZenMode.capture(), spyConditionId.capture(), eq(DoNotDisturbQuickAffordanceConfig.TAG))
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result)
|
||||||
|
assertEquals(ZEN_MODE_OFF, spyZenMode.value)
|
||||||
|
assertNull(spyConditionId.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `onTriggered - dnd mode is ZEN_MODE_OFF - setting is FOREVER - set zen with no condition`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(true)
|
||||||
|
whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
|
||||||
|
settings.putInt(Settings.Secure.ZEN_DURATION, ZEN_DURATION_FOREVER)
|
||||||
|
collectLastValue(underTest.lockScreenState)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
//when
|
||||||
|
val result = underTest.onTriggered(null)
|
||||||
|
verify(zenModeController).setZen(spyZenMode.capture(), spyConditionId.capture(), eq(DoNotDisturbQuickAffordanceConfig.TAG))
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result)
|
||||||
|
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, spyZenMode.value)
|
||||||
|
assertNull(spyConditionId.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `onTriggered - dnd mode is ZEN_MODE_OFF - setting is not FOREVER or PROMPT - set zen with condition`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(true)
|
||||||
|
whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
|
||||||
|
settings.putInt(Settings.Secure.ZEN_DURATION, -900)
|
||||||
|
collectLastValue(underTest.lockScreenState)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
//when
|
||||||
|
val result = underTest.onTriggered(null)
|
||||||
|
verify(zenModeController).setZen(spyZenMode.capture(), spyConditionId.capture(), eq(DoNotDisturbQuickAffordanceConfig.TAG))
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result)
|
||||||
|
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, spyZenMode.value)
|
||||||
|
assertEquals(conditionUri, spyConditionId.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `onTriggered - dnd mode is ZEN_MODE_OFF - setting is PROMPT - show dialog`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
val expandable: Expandable = mock()
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(true)
|
||||||
|
whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
|
||||||
|
settings.putInt(Settings.Secure.ZEN_DURATION, ZEN_DURATION_PROMPT)
|
||||||
|
whenever(enableZenModeDialog.createDialog()).thenReturn(mock())
|
||||||
|
collectLastValue(underTest.lockScreenState)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
//when
|
||||||
|
val result = underTest.onTriggered(expandable)
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertTrue(result is KeyguardQuickAffordanceConfig.OnTriggeredResult.ShowDialog)
|
||||||
|
assertEquals(expandable, (result as KeyguardQuickAffordanceConfig.OnTriggeredResult.ShowDialog).expandable)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `lockScreenState - dndAvailable starts as true - changes to false - State moves to Hidden`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(true)
|
||||||
|
val callbackCaptor: ArgumentCaptor<ZenModeController.Callback> = argumentCaptor()
|
||||||
|
val valueSnapshot = collectLastValue(underTest.lockScreenState)
|
||||||
|
val secondLastValue = valueSnapshot()
|
||||||
|
verify(zenModeController).addCallback(callbackCaptor.capture())
|
||||||
|
|
||||||
|
//when
|
||||||
|
callbackCaptor.value.onZenAvailableChanged(false)
|
||||||
|
val lastValue = valueSnapshot()
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertTrue(secondLastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
|
||||||
|
assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `lockScreenState - dndMode starts as ZEN_MODE_OFF - changes to not OFF - State moves to Visible`() = testScope.runTest {
|
||||||
|
//given
|
||||||
|
whenever(zenModeController.isZenAvailable).thenReturn(true)
|
||||||
|
whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
|
||||||
|
val valueSnapshot = collectLastValue(underTest.lockScreenState)
|
||||||
|
val secondLastValue = valueSnapshot()
|
||||||
|
val callbackCaptor: ArgumentCaptor<ZenModeController.Callback> = argumentCaptor()
|
||||||
|
verify(zenModeController).addCallback(callbackCaptor.capture())
|
||||||
|
|
||||||
|
//when
|
||||||
|
callbackCaptor.value.onZenChanged(ZEN_MODE_IMPORTANT_INTERRUPTIONS)
|
||||||
|
val lastValue = valueSnapshot()
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertEquals(
|
||||||
|
KeyguardQuickAffordanceConfig.LockScreenState.Visible(
|
||||||
|
Icon.Resource(
|
||||||
|
R.drawable.qs_dnd_icon_off,
|
||||||
|
ContentDescription.Resource(R.string.dnd_is_off)
|
||||||
|
),
|
||||||
|
ActivationState.Inactive
|
||||||
|
),
|
||||||
|
secondLastValue,
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
KeyguardQuickAffordanceConfig.LockScreenState.Visible(
|
||||||
|
Icon.Resource(
|
||||||
|
R.drawable.qs_dnd_icon_on,
|
||||||
|
ContentDescription.Resource(R.string.dnd_is_on)
|
||||||
|
),
|
||||||
|
ActivationState.Active
|
||||||
|
),
|
||||||
|
lastValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.internal.widget.LockPatternUtils
|
import com.android.internal.widget.LockPatternUtils
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||||
|
import com.android.systemui.animation.DialogLaunchAnimator
|
||||||
import com.android.systemui.animation.Expandable
|
import com.android.systemui.animation.Expandable
|
||||||
import com.android.systemui.common.shared.model.ContentDescription
|
import com.android.systemui.common.shared.model.ContentDescription
|
||||||
import com.android.systemui.common.shared.model.Icon
|
import com.android.systemui.common.shared.model.Icon
|
||||||
@@ -214,6 +215,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var activityStarter: ActivityStarter
|
@Mock private lateinit var activityStarter: ActivityStarter
|
||||||
@Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
|
@Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
|
||||||
@Mock private lateinit var expandable: Expandable
|
@Mock private lateinit var expandable: Expandable
|
||||||
|
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
|
||||||
|
|
||||||
private lateinit var underTest: KeyguardQuickAffordanceInteractor
|
private lateinit var underTest: KeyguardQuickAffordanceInteractor
|
||||||
|
|
||||||
@@ -308,6 +310,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
|
|||||||
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
|
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
|
||||||
},
|
},
|
||||||
repository = { quickAffordanceRepository },
|
repository = { quickAffordanceRepository },
|
||||||
|
launchAnimator = launchAnimator,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.internal.widget.LockPatternUtils
|
import com.android.internal.widget.LockPatternUtils
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.animation.DialogLaunchAnimator
|
||||||
import com.android.systemui.common.shared.model.ContentDescription
|
import com.android.systemui.common.shared.model.ContentDescription
|
||||||
import com.android.systemui.common.shared.model.Icon
|
import com.android.systemui.common.shared.model.Icon
|
||||||
import com.android.systemui.coroutines.collectLastValue
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
@@ -73,6 +74,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
||||||
@Mock private lateinit var userTracker: UserTracker
|
@Mock private lateinit var userTracker: UserTracker
|
||||||
@Mock private lateinit var activityStarter: ActivityStarter
|
@Mock private lateinit var activityStarter: ActivityStarter
|
||||||
|
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
|
||||||
|
|
||||||
private lateinit var underTest: KeyguardQuickAffordanceInteractor
|
private lateinit var underTest: KeyguardQuickAffordanceInteractor
|
||||||
|
|
||||||
@@ -171,6 +173,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
|
|||||||
activityStarter = activityStarter,
|
activityStarter = activityStarter,
|
||||||
featureFlags = featureFlags,
|
featureFlags = featureFlags,
|
||||||
repository = { quickAffordanceRepository },
|
repository = { quickAffordanceRepository },
|
||||||
|
launchAnimator = launchAnimator,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import android.os.UserHandle
|
|||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.internal.widget.LockPatternUtils
|
import com.android.internal.widget.LockPatternUtils
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.animation.DialogLaunchAnimator
|
||||||
import com.android.systemui.animation.Expandable
|
import com.android.systemui.animation.Expandable
|
||||||
import com.android.systemui.common.shared.model.Icon
|
import com.android.systemui.common.shared.model.Icon
|
||||||
import com.android.systemui.coroutines.collectLastValue
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
@@ -82,6 +83,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
||||||
@Mock private lateinit var userTracker: UserTracker
|
@Mock private lateinit var userTracker: UserTracker
|
||||||
@Mock private lateinit var activityStarter: ActivityStarter
|
@Mock private lateinit var activityStarter: ActivityStarter
|
||||||
|
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
|
||||||
|
|
||||||
private lateinit var underTest: KeyguardBottomAreaViewModel
|
private lateinit var underTest: KeyguardBottomAreaViewModel
|
||||||
|
|
||||||
@@ -191,6 +193,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
|
|||||||
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
|
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
|
||||||
},
|
},
|
||||||
repository = { quickAffordanceRepository },
|
repository = { quickAffordanceRepository },
|
||||||
|
launchAnimator = launchAnimator,
|
||||||
),
|
),
|
||||||
bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository),
|
bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository),
|
||||||
burnInHelperWrapper = burnInHelperWrapper,
|
burnInHelperWrapper = burnInHelperWrapper,
|
||||||
|
|||||||
Reference in New Issue
Block a user