Merge "Do null check to account for the case where provider is only autofill provider." into udc-dev
diff --git a/res/drawable/ic_stylus.xml b/res/drawable/ic_stylus.xml
new file mode 100644
index 0000000..eb52fec
--- /dev/null
+++ b/res/drawable/ic_stylus.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?android:attr/colorControlNormal">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M167,840Q146,845 130.5,829.5Q115,814 120,793L160,602L358,800L167,840ZM358,800L160,602L618,144Q641,121 675,121Q709,121 732,144L816,228Q839,251 839,285Q839,319 816,342L358,800ZM675,200L261,614L346,699L760,285Q760,285 760,285Q760,285 760,285L675,200Q675,200 675,200Q675,200 675,200Z"/>
+</vector>
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/RequestPermissionActivity.java b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
index 620cfb0..32ca277 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
@@ -72,6 +72,7 @@
private int mRequest;
private AlertDialog mDialog;
+ private AlertDialog mRequestDialog;
private BroadcastReceiver mReceiver;
@@ -96,33 +97,35 @@
if (mRequest == REQUEST_DISABLE) {
switch (btState) {
case BluetoothAdapter.STATE_OFF:
- case BluetoothAdapter.STATE_TURNING_OFF: {
+ case BluetoothAdapter.STATE_TURNING_OFF:
proceedAndFinish();
- } break;
-
+ break;
case BluetoothAdapter.STATE_ON:
- case BluetoothAdapter.STATE_TURNING_ON: {
- RequestPermissionHelper.INSTANCE.requestDisable(this, mAppLabel,
- () -> {
- onDisableConfirmed();
- return Unit.INSTANCE;
- },
- () -> {
- cancelAndFinish();
- return Unit.INSTANCE;
- });
- } break;
-
- default: {
+ case BluetoothAdapter.STATE_TURNING_ON:
+ mRequestDialog =
+ RequestPermissionHelper.INSTANCE.requestDisable(this, mAppLabel,
+ () -> {
+ onDisableConfirmed();
+ return Unit.INSTANCE;
+ },
+ () -> {
+ cancelAndFinish();
+ return Unit.INSTANCE;
+ });
+ if (mRequestDialog != null) {
+ mRequestDialog.show();
+ }
+ break;
+ default:
Log.e(TAG, "Unknown adapter state: " + btState);
cancelAndFinish();
- } break;
+ break;
}
} else {
switch (btState) {
case BluetoothAdapter.STATE_OFF:
case BluetoothAdapter.STATE_TURNING_OFF:
- case BluetoothAdapter.STATE_TURNING_ON: {
+ case BluetoothAdapter.STATE_TURNING_ON:
/*
* Strictly speaking STATE_TURNING_ON belong with STATE_ON;
* however, BT may not be ready when the user clicks yes and we
@@ -131,20 +134,23 @@
* case via the broadcast receiver.
*/
- // Start the helper activity to ask the user about enabling bt AND discovery
- RequestPermissionHelper.INSTANCE.requestEnable(this, mAppLabel,
- mRequest == REQUEST_ENABLE_DISCOVERABLE ? mTimeout : -1,
- () -> {
- onEnableConfirmed();
- return Unit.INSTANCE;
- },
- () -> {
- cancelAndFinish();
- return Unit.INSTANCE;
- });
- } break;
-
- case BluetoothAdapter.STATE_ON: {
+ // Show the helper dialog to ask the user about enabling bt AND discovery
+ mRequestDialog =
+ RequestPermissionHelper.INSTANCE.requestEnable(this, mAppLabel,
+ mRequest == REQUEST_ENABLE_DISCOVERABLE ? mTimeout : -1,
+ () -> {
+ onEnableConfirmed();
+ return Unit.INSTANCE;
+ },
+ () -> {
+ cancelAndFinish();
+ return Unit.INSTANCE;
+ });
+ if (mRequestDialog != null) {
+ mRequestDialog.show();
+ }
+ break;
+ case BluetoothAdapter.STATE_ON:
if (mRequest == REQUEST_ENABLE) {
// Nothing to do. Already enabled.
proceedAndFinish();
@@ -152,12 +158,11 @@
// Ask the user about enabling discovery mode
createDialog();
}
- } break;
-
- default: {
+ break;
+ default:
Log.e(TAG, "Unknown adapter state: " + btState);
cancelAndFinish();
- } break;
+ break;
}
}
}
@@ -275,10 +280,6 @@
}
}
- if (mDialog != null) {
- mDialog.dismiss();
- }
-
setResult(returnCode);
finish();
}
@@ -365,6 +366,14 @@
unregisterReceiver(mReceiver);
mReceiver = null;
}
+ if (mDialog != null && mDialog.isShowing()) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ if (mRequestDialog != null && mRequestDialog.isShowing()) {
+ mRequestDialog.dismiss();
+ mRequestDialog = null;
+ }
}
@Override
diff --git a/src/com/android/settings/bluetooth/RequestPermissionHelper.kt b/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
index 000a7d1..73084e4 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
+++ b/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
@@ -30,20 +30,20 @@
timeout: Int,
onAllow: () -> Unit,
onDeny: () -> Unit,
- ) {
+ ): AlertDialog? {
if (context.resources.getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog)) {
// Don't even show the dialog if configured this way
onAllow()
- return
+ return null
}
- AlertDialog.Builder(context).apply {
+ return AlertDialog.Builder(context).apply {
setMessage(context.getEnableMessage(timeout, appLabel))
setPositiveButton(R.string.allow) { _, _ ->
if (context.isDisallowBluetooth()) onDeny() else onAllow()
}
setNegativeButton(R.string.deny) { _, _ -> onDeny() }
setOnCancelListener { onDeny() }
- }.show()
+ }.create()
}
fun requestDisable(
@@ -51,18 +51,18 @@
appLabel: CharSequence?,
onAllow: () -> Unit,
onDeny: () -> Unit,
- ) {
+ ): AlertDialog? {
if (context.resources.getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog)) {
// Don't even show the dialog if configured this way
onAllow()
- return
+ return null
}
- AlertDialog.Builder(context).apply {
+ return AlertDialog.Builder(context).apply {
setMessage(context.getDisableMessage(appLabel))
setPositiveButton(R.string.allow) { _, _ -> onAllow() }
setNegativeButton(R.string.deny) { _, _ -> onDeny() }
setOnCancelListener { onDeny() }
- }.show()
+ }.create()
}
}
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
index 947c5ac..1187c59 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
@@ -165,8 +165,7 @@
}
mUsiPreference.setKey(PREF_KEY);
mUsiPreference.setTitle(R.string.stylus_connected_devices_title);
- // TODO(b/250909304): pending actual icon visD
- mUsiPreference.setIcon(R.drawable.ic_edit);
+ mUsiPreference.setIcon(R.drawable.ic_stylus);
mUsiPreference.setOnPreferenceClickListener((Preference p) -> {
mMetricsFeatureProvider.logClickedPreference(p, mFragment.getMetricsCategory());
launchDeviceDetails();
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java b/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
index 379815b..23db3cb 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
@@ -70,8 +70,7 @@
ImageView iconView = mHeaderPreference.findViewById(R.id.entity_header_icon);
if (iconView != null) {
- // TODO(b/250909304): get proper icon once VisD ready
- iconView.setImageResource(R.drawable.ic_edit);
+ iconView.setImageResource(R.drawable.ic_stylus);
iconView.setContentDescription("Icon for stylus");
}
refresh();
diff --git a/src/com/android/settings/spa/SpaActivity.kt b/src/com/android/settings/spa/SpaActivity.kt
index 27f7241..2b52b21 100644
--- a/src/com/android/settings/spa/SpaActivity.kt
+++ b/src/com/android/settings/spa/SpaActivity.kt
@@ -22,14 +22,34 @@
import android.os.RemoteException
import android.os.UserHandle
import android.util.Log
+import androidx.annotation.VisibleForTesting
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settingslib.spa.framework.BrowseActivity
+import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
import com.android.settingslib.spa.framework.util.appendSpaParams
+import com.google.android.setupcompat.util.WizardManagerHelper
class SpaActivity : BrowseActivity() {
+ override fun isPageEnabled(page: SettingsPage) =
+ super.isPageEnabled(page) && !isSuwAndPageBlocked(page.sppName)
+
companion object {
private const val TAG = "SpaActivity"
+
+ /** The pages that blocked from SUW. */
+ private val SuwBlockedPages = setOf(AppInfoSettingsProvider.name)
+
+ @VisibleForTesting
+ fun Context.isSuwAndPageBlocked(name: String): Boolean =
+ if (name in SuwBlockedPages && !WizardManagerHelper.isDeviceProvisioned(this)) {
+ Log.w(TAG, "$name blocked before SUW completed.");
+ true
+ } else {
+ false
+ }
+
@JvmStatic
fun Context.startSpaActivity(destination: String) {
val intent = Intent(this, SpaActivity::class.java)
diff --git a/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionActivityTest.kt b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionActivityTest.kt
new file mode 100644
index 0000000..13cbb35
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionActivityTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.bluetooth
+
+import android.bluetooth.BluetoothAdapter
+import android.content.Intent
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.android.controller.ActivityController
+import org.robolectric.annotation.Config
+import org.robolectric.shadow.api.Shadow
+import org.robolectric.shadows.ShadowBluetoothAdapter
+
+@RunWith(RobolectricTestRunner::class)
+@Config(shadows = [ShadowAlertDialogCompat::class, ShadowBluetoothAdapter::class])
+class RequestPermissionActivityTest {
+ private lateinit var activityController: ActivityController<RequestPermissionActivity>
+ private lateinit var bluetoothAdapter: ShadowBluetoothAdapter
+
+ @Before
+ fun setUp() {
+ bluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter())
+ }
+
+ @After
+ fun tearDown() {
+ activityController.pause().stop().destroy()
+ ShadowAlertDialogCompat.reset()
+ }
+
+ @Test
+ fun requestEnable_whenBluetoothIsOff_showConfirmDialog() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_OFF)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_ENABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ val shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog)
+ assertThat(shadowDialog.message.toString())
+ .isEqualTo("An app wants to turn on Bluetooth")
+ }
+
+ @Test
+ fun requestEnable_whenBluetoothIsOn_doNothing() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_ON)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_ENABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ assertThat(dialog).isNull()
+ }
+
+ @Test
+ fun requestDisable_whenBluetoothIsOff_doNothing() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_OFF)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_DISABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ assertThat(dialog).isNull()
+ }
+
+ @Test
+ fun requestDisable_whenBluetoothIsOn_showConfirmDialog() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_ON)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_DISABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ val shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog)
+ assertThat(shadowDialog.message.toString())
+ .isEqualTo("An app wants to turn off Bluetooth")
+ }
+
+ private fun createActivity(action: String) {
+ activityController =
+ ActivityController.of(RequestPermissionActivity(), Intent(action)).apply {
+ create()
+ start()
+ postCreate(null)
+ resume()
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
index ce0792c..e51a2f9 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
@@ -49,13 +49,14 @@
@Test
fun requestEnable_withAppLabelAndNoTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = "App Label",
timeout = -1,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("App Label wants to turn on Bluetooth")
}
@@ -63,13 +64,14 @@
@Test
fun requestEnable_withAppLabelAndZeroTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = "App Label",
timeout = 0,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"App Label wants to turn on Bluetooth and make your phone visible to other devices. " +
@@ -80,13 +82,14 @@
@Test
fun requestEnable_withAppLabelAndNormalTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = "App Label",
timeout = 120,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"App Label wants to turn on Bluetooth and make your phone visible to other devices " +
@@ -97,13 +100,14 @@
@Test
fun requestEnable_withNoAppLabelAndNoTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = null,
timeout = -1,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("An app wants to turn on Bluetooth")
}
@@ -111,13 +115,14 @@
@Test
fun requestEnable_withNoAppLabelAndZeroTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = null,
timeout = 0,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"An app wants to turn on Bluetooth and make your phone visible to other devices. " +
@@ -128,13 +133,14 @@
@Test
fun requestEnable_withNoAppLabelAndNormalTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = null,
timeout = 120,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"An app wants to turn on Bluetooth and make your phone visible to other devices for " +
@@ -177,12 +183,13 @@
@Test
fun requestDisable_withAppLabel_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestDisable(
context = activity,
appLabel = "App Label",
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("App Label wants to turn off Bluetooth")
}
@@ -190,12 +197,13 @@
@Test
fun requestDisable_withNoAppLabel_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestDisable(
context = activity,
appLabel = null,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("An app wants to turn off Bluetooth")
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
index 46b956e..1b2a7b1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
@@ -21,33 +21,71 @@
import android.net.Uri
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.settings.spa.SpaActivity.Companion.isSuwAndPageBlocked
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
+import com.android.settings.spa.app.AllAppListPageProvider
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settingslib.spa.framework.util.KEY_DESTINATION
+import com.google.android.setupcompat.util.WizardManagerHelper
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Answers
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
+import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidJUnit4::class)
class SpaActivityTest {
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
+ private lateinit var mockSession: MockitoSession
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ @Mock
private lateinit var context: Context
@Before
fun setUp() {
- `when`(context.applicationContext.packageName).thenReturn("com.android.settings")
+ mockSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .mockStatic(WizardManagerHelper::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ whenever(context.applicationContext).thenReturn(context)
+ }
+
+ @After
+ fun tearDown() {
+ mockSession.finishMocking()
+ }
+
+ @Test
+ fun isSuwAndPageBlocked_regularPage_notBlocked() {
+ val isBlocked = context.isSuwAndPageBlocked(AllAppListPageProvider.name)
+
+ assertThat(isBlocked).isFalse()
+ }
+
+ @Test
+ fun isSuwAndPageBlocked_blocklistedPageInSuw_blocked() {
+ whenever(WizardManagerHelper.isDeviceProvisioned(context)).thenReturn(false)
+
+ val isBlocked = context.isSuwAndPageBlocked(AppInfoSettingsProvider.name)
+
+ assertThat(isBlocked).isTrue()
+ }
+
+ @Test
+ fun isSuwAndPageBlocked_blocklistedPageNotInSuw_notBlocked() {
+ whenever(WizardManagerHelper.isDeviceProvisioned(context)).thenReturn(true)
+
+ val isBlocked = context.isSuwAndPageBlocked(AppInfoSettingsProvider.name)
+
+ assertThat(isBlocked).isFalse()
}
@Test