Support for unavailable and disabled affordances. am: af8fd1b3c5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20441246

Change-Id: I6282dd626c1d84815aabf567ee144330954b417c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Alejandro Nijamkin
2022-11-21 19:20:25 +00:00
committed by Automerger Merge Worker
18 changed files with 467 additions and 69 deletions

View File

@@ -2679,4 +2679,50 @@
<!-- Time format for the Dream Time Complication for 24-hour time format [CHAR LIMIT=NONE] --> <!-- Time format for the Dream Time Complication for 24-hour time format [CHAR LIMIT=NONE] -->
<string name="dream_time_complication_24_hr_time_format">kk:mm</string> <string name="dream_time_complication_24_hr_time_format">kk:mm</string>
<!--
Template for an action that opens a specific app. [CHAR LIMIT=16]
-->
<string name="keyguard_affordance_enablement_dialog_action_template">Open <xliff:g id="appName" example="Wallet">%1$s</xliff:g></string>
<!--
Template for a message shown right before a list of instructions that tell the user what to do
in order to enable a shortcut to a specific app. [CHAR LIMIT=NONE]
-->
<string name="keyguard_affordance_enablement_dialog_message">To add the <xliff:g id="appName" example="Wallet">%1$s</xliff:g> app as a shortcut, make sure</string>
<!--
Requirement for the wallet app to be available for the user to use. This is shown as part of a
bulleted list of requirements. When all requirements are met, the app can be accessed through a
shortcut button on the lock screen. [CHAR LIMIT=NONE].
-->
<string name="keyguard_affordance_enablement_dialog_wallet_instruction_1">&#8226; The app is set up</string>
<!--
Requirement for the wallet app to be available for the user to use. This is shown as part of a
bulleted list of requirements. When all requirements are met, the app can be accessed through a
shortcut button on the lock screen. [CHAR LIMIT=NONE].
-->
<string name="keyguard_affordance_enablement_dialog_wallet_instruction_2">&#8226; At least one card has been added to Wallet</string>
<!--
Requirement for the QR code scanner functionality to be available for the user to use. This is
shown as part of a bulleted list of requirements. When all requirements are met, the piece of
functionality can be accessed through a shortcut button on the lock screen. [CHAR LIMIT=NONE].
-->
<string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction">&#8226; Install a camera app</string>
<!--
Requirement for the home app to be available for the user to use. This is shown as part of a
bulleted list of requirements. When all requirements are met, the app can be accessed through a
shortcut button on the lock screen. [CHAR LIMIT=NONE].
-->
<string name="keyguard_affordance_enablement_dialog_home_instruction_1">&#8226; The app is set up</string>
<!--
Requirement for the home app to be available for the user to use. This is shown as part of a
bulleted list of requirements. When all requirements are met, the app can be accessed through a
shortcut button on the lock screen. [CHAR LIMIT=NONE].
-->
<string name="keyguard_affordance_enablement_dialog_home_instruction_2">&#8226; At least one device is available</string>
</resources> </resources>

View File

@@ -67,6 +67,8 @@ object KeyguardQuickAffordanceProviderContract {
object AffordanceTable { object AffordanceTable {
const val TABLE_NAME = "affordances" const val TABLE_NAME = "affordances"
val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build() val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
const val ENABLEMENT_INSTRUCTIONS_DELIMITER = "]["
const val COMPONENT_NAME_SEPARATOR = "/"
object Columns { object Columns {
/** String. Unique ID for this affordance. */ /** String. Unique ID for this affordance. */
@@ -78,6 +80,25 @@ object KeyguardQuickAffordanceProviderContract {
* ID from the system UI package. * ID from the system UI package.
*/ */
const val ICON = "icon" const val ICON = "icon"
/** Integer. `1` if the affordance is enabled or `0` if it disabled. */
const val IS_ENABLED = "is_enabled"
/**
* String. List of strings, delimited by [ENABLEMENT_INSTRUCTIONS_DELIMITER] to be shown
* to the user if the affordance is disabled and the user selects the affordance. The
* first one is a title while the rest are the steps needed to re-enable the affordance.
*/
const val ENABLEMENT_INSTRUCTIONS = "enablement_instructions"
/**
* String. Optional label for a button that, when clicked, opens a destination activity
* where the user can re-enable the disabled affordance.
*/
const val ENABLEMENT_ACTION_TEXT = "enablement_action_text"
/**
* String. Optional package name and activity action string, delimited by
* [COMPONENT_NAME_SEPARATOR] to use with an `Intent` to start an activity that opens a
* destination where the user can re-enable the disabled affordance.
*/
const val ENABLEMENT_COMPONENT_NAME = "enablement_action_intent"
} }
} }

View File

@@ -31,6 +31,7 @@ import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCall
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.runBlocking
class KeyguardQuickAffordanceProvider : class KeyguardQuickAffordanceProvider :
ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer { ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer {
@@ -118,9 +119,9 @@ class KeyguardQuickAffordanceProvider :
sortOrder: String?, sortOrder: String?,
): Cursor? { ): Cursor? {
return when (uriMatcher.match(uri)) { return when (uriMatcher.match(uri)) {
MATCH_CODE_ALL_AFFORDANCES -> queryAffordances() MATCH_CODE_ALL_AFFORDANCES -> runBlocking { queryAffordances() }
MATCH_CODE_ALL_SLOTS -> querySlots() MATCH_CODE_ALL_SLOTS -> querySlots()
MATCH_CODE_ALL_SELECTIONS -> querySelections() MATCH_CODE_ALL_SELECTIONS -> runBlocking { querySelections() }
MATCH_CODE_ALL_FLAGS -> queryFlags() MATCH_CODE_ALL_FLAGS -> queryFlags()
else -> null else -> null
} }
@@ -194,7 +195,7 @@ class KeyguardQuickAffordanceProvider :
} }
} }
private fun querySelections(): Cursor { private suspend fun querySelections(): Cursor {
return MatrixCursor( return MatrixCursor(
arrayOf( arrayOf(
Contract.SelectionTable.Columns.SLOT_ID, Contract.SelectionTable.Columns.SLOT_ID,
@@ -219,12 +220,16 @@ class KeyguardQuickAffordanceProvider :
} }
} }
private fun queryAffordances(): Cursor { private suspend fun queryAffordances(): Cursor {
return MatrixCursor( return MatrixCursor(
arrayOf( arrayOf(
Contract.AffordanceTable.Columns.ID, Contract.AffordanceTable.Columns.ID,
Contract.AffordanceTable.Columns.NAME, Contract.AffordanceTable.Columns.NAME,
Contract.AffordanceTable.Columns.ICON, Contract.AffordanceTable.Columns.ICON,
Contract.AffordanceTable.Columns.IS_ENABLED,
Contract.AffordanceTable.Columns.ENABLEMENT_INSTRUCTIONS,
Contract.AffordanceTable.Columns.ENABLEMENT_ACTION_TEXT,
Contract.AffordanceTable.Columns.ENABLEMENT_COMPONENT_NAME,
) )
) )
.apply { .apply {
@@ -234,6 +239,12 @@ class KeyguardQuickAffordanceProvider :
representation.id, representation.id,
representation.name, representation.name,
representation.iconResourceId, representation.iconResourceId,
if (representation.isEnabled) 1 else 0,
representation.instructions?.joinToString(
Contract.AffordanceTable.ENABLEMENT_INSTRUCTIONS_DELIMITER
),
representation.actionText,
representation.actionComponentName,
) )
) )
} }

View File

@@ -20,6 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import com.android.systemui.R
import com.android.systemui.animation.Expandable import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -45,7 +46,7 @@ import kotlinx.coroutines.flow.flowOf
class HomeControlsKeyguardQuickAffordanceConfig class HomeControlsKeyguardQuickAffordanceConfig
@Inject @Inject
constructor( constructor(
@Application context: Context, @Application private val context: Context,
private val component: ControlsComponent, private val component: ControlsComponent,
) : KeyguardQuickAffordanceConfig { ) : KeyguardQuickAffordanceConfig {
@@ -66,6 +67,36 @@ constructor(
} }
} }
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
if (!component.isEnabled()) {
return KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
}
val currentServices =
component.getControlsListingController().getOrNull()?.getCurrentServices()
val hasFavorites =
component.getControlsController().getOrNull()?.getFavorites()?.isNotEmpty() == true
if (currentServices.isNullOrEmpty() || !hasFavorites) {
return KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
instructions =
listOf(
context.getString(
R.string.keyguard_affordance_enablement_dialog_message,
pickerName,
),
context.getString(
R.string.keyguard_affordance_enablement_dialog_home_instruction_1
),
context.getString(
R.string.keyguard_affordance_enablement_dialog_home_instruction_2
),
),
)
}
return KeyguardQuickAffordanceConfig.PickerScreenState.Default
}
override fun onTriggered( override fun onTriggered(
expandable: Expandable?, expandable: Expandable?,
): KeyguardQuickAffordanceConfig.OnTriggeredResult { ): KeyguardQuickAffordanceConfig.OnTriggeredResult {

View File

@@ -21,6 +21,7 @@ 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
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** Defines interface that can act as data source for a single quick affordance model. */ /** Defines interface that can act as data source for a single quick affordance model. */
@@ -40,6 +41,12 @@ interface KeyguardQuickAffordanceConfig {
*/ */
val lockScreenState: Flow<LockScreenState> val lockScreenState: Flow<LockScreenState>
/**
* Returns the [PickerScreenState] representing the affordance in the settings or selector
* experience.
*/
suspend fun getPickerScreenState(): PickerScreenState = PickerScreenState.Default
/** /**
* Notifies that the affordance was clicked by the user. * Notifies that the affordance was clicked by the user.
* *
@@ -48,6 +55,58 @@ interface KeyguardQuickAffordanceConfig {
*/ */
fun onTriggered(expandable: Expandable?): OnTriggeredResult fun onTriggered(expandable: Expandable?): OnTriggeredResult
/**
* Encapsulates the state of a quick affordance within the context of the settings or selector
* experience.
*/
sealed class PickerScreenState {
/** The picker shows the item for selecting this affordance as it normally would. */
object Default : PickerScreenState()
/**
* The picker does not show an item for selecting this affordance as it is not supported on
* the device at all. For example, missing hardware requirements.
*/
object UnavailableOnDevice : PickerScreenState()
/**
* The picker shows the item for selecting this affordance as disabled. Clicking on it will
* show the given instructions to the user. If [actionText] and [actionComponentName] are
* provided (optional) a button will be shown to open an activity to help the user complete
* the steps described in the instructions.
*/
data class Disabled(
/** List of human-readable instructions for setting up the quick affordance. */
val instructions: List<String>,
/**
* Optional text to display on a button that the user can click to start a flow to go
* and set up the quick affordance and make it enabled.
*/
val actionText: String? = null,
/**
* Optional component name to be able to build an `Intent` that opens an `Activity` for
* the user to be able to set up the quick affordance and make it enabled.
*
* This is either just an action for the `Intent` or a package name and action,
* separated by [Contract.AffordanceTable.COMPONENT_NAME_SEPARATOR] for convenience, you
* can use the [componentName] function.
*/
val actionComponentName: String? = null,
) : PickerScreenState() {
init {
check(instructions.isNotEmpty()) { "Instructions must not be empty!" }
check(
(actionText.isNullOrEmpty() && actionComponentName.isNullOrEmpty()) ||
(!actionText.isNullOrEmpty() && !actionComponentName.isNullOrEmpty())
) {
"actionText and actionComponentName must either both be null/empty or both be" +
" non-empty!"
}
}
}
}
/** /**
* Encapsulates the state of a "quick affordance" in the keyguard bottom area (for example, a * Encapsulates the state of a "quick affordance" in the keyguard bottom area (for example, a
* button on the lock-screen). * button on the lock-screen).
@@ -83,4 +142,18 @@ interface KeyguardQuickAffordanceConfig {
val canShowWhileLocked: Boolean, val canShowWhileLocked: Boolean,
) : OnTriggeredResult() ) : OnTriggeredResult()
} }
companion object {
fun componentName(
packageName: String? = null,
action: String?,
): String? {
return when {
action.isNullOrEmpty() -> null
!packageName.isNullOrEmpty() ->
"$packageName${Contract.AffordanceTable.COMPONENT_NAME_SEPARATOR}$action"
else -> action
}
}
}
} }

View File

@@ -36,7 +36,7 @@ import kotlinx.coroutines.flow.Flow
class QrCodeScannerKeyguardQuickAffordanceConfig class QrCodeScannerKeyguardQuickAffordanceConfig
@Inject @Inject
constructor( constructor(
@Application context: Context, @Application private val context: Context,
private val controller: QRCodeScannerController, private val controller: QRCodeScannerController,
) : KeyguardQuickAffordanceConfig { ) : KeyguardQuickAffordanceConfig {
@@ -75,6 +75,28 @@ constructor(
} }
} }
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return when {
!controller.isAvailableOnDevice ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
!controller.isAbleToOpenCameraApp ->
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
instructions =
listOf(
context.getString(
R.string.keyguard_affordance_enablement_dialog_message,
pickerName,
),
context.getString(
R.string
.keyguard_affordance_enablement_dialog_qr_scanner_instruction
),
),
)
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default
}
}
override fun onTriggered( override fun onTriggered(
expandable: Expandable?, expandable: Expandable?,
): KeyguardQuickAffordanceConfig.OnTriggeredResult { ): KeyguardQuickAffordanceConfig.OnTriggeredResult {

View File

@@ -18,10 +18,12 @@
package com.android.systemui.keyguard.data.quickaffordance package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.service.quickaccesswallet.GetWalletCardsError import android.service.quickaccesswallet.GetWalletCardsError
import android.service.quickaccesswallet.GetWalletCardsResponse import android.service.quickaccesswallet.GetWalletCardsResponse
import android.service.quickaccesswallet.QuickAccessWalletClient import android.service.quickaccesswallet.QuickAccessWalletClient
import android.service.quickaccesswallet.WalletCard
import android.util.Log import android.util.Log
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.animation.Expandable import com.android.systemui.animation.Expandable
@@ -31,25 +33,27 @@ 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.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.Companion.componentName
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.wallet.controller.QuickAccessWalletController import com.android.systemui.wallet.controller.QuickAccessWalletController
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.suspendCancellableCoroutine
/** Quick access wallet quick affordance data source. */ /** Quick access wallet quick affordance data source. */
@SysUISingleton @SysUISingleton
class QuickAccessWalletKeyguardQuickAffordanceConfig class QuickAccessWalletKeyguardQuickAffordanceConfig
@Inject @Inject
constructor( constructor(
@Application context: Context, @Application private val context: Context,
private val walletController: QuickAccessWalletController, private val walletController: QuickAccessWalletController,
private val activityStarter: ActivityStarter, private val activityStarter: ActivityStarter,
) : KeyguardQuickAffordanceConfig { ) : KeyguardQuickAffordanceConfig {
override val key: String = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET override val key: String = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
override val pickerName = context.getString(R.string.accessibility_wallet_button) override val pickerName: String = context.getString(R.string.accessibility_wallet_button)
override val pickerIconResourceId = R.drawable.ic_wallet_lockscreen override val pickerIconResourceId = R.drawable.ic_wallet_lockscreen
@@ -58,10 +62,11 @@ constructor(
val callback = val callback =
object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback { object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) { override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) {
val hasCards = response?.walletCards?.isNotEmpty() == true
trySendWithFailureLogging( trySendWithFailureLogging(
state( state(
isFeatureEnabled = walletController.isWalletEnabled, isFeatureEnabled = walletController.isWalletEnabled,
hasCard = response?.walletCards?.isNotEmpty() == true, hasCard = hasCards,
tileIcon = walletController.walletClient.tileIcon, tileIcon = walletController.walletClient.tileIcon,
), ),
TAG, TAG,
@@ -93,6 +98,44 @@ constructor(
} }
} }
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return when {
!walletController.isWalletEnabled ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
walletController.walletClient.tileIcon == null || queryCards().isEmpty() -> {
val componentName =
walletController.walletClient.createWalletSettingsIntent().toComponentName()
val actionText =
if (componentName != null) {
context.getString(
R.string.keyguard_affordance_enablement_dialog_action_template,
pickerName,
)
} else {
null
}
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
instructions =
listOf(
context.getString(
R.string.keyguard_affordance_enablement_dialog_message,
pickerName,
),
context.getString(
R.string.keyguard_affordance_enablement_dialog_wallet_instruction_1
),
context.getString(
R.string.keyguard_affordance_enablement_dialog_wallet_instruction_2
),
),
actionText = actionText,
actionComponentName = componentName,
)
}
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default
}
}
override fun onTriggered( override fun onTriggered(
expandable: Expandable?, expandable: Expandable?,
): KeyguardQuickAffordanceConfig.OnTriggeredResult { ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
@@ -104,6 +147,24 @@ constructor(
return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
} }
private suspend fun queryCards(): List<WalletCard> {
return suspendCancellableCoroutine { continuation ->
val callback =
object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) {
continuation.resumeWith(
Result.success(response?.walletCards ?: emptyList())
)
}
override fun onWalletCardRetrievalError(error: GetWalletCardsError?) {
continuation.resumeWith(Result.success(emptyList()))
}
}
walletController.queryWalletCards(callback)
}
}
private fun state( private fun state(
isFeatureEnabled: Boolean, isFeatureEnabled: Boolean,
hasCard: Boolean, hasCard: Boolean,
@@ -125,6 +186,14 @@ constructor(
} }
} }
private fun Intent?.toComponentName(): String? {
if (this == null) {
return null
}
return componentName(packageName = `package`, action = action)
}
companion object { companion object {
private const val TAG = "QuickAccessWalletKeyguardQuickAffordanceConfig" private const val TAG = "QuickAccessWalletKeyguardQuickAffordanceConfig"
} }

View File

@@ -121,16 +121,30 @@ constructor(
} }
/** /**
* Returns the list of representation objects for all known affordances, regardless of what is * Returns the list of representation objects for all known, device-available affordances,
* selected. This is useful for building experiences like the picker/selector or user settings * regardless of what is selected. This is useful for building experiences like the
* so the user can see everything that can be selected in a menu. * picker/selector or user settings so the user can see everything that can be selected in a
* menu.
*/ */
fun getAffordancePickerRepresentations(): List<KeyguardQuickAffordancePickerRepresentation> { suspend fun getAffordancePickerRepresentations():
return configs.map { config -> List<KeyguardQuickAffordancePickerRepresentation> {
return configs
.associateWith { config -> config.getPickerScreenState() }
.filterNot { (_, pickerState) ->
pickerState is KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
}
.map { (config, pickerState) ->
val disabledPickerState =
pickerState as? KeyguardQuickAffordanceConfig.PickerScreenState.Disabled
KeyguardQuickAffordancePickerRepresentation( KeyguardQuickAffordancePickerRepresentation(
id = config.key, id = config.key,
name = config.pickerName, name = config.pickerName,
iconResourceId = config.pickerIconResourceId, iconResourceId = config.pickerIconResourceId,
isEnabled =
pickerState is KeyguardQuickAffordanceConfig.PickerScreenState.Default,
instructions = disabledPickerState?.instructions,
actionText = disabledPickerState?.actionText,
actionComponentName = disabledPickerState?.actionComponentName,
) )
} }
} }

View File

@@ -189,7 +189,7 @@ constructor(
} }
/** Returns affordance IDs indexed by slot ID, for all known slots. */ /** Returns affordance IDs indexed by slot ID, for all known slots. */
fun getSelections(): Map<String, List<KeyguardQuickAffordancePickerRepresentation>> { suspend fun getSelections(): Map<String, List<KeyguardQuickAffordancePickerRepresentation>> {
check(isUsingRepository) check(isUsingRepository)
val slots = repository.get().getSlotPickerRepresentations() val slots = repository.get().getSlotPickerRepresentations()
@@ -310,7 +310,8 @@ constructor(
return Pair(splitUp[0], splitUp[1]) return Pair(splitUp[0], splitUp[1])
} }
fun getAffordancePickerRepresentations(): List<KeyguardQuickAffordancePickerRepresentation> { suspend fun getAffordancePickerRepresentations():
List<KeyguardQuickAffordancePickerRepresentation> {
check(isUsingRepository) check(isUsingRepository)
return repository.get().getAffordancePickerRepresentations() return repository.get().getAffordancePickerRepresentations()

View File

@@ -27,4 +27,22 @@ data class KeyguardQuickAffordancePickerRepresentation(
val id: String, val id: String,
val name: String, val name: String,
@DrawableRes val iconResourceId: Int, @DrawableRes val iconResourceId: Int,
/** Whether this quick affordance is enabled. */
val isEnabled: Boolean = true,
/** If not enabled, the list of user-visible steps to re-enable it. */
val instructions: List<String>? = null,
/**
* If not enabled, an optional label for a button that takes the user to a destination where
* they can re-enable it.
*/
val actionText: String? = null,
/**
* If not enabled, an optional component name (package and action) for a button that takes the
* user to a destination where they can re-enable it.
*/
val actionComponentName: String? = null,
) )

View File

@@ -158,14 +158,18 @@ public class QRCodeScannerController implements
* Returns true if lock screen entry point for QR Code Scanner is to be enabled. * Returns true if lock screen entry point for QR Code Scanner is to be enabled.
*/ */
public boolean isEnabledForLockScreenButton() { public boolean isEnabledForLockScreenButton() {
return mQRCodeScannerEnabled && mIntent != null && mConfigEnableLockScreenButton return mQRCodeScannerEnabled && isAbleToOpenCameraApp() && isAvailableOnDevice();
&& isActivityCallable(mIntent); }
/** Returns whether the feature is available on the device. */
public boolean isAvailableOnDevice() {
return mConfigEnableLockScreenButton;
} }
/** /**
* Returns true if quick settings entry point for QR Code Scanner is to be enabled. * Returns true if the feature can open a camera app on the device.
*/ */
public boolean isEnabledForQuickSettings() { public boolean isAbleToOpenCameraApp() {
return mIntent != null && isActivityCallable(mIntent); return mIntent != null && isActivityCallable(mIntent);
} }

View File

@@ -115,7 +115,7 @@ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> {
state.label = mContext.getString(R.string.qr_code_scanner_title); state.label = mContext.getString(R.string.qr_code_scanner_title);
state.contentDescription = state.label; state.contentDescription = state.label;
state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner); state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner);
state.state = mQRCodeScannerController.isEnabledForQuickSettings() ? Tile.STATE_INACTIVE state.state = mQRCodeScannerController.isAbleToOpenCameraApp() ? Tile.STATE_INACTIVE
: Tile.STATE_UNAVAILABLE; : Tile.STATE_UNAVAILABLE;
} }

View File

@@ -24,8 +24,9 @@ import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import java.util.Optional import java.util.*
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@@ -40,7 +41,6 @@ import org.mockito.ArgumentCaptor
import org.mockito.Captor import org.mockito.Captor
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@SmallTest @SmallTest
@@ -93,6 +93,14 @@ class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTes
whenever(component.getControlsController()).thenReturn(Optional.of(controlsController)) whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
whenever(component.getControlsListingController()) whenever(component.getControlsListingController())
.thenReturn(Optional.of(controlsListingController)) .thenReturn(Optional.of(controlsListingController))
whenever(controlsListingController.getCurrentServices())
.thenReturn(
if (hasServiceInfos) {
listOf(mock(), mock())
} else {
emptyList()
}
)
whenever(component.canShowWhileLockedSetting) whenever(component.canShowWhileLockedSetting)
.thenReturn(MutableStateFlow(canShowWhileLocked)) .thenReturn(MutableStateFlow(canShowWhileLocked))
whenever(component.getVisibility()) whenever(component.getVisibility())
@@ -144,6 +152,17 @@ class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTes
KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java
} }
) )
assertThat(underTest.getPickerScreenState())
.isInstanceOf(
when {
!isFeatureEnabled ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice::class
.java
hasServiceInfos && hasFavorites ->
KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java
}
)
job.cancel() job.cancel()
} }
} }

View File

@@ -24,17 +24,18 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.JUnit4 import org.junit.runners.JUnit4
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@SmallTest @SmallTest
@@ -134,6 +135,33 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
) )
} }
@Test
fun `getPickerScreenState - enabled if configured on device - can open camera`() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(true)
whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default)
}
@Test
fun `getPickerScreenState - disabled if configured on device - cannot open camera`() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(true)
whenever(controller.isAbleToOpenCameraApp).thenReturn(false)
assertThat(underTest.getPickerScreenState())
.isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java)
}
@Test
fun `getPickerScreenState - unavailable if not configured on device`() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(false)
whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
}
private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.LockScreenState?) { private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.LockScreenState?) {
assertThat(latest) assertThat(latest)
.isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java)

View File

@@ -33,9 +33,11 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.android.systemui.wallet.controller.QuickAccessWalletController import com.android.systemui.wallet.controller.QuickAccessWalletController
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@@ -44,6 +46,7 @@ import org.mockito.Mock
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest @SmallTest
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
@@ -59,7 +62,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
underTest = underTest =
QuickAccessWalletKeyguardQuickAffordanceConfig( QuickAccessWalletKeyguardQuickAffordanceConfig(
mock(), context,
walletController, walletController,
activityStarter, activityStarter,
) )
@@ -151,6 +154,44 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
) )
} }
@Test
fun `getPickerScreenState - default`() = runTest {
setUpState()
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default)
}
@Test
fun `getPickerScreenState - unavailable`() = runTest {
setUpState(
isWalletEnabled = false,
)
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
}
@Test
fun `getPickerScreenState - disabled when there is no icon`() = runTest {
setUpState(
hasWalletIcon = false,
)
assertThat(underTest.getPickerScreenState())
.isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java)
}
@Test
fun `getPickerScreenState - disabled when there is no card`() = runTest {
setUpState(
hasSelectedCard = false,
)
assertThat(underTest.getPickerScreenState())
.isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java)
}
private fun setUpState( private fun setUpState(
isWalletEnabled: Boolean = true, isWalletEnabled: Boolean = true,
isWalletQuerySuccessful: Boolean = true, isWalletQuerySuccessful: Boolean = true,

View File

@@ -133,7 +133,8 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() {
} }
@Test @Test
fun getAffordancePickerRepresentations() { fun getAffordancePickerRepresentations() =
runBlocking(IMMEDIATE) {
assertThat(underTest.getAffordancePickerRepresentations()) assertThat(underTest.getAffordancePickerRepresentations())
.isEqualTo( .isEqualTo(
listOf( listOf(

View File

@@ -31,7 +31,6 @@ import static org.mockito.Mockito.when;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.provider.Settings; import android.provider.Settings;
@@ -133,7 +132,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails(null); verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse(); assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isEnabledForQuickSettings()).isFalse(); assertThat(mController.isAbleToOpenCameraApp()).isFalse();
} }
@Test @Test
@@ -152,7 +151,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
} }
@Test @Test
@@ -162,7 +161,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
} }
@Test @Test
@@ -172,7 +171,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
} }
@Test @Test
@@ -182,7 +181,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails("abc/abc.def"); verifyActivityDetails("abc/abc.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
} }
@Test @Test
@@ -192,7 +191,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails(null); verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse(); assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isEnabledForQuickSettings()).isFalse(); assertThat(mController.isAbleToOpenCameraApp()).isFalse();
} }
@Test @Test
@@ -202,21 +201,21 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER, SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
"def/.ijk", false); "def/.ijk", false);
verifyActivityDetails("def/.ijk"); verifyActivityDetails("def/.ijk");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER, SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
null, false); null, false);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
// Once from setup + twice from this function // Once from setup + twice from this function
verify(mCallback, times(3)).onQRCodeScannerActivityChanged(); verify(mCallback, times(3)).onQRCodeScannerActivityChanged();
@@ -229,7 +228,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails(null); verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse(); assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isEnabledForQuickSettings()).isFalse(); assertThat(mController.isAbleToOpenCameraApp()).isFalse();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER, SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
@@ -237,14 +236,14 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
verifyActivityDetails("def/.ijk"); verifyActivityDetails("def/.ijk");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER, SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
null, false); null, false);
verifyActivityDetails(null); verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse(); assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isEnabledForQuickSettings()).isFalse(); assertThat(mController.isAbleToOpenCameraApp()).isFalse();
verify(mCallback, times(2)).onQRCodeScannerActivityChanged(); verify(mCallback, times(2)).onQRCodeScannerActivityChanged();
} }
@@ -296,19 +295,19 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "0", mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "0",
UserHandle.USER_CURRENT); UserHandle.USER_CURRENT);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isFalse(); assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "1", mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "1",
UserHandle.USER_CURRENT); UserHandle.USER_CURRENT);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
// Once from setup + twice from this function // Once from setup + twice from this function
verify(mCallback, times(3)).onQRCodeScannerPreferenceChanged(); verify(mCallback, times(3)).onQRCodeScannerPreferenceChanged();
} }
@@ -320,13 +319,13 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true); /* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE, mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE,
QR_CODE_SCANNER_PREFERENCE_CHANGE); QR_CODE_SCANNER_PREFERENCE_CHANGE);
verifyActivityDetails(null); verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse(); assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isEnabledForQuickSettings()).isFalse(); assertThat(mController.isAbleToOpenCameraApp()).isFalse();
// Unregister once again and make sure it affects the next register event // Unregister once again and make sure it affects the next register event
mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE, mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE,
@@ -335,7 +334,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
QR_CODE_SCANNER_PREFERENCE_CHANGE); QR_CODE_SCANNER_PREFERENCE_CHANGE);
verifyActivityDetails("abc/.def"); verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue(); assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
} }
@Test @Test
@@ -345,7 +344,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ false); /* enableOnLockScreen */ false);
assertThat(mController.getIntent()).isNotNull(); assertThat(mController.getIntent()).isNotNull();
assertThat(mController.isEnabledForLockScreenButton()).isFalse(); assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isEnabledForQuickSettings()).isTrue(); assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(getSettingsQRCodeDefaultComponent()).isNull(); assertThat(getSettingsQRCodeDefaultComponent()).isNull();
} }
} }

View File

@@ -108,7 +108,7 @@ public class QRCodeScannerTileTest extends SysuiTestCase {
@Test @Test
public void testQRCodeTileUnavailable() { public void testQRCodeTileUnavailable() {
when(mController.isEnabledForQuickSettings()).thenReturn(false); when(mController.isAbleToOpenCameraApp()).thenReturn(false);
QSTile.State state = new QSTile.State(); QSTile.State state = new QSTile.State();
mTile.handleUpdateState(state, null); mTile.handleUpdateState(state, null);
assertEquals(state.state, Tile.STATE_UNAVAILABLE); assertEquals(state.state, Tile.STATE_UNAVAILABLE);
@@ -116,7 +116,7 @@ public class QRCodeScannerTileTest extends SysuiTestCase {
@Test @Test
public void testQRCodeTileAvailable() { public void testQRCodeTileAvailable() {
when(mController.isEnabledForQuickSettings()).thenReturn(true); when(mController.isAbleToOpenCameraApp()).thenReturn(true);
QSTile.State state = new QSTile.State(); QSTile.State state = new QSTile.State();
mTile.handleUpdateState(state, null); mTile.handleUpdateState(state, null);
assertEquals(state.state, Tile.STATE_INACTIVE); assertEquals(state.state, Tile.STATE_INACTIVE);