[QR Scanner]: Fix the logic to initialize intent with default activity

- When the QR Scanner tile is not among active/enabled tiles and no QR scanner shortcut on lockscreen, then there won't be any observers registered for QRCodeScannerController, in that case, the Intent would be set to null
- Now, when user tries to set the QR scanner for lockscreen shortcut, it checks if intent is callable or not, and it returns false, as intent is set to null
- Also, enable QR scanner in lockscreen shortcut only when the configured activity is callable

Bug: 290862496, 289446172
Test: atest QRCodeScannerControllerTest, QRCodeScannerTileTest, QrCodeScannerKeyguardQuickAffordanceConfigTest
Test: Manual test by flashing on device and checking the capability of adding QR scanner as lockscreen shortcut even when the QRScanner tile is not among active/enabled tiles
Change-Id: I7c86fa5e8bbf79cc0e94807105e518136de4b206
This commit is contained in:
Avinash Vadlamudi
2023-07-13 17:40:28 +00:00
parent 224c03fb11
commit 41805a9beb
7 changed files with 45 additions and 65 deletions

View File

@@ -3052,13 +3052,6 @@
-->
<string name="wallet_quick_affordance_unavailable_configure_the_app">To add the Wallet app as a shortcut, make sure at least one card has been added</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="qr_scanner_quick_affordance_unavailable_explanation">To add the QR code scanner as a shortcut, make sure a camera app is installed</string>
<!--
Explains that the lock screen shortcut for the "home" app is not available because the app isn't
installed. This is shown as part of a dialog that explains to the user why they cannot select

View File

@@ -78,16 +78,8 @@ constructor(
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return when {
!controller.isAvailableOnDevice ->
!isEnabledForPickerStateOption() ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
!controller.isAbleToOpenCameraApp -> {
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
explanation =
context.getString(
R.string.qr_scanner_quick_affordance_unavailable_explanation
),
)
}
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default()
}
}
@@ -118,6 +110,11 @@ constructor(
}
}
/** Returns whether QR scanner be shown as one of available lockscreen shortcut option. */
private fun isEnabledForPickerStateOption(): Boolean {
return controller.isAbleToLaunchScannerActivity && controller.isAllowedOnLockScreen
}
companion object {
private const val TAG = "QrCodeScannerKeyguardQuickAffordanceConfig"
}

View File

@@ -120,6 +120,7 @@ public class QRCodeScannerController implements
mUserTracker = userTracker;
mConfigEnableLockScreenButton = mContext.getResources().getBoolean(
android.R.bool.config_enableQrCodeScannerOnLockScreen);
mExecutor.execute(this::updateQRCodeScannerActivityDetails);
}
/**
@@ -158,18 +159,18 @@ public class QRCodeScannerController implements
* Returns true if lock screen entry point for QR Code Scanner is to be enabled.
*/
public boolean isEnabledForLockScreenButton() {
return mQRCodeScannerEnabled && isAbleToOpenCameraApp() && isAvailableOnDevice();
return mQRCodeScannerEnabled && isAbleToLaunchScannerActivity() && isAllowedOnLockScreen();
}
/** Returns whether the feature is available on the device. */
public boolean isAvailableOnDevice() {
/** Returns whether the QR scanner button is allowed on lockscreen. */
public boolean isAllowedOnLockScreen() {
return mConfigEnableLockScreenButton;
}
/**
* Returns true if the feature can open a camera app on the device.
* Returns true if the feature can open the configured QR scanner activity.
*/
public boolean isAbleToOpenCameraApp() {
public boolean isAbleToLaunchScannerActivity() {
return mIntent != null && isActivityCallable(mIntent);
}
@@ -355,9 +356,6 @@ public class QRCodeScannerController implements
// Reset cached values to default as we are no longer listening
mOnDefaultQRCodeScannerChangedListener = null;
mQRCodeScannerActivity = null;
mIntent = null;
mComponentName = null;
}
private void notifyQRCodeScannerActivityChanged() {

View File

@@ -120,7 +120,7 @@ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> {
state.label = mContext.getString(R.string.qr_code_scanner_title);
state.contentDescription = state.label;
state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner);
state.state = mQRCodeScannerController.isAbleToOpenCameraApp() ? Tile.STATE_INACTIVE
state.state = mQRCodeScannerController.isAbleToLaunchScannerActivity() ? Tile.STATE_INACTIVE
: Tile.STATE_UNAVAILABLE;
// The assumption is that if the OEM has the QR code scanner module enabled then the scanner
// would go to "Unavailable" state only when GMS core is updating.

View File

@@ -137,27 +137,18 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
fun getPickerScreenState_enabledIfConfiguredOnDevice_canOpenCamera() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(true)
whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() = runTest {
whenever(controller.isAllowedOnLockScreen).thenReturn(true)
whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true)
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
}
@Test
fun getPickerScreenState_disabledIfConfiguredOnDevice_cannotOpenCamera() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(true)
whenever(controller.isAbleToOpenCameraApp).thenReturn(false)
assertThat(underTest.getPickerScreenState())
.isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java)
}
@Test
fun getPickerScreenState_unavailableIfNotConfiguredOnDevice() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(false)
whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() = runTest {
whenever(controller.isAllowedOnLockScreen).thenReturn(true)
whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false)
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)

View File

@@ -132,7 +132,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isAbleToOpenCameraApp()).isFalse();
assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
}
@Test
@@ -151,7 +151,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -161,7 +161,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -171,7 +171,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -181,7 +181,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/abc.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -191,7 +191,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isAbleToOpenCameraApp()).isFalse();
assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
}
@Test
@@ -201,24 +201,24 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
"def/.ijk", false);
verifyActivityDetails("def/.ijk");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
null, false);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
// Once from setup + twice from this function
verify(mCallback, times(3)).onQRCodeScannerActivityChanged();
// twice from this function
verify(mCallback, times(2)).onQRCodeScannerActivityChanged();
}
@Test
@@ -228,7 +228,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isAbleToOpenCameraApp()).isFalse();
assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
@@ -236,14 +236,14 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
verifyActivityDetails("def/.ijk");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
null, false);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isAbleToOpenCameraApp()).isFalse();
assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
verify(mCallback, times(2)).onQRCodeScannerActivityChanged();
}
@@ -295,19 +295,20 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "0",
UserHandle.USER_CURRENT);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAllowedOnLockScreen()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "1",
UserHandle.USER_CURRENT);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
// Once from setup + twice from this function
verify(mCallback, times(3)).onQRCodeScannerPreferenceChanged();
}
@@ -319,13 +320,13 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
// even if unregistered, intent and activity details are retained
mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE,
QR_CODE_SCANNER_PREFERENCE_CHANGE);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isAbleToOpenCameraApp()).isFalse();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
assertThat(mController.isAllowedOnLockScreen()).isTrue();
// Unregister once again and make sure it affects the next register event
mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE,
@@ -334,7 +335,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
QR_CODE_SCANNER_PREFERENCE_CHANGE);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -344,7 +345,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ false);
assertThat(mController.getIntent()).isNotNull();
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
assertThat(mController.isAbleToOpenCameraApp()).isTrue();
assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
assertThat(getSettingsQRCodeDefaultComponent()).isNull();
}
}

View File

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