summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-10-13 07:59:59 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-10-13 07:59:59 +0000
commit3ec694e35e992b60e58f2f3493f398235c073b9a (patch)
tree2778a1db372ae3113fd068ad7f5f4dcb9f14d00a
parentd15ecd4c642d89af9213ef4803534cdffe2f1144 (diff)
parent05ea36ddc50c504fc21df11195ca5850396cdcd6 (diff)
downloadSettings-android10-android13-mainline-tzdata-release.tar.gz
Change-Id: I7ca721489510f79850728e299b0b2f6201010a23
-rw-r--r--res/values/strings.xml4
-rw-r--r--res/values/styles.xml10
-rw-r--r--res/xml/location_scanning.xml4
-rw-r--r--res/xml/vpn_app_management.xml14
-rw-r--r--src/com/android/settings/ActivityPicker.java4
-rw-r--r--src/com/android/settings/DefaultRingtonePreference.java26
-rw-r--r--src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java9
-rw-r--r--src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java23
-rw-r--r--src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java19
-rw-r--r--src/com/android/settings/location/BluetoothScanningPreferenceController.java11
-rw-r--r--src/com/android/settings/location/WifiScanningPreferenceController.java11
-rw-r--r--src/com/android/settings/network/PrivateDnsPreferenceController.java9
-rw-r--r--src/com/android/settings/nfc/SecureNfcEnabler.java14
-rw-r--r--src/com/android/settings/nfc/SecureNfcPreferenceController.java18
-rw-r--r--src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java54
-rw-r--r--src/com/android/settings/notification/NotificationAccessConfirmationActivity.java33
-rw-r--r--src/com/android/settings/notification/ZenRulePreference.java2
-rw-r--r--src/com/android/settings/security/CredentialStorage.java15
-rw-r--r--src/com/android/settings/users/AppRestrictionsFragment.java29
-rw-r--r--src/com/android/settings/users/EditUserPhotoController.java43
-rw-r--r--src/com/android/settings/vpn2/AppManagementFragment.java51
-rw-r--r--tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java27
-rw-r--r--tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java27
-rw-r--r--tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java11
-rw-r--r--tests/robotests/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceControllerTest.java169
-rw-r--r--tests/unit/Android.mk2
-rw-r--r--tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java82
27 files changed, 654 insertions, 67 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 204e0d6c2dd..ad0c215bfd4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4461,7 +4461,7 @@
<!-- Manage applications, individual application screen, confirmation dialog title. Displays when user selects to "Clear data". -->
<string name="clear_data_dlg_title">Delete app data?</string>
<!-- Manage applications, individual application screen, confirmation dialog message. Displays when user selects to "Clear data". It warns the user of the consequences of clearing the data for an app. -->
- <string name="clear_data_dlg_text">All this app\u2019s data will be deleted permanently. This includes all files, settings, accounts, databases, etc.</string>
+ <string name="clear_data_dlg_text">This app\u2019s data will be permanently deleted. This includes files, settings, databases, and other app data.</string>
<!-- Manage applications, individual application screen, confirmation dialog button. Displays when user selects to "Clear data". Goes through with the clearing of the data. -->
<string name="dlg_ok">OK</string>
<!-- Manage applications, individual application screen, confirmation dialog button. Displays when user selects to "Clear data". -->
@@ -6619,7 +6619,7 @@
<!-- Button label to disconnect from a VPN profile. [CHAR LIMIT=40] -->
<string name="vpn_disconnect">Disconnect</string>
<!-- Field label to show the version number for a VPN app. [CHAR LIMIT=40] -->
- <string name="vpn_version">Version <xliff:g id="version" example="3.3.0">%s</xliff:g></string>
+ <string name="vpn_version">Version</string>
<!-- Button label to forget a VPN profile [CHAR LIMIT=40] -->
<string name="vpn_forget_long">Forget VPN</string>
<!-- Dialog message title to set another VPN app to be always-on [CHAR LIMIT=40] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d3d3199f62b..ec66bc8d1b8 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -197,6 +197,16 @@
<item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Small</item>
</style>
+ <style name="vpn_app_management_version_title">
+ <item name="android:textAppearance">?android:attr/textAppearanceListItem</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="vpn_app_management_version_summary">
+ <item name="android:textAppearance">?android:attr/textAppearanceListItemSecondary</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
<style name="TextAppearance" parent="android:TextAppearance.DeviceDefault"/>
<style name="TextAppearance.info_label">
diff --git a/res/xml/location_scanning.xml b/res/xml/location_scanning.xml
index 5e7bd244520..f4847681150 100644
--- a/res/xml/location_scanning.xml
+++ b/res/xml/location_scanning.xml
@@ -18,13 +18,13 @@
android:title="@string/location_scanning_screen_title"
android:key="scanning_screen">
- <SwitchPreference
+ <com.android.settingslib.RestrictedSwitchPreference
android:title="@string/location_scanning_wifi_always_scanning_title"
android:summary="@string/location_scanning_wifi_always_scanning_description"
android:defaultValue="true"
android:key="wifi_always_scanning" />
- <SwitchPreference
+ <com.android.settingslib.RestrictedSwitchPreference
android:title="@string/location_scanning_bluetooth_always_scanning_title"
android:summary="@string/location_scanning_bluetooth_always_scanning_description"
android:defaultValue="true"
diff --git a/res/xml/vpn_app_management.xml b/res/xml/vpn_app_management.xml
index bcaa6b0a62f..adc441d8468 100644
--- a/res/xml/vpn_app_management.xml
+++ b/res/xml/vpn_app_management.xml
@@ -15,14 +15,24 @@
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:settings="http://schemas.android.com/apk/res-auto">
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ orderingFromXml="false"
+ >
+
+ <!-- To limit the size (in height) of version Preference displayed here,
+ maximum height of TextView need to be set programmingly.
+ Therefore, this Preference got removed from here and will be added
+ dynamically through source code.
<Preference
+ android:order="0"
android:key="version"
android:textColor="?android:attr/textColorSecondary"
android:selectable="false"/>
+ -->
<com.android.settingslib.RestrictedSwitchPreference
+ android:order="10"
android:key="always_on_vpn"
android:title="@string/vpn_menu_lockdown"
android:defaultValue="false"
@@ -32,6 +42,7 @@
settings:restrictedSwitchSummary="@string/disabled_by_admin_summary_text" />
<com.android.settingslib.RestrictedSwitchPreference
+ android:order="20"
android:key="lockdown_vpn"
android:title="@string/vpn_require_connection"
android:defaultValue="false"
@@ -41,6 +52,7 @@
settings:restrictedSwitchSummary="@string/disabled_by_admin_summary_text" />
<com.android.settingslib.RestrictedPreference
+ android:order="30"
android:key="forget_vpn"
android:title="@string/vpn_forget_long"
android:icon="@drawable/ic_delete"
diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
index ae61944cbe1..f75ce3740aa 100644
--- a/src/com/android/settings/ActivityPicker.java
+++ b/src/com/android/settings/ActivityPicker.java
@@ -16,6 +16,8 @@
package com.android.settings;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
@@ -71,6 +73,8 @@ public class ActivityPicker extends AlertActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
final Intent intent = getIntent();
diff --git a/src/com/android/settings/DefaultRingtonePreference.java b/src/com/android/settings/DefaultRingtonePreference.java
index 9f9f832b100..9bf626c9898 100644
--- a/src/com/android/settings/DefaultRingtonePreference.java
+++ b/src/com/android/settings/DefaultRingtonePreference.java
@@ -22,6 +22,9 @@ import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.util.AttributeSet;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
public class DefaultRingtonePreference extends RingtonePreference {
private static final String TAG = "DefaultRingtonePreference";
@@ -43,6 +46,29 @@ public class DefaultRingtonePreference extends RingtonePreference {
@Override
protected void onSaveRingtone(Uri ringtoneUri) {
+ if (ringtoneUri == null) {
+ setActualDefaultRingtoneUri(ringtoneUri);
+ return;
+ }
+
+ String mimeType = mUserContext.getContentResolver().getType(ringtoneUri);
+ if (mimeType == null) {
+ Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri
+ + " ignored: failure to find mimeType (no access from this context?)");
+ return;
+ }
+
+ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) {
+ Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri
+ + " ignored: associated mimeType:" + mimeType + " is not an audio type");
+ return;
+ }
+
+ setActualDefaultRingtoneUri(ringtoneUri);
+ }
+
+ @VisibleForTesting
+ void setActualDefaultRingtoneUri(Uri ringtoneUri) {
RingtoneManager.setActualDefaultRingtoneUri(mUserContext, getRingtoneType(), ringtoneUri);
}
diff --git a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
index 0d130d92122..fe14c52c228 100644
--- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
@@ -18,12 +18,16 @@ package com.android.settings.connecteddevice;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothFilesPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.nfc.AndroidBeamPreferenceController;
+import com.android.settings.nfc.SecureNfcPreferenceController;
import com.android.settings.print.PrintSettingPreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -106,6 +110,11 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
keys.add(AndroidBeamPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
}
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ final UserInfo myUserInfo = userManager.getUserInfo(UserHandle.myUserId());
+ if (myUserInfo.isGuest()) {
+ keys.add(SecureNfcPreferenceController.KEY_SECURENFC_SETTINGS);
+ }
return keys;
}
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index cbabb06eb61..9cf18a9ba56 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -20,12 +20,15 @@ import android.content.Context;
import android.net.Uri;
import android.provider.DeviceConfig;
import android.provider.SearchIndexableResource;
+import android.text.TextUtils;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.SettingsUIDeviceConfig;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.password.PasswordUtils;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -40,6 +43,10 @@ import java.util.List;
public class ConnectedDeviceDashboardFragment extends DashboardFragment {
private static final String TAG = "ConnectedDeviceFrag";
+ private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
+ private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
@VisibleForTesting
static final String KEY_CONNECTED_DEVICES = "connected_device_list";
@@ -90,6 +97,13 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
super.onAttach(context);
final boolean nearbyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_NEAR_BY_SUGGESTION_ENABLED, true);
+ String callingAppPackageName = PasswordUtils.getCallingAppPackageName(
+ getActivity().getActivityToken());
+ String action = getIntent() != null ? getIntent().getAction() : "";
+ if (DEBUG) {
+ Log.d(TAG, "onAttach() calling package name is : " + callingAppPackageName
+ + ", action : " + action);
+ }
use(AvailableMediaDeviceGroupController.class).init(this);
use(ConnectedDeviceGroupController.class).init(this);
use(PreviouslyConnectedDevicePreferenceController.class).init(this);
@@ -97,6 +111,15 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
use(SlicePreferenceController.class).setSliceUri(nearbyEnabled
? Uri.parse(getString(R.string.config_nearby_devices_slice_uri))
: null);
+ use(DiscoverableFooterPreferenceController.class)
+ .setAlwaysDiscoverable(isAlwaysDiscoverable(callingAppPackageName, action));
+ }
+
+ @VisibleForTesting
+ boolean isAlwaysDiscoverable(String callingAppPackageName, String action) {
+ return TextUtils.equals(SLICE_ACTION, action) ? false
+ : TextUtils.equals(SETTINGS_PACKAGE_NAME, callingAppPackageName)
+ || TextUtils.equals(SYSTEMUI_PACKAGE_NAME, callingAppPackageName);
}
/**
diff --git a/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java
index ead33070ee0..bb0417e580f 100644
--- a/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java
+++ b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java
@@ -55,6 +55,7 @@ public class DiscoverableFooterPreferenceController extends BasePreferenceContro
private FooterPreference mPreference;
private BluetoothAdapter mBluetoothAdapter;
private AlwaysDiscoverable mAlwaysDiscoverable;
+ private boolean mIsAlwaysDiscoverable;
public DiscoverableFooterPreferenceController(Context context) {
super(context, KEY);
@@ -119,7 +120,9 @@ public class DiscoverableFooterPreferenceController extends BasePreferenceContro
}
mContext.registerReceiver(mBluetoothChangedReceiver,
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
- mAlwaysDiscoverable.start();
+ if (mIsAlwaysDiscoverable) {
+ mAlwaysDiscoverable.start();
+ }
updateFooterPreferenceTitle(mBluetoothAdapter.getState());
}
@@ -129,7 +132,19 @@ public class DiscoverableFooterPreferenceController extends BasePreferenceContro
return;
}
mContext.unregisterReceiver(mBluetoothChangedReceiver);
- mAlwaysDiscoverable.stop();
+ if (mIsAlwaysDiscoverable) {
+ mAlwaysDiscoverable.stop();
+ }
+ }
+
+ /**
+ * Set whether the device can be discovered. By default the value will be {@code false}.
+ *
+ * @param isAlwaysDiscoverable {@code true} if the device can be discovered,
+ * otherwise {@code false}
+ */
+ public void setAlwaysDiscoverable(boolean isAlwaysDiscoverable) {
+ mIsAlwaysDiscoverable = isAlwaysDiscoverable;
}
private void updateFooterPreferenceTitle (int bluetoothState) {
diff --git a/src/com/android/settings/location/BluetoothScanningPreferenceController.java b/src/com/android/settings/location/BluetoothScanningPreferenceController.java
index d16e1e58e2f..cee31053ea6 100644
--- a/src/com/android/settings/location/BluetoothScanningPreferenceController.java
+++ b/src/com/android/settings/location/BluetoothScanningPreferenceController.java
@@ -14,12 +14,17 @@
package com.android.settings.location;
import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.core.AbstractPreferenceController;
public class BluetoothScanningPreferenceController extends AbstractPreferenceController
@@ -46,6 +51,12 @@ public class BluetoothScanningPreferenceController extends AbstractPreferenceCon
((SwitchPreference) preference).setChecked(
Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1);
+ final RestrictedLockUtils.EnforcedAdmin admin =
+ RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
+ mContext, UserManager.DISALLOW_CONFIG_LOCATION, UserHandle.myUserId());
+ if (admin != null) {
+ ((RestrictedSwitchPreference) preference).setDisabledByAdmin(admin);
+ }
}
@Override
diff --git a/src/com/android/settings/location/WifiScanningPreferenceController.java b/src/com/android/settings/location/WifiScanningPreferenceController.java
index 234ec5e53e1..fb64fa9534c 100644
--- a/src/com/android/settings/location/WifiScanningPreferenceController.java
+++ b/src/com/android/settings/location/WifiScanningPreferenceController.java
@@ -14,12 +14,17 @@
package com.android.settings.location;
import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.core.AbstractPreferenceController;
public class WifiScanningPreferenceController extends AbstractPreferenceController
@@ -46,6 +51,12 @@ public class WifiScanningPreferenceController extends AbstractPreferenceControll
((SwitchPreference) preference).setChecked(
Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1);
+ final RestrictedLockUtils.EnforcedAdmin admin =
+ RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
+ mContext, UserManager.DISALLOW_CONFIG_LOCATION, UserHandle.myUserId());
+ if (admin != null) {
+ ((RestrictedSwitchPreference) preference).setDisabledByAdmin(admin);
+ }
}
@Override
diff --git a/src/com/android/settings/network/PrivateDnsPreferenceController.java b/src/com/android/settings/network/PrivateDnsPreferenceController.java
index 47c3a95c9fd..b74345170c0 100644
--- a/src/com/android/settings/network/PrivateDnsPreferenceController.java
+++ b/src/com/android/settings/network/PrivateDnsPreferenceController.java
@@ -84,9 +84,12 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
@Override
public int getAvailabilityStatus() {
- return mContext.getResources().getBoolean(R.bool.config_show_private_dns_settings)
- ? AVAILABLE
- : UNSUPPORTED_ON_DEVICE;
+ if (!mContext.getResources().getBoolean(R.bool.config_show_private_dns_settings)) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ final UserManager userManager = mContext.getSystemService(UserManager.class);
+ if (userManager.isGuestUser()) return DISABLED_FOR_USER;
+ return AVAILABLE;
}
@Override
diff --git a/src/com/android/settings/nfc/SecureNfcEnabler.java b/src/com/android/settings/nfc/SecureNfcEnabler.java
index 9acaf6461f2..f31a382a571 100644
--- a/src/com/android/settings/nfc/SecureNfcEnabler.java
+++ b/src/com/android/settings/nfc/SecureNfcEnabler.java
@@ -18,9 +18,8 @@ package com.android.settings.nfc;
import android.content.Context;
import android.nfc.NfcAdapter;
-import android.provider.Settings;
+import android.os.UserManager;
-import androidx.annotation.VisibleForTesting;
import androidx.preference.SwitchPreference;
import com.android.settings.R;
@@ -32,10 +31,12 @@ import com.android.settings.R;
*/
public class SecureNfcEnabler extends BaseNfcEnabler {
private final SwitchPreference mPreference;
+ private final UserManager mUserManager;
public SecureNfcEnabler(Context context, SwitchPreference preference) {
super(context);
mPreference = preference;
+ mUserManager = context.getSystemService(UserManager.class);
}
@Override
@@ -48,7 +49,7 @@ public class SecureNfcEnabler extends BaseNfcEnabler {
case NfcAdapter.STATE_ON:
mPreference.setSummary(R.string.nfc_secure_toggle_summary);
mPreference.setChecked(mPreference.isChecked());
- mPreference.setEnabled(true);
+ mPreference.setEnabled(isToggleable());
break;
case NfcAdapter.STATE_TURNING_ON:
mPreference.setEnabled(false);
@@ -58,4 +59,11 @@ public class SecureNfcEnabler extends BaseNfcEnabler {
break;
}
}
+
+ private boolean isToggleable() {
+ if (mUserManager.isGuestUser()) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/src/com/android/settings/nfc/SecureNfcPreferenceController.java b/src/com/android/settings/nfc/SecureNfcPreferenceController.java
index 12dbd5749ca..2ff685e5a0b 100644
--- a/src/com/android/settings/nfc/SecureNfcPreferenceController.java
+++ b/src/com/android/settings/nfc/SecureNfcPreferenceController.java
@@ -17,6 +17,7 @@ package com.android.settings.nfc;
import android.content.Context;
import android.nfc.NfcAdapter;
+import android.os.UserManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
@@ -29,12 +30,15 @@ import com.android.settingslib.core.lifecycle.events.OnResume;
public class SecureNfcPreferenceController extends TogglePreferenceController
implements LifecycleObserver, OnResume, OnPause {
+ public static final String KEY_SECURENFC_SETTINGS = "nfc_secure_settings";
private final NfcAdapter mNfcAdapter;
private SecureNfcEnabler mSecureNfcEnabler;
+ private final UserManager mUserManager;
public SecureNfcPreferenceController(Context context, String key) {
super(context, key);
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
+ mUserManager = context.getSystemService(UserManager.class);
}
@Override
@@ -57,7 +61,11 @@ public class SecureNfcPreferenceController extends TogglePreferenceController
@Override
public boolean setChecked(boolean isChecked) {
- return mNfcAdapter.enableSecureNfc(isChecked);
+ if (isToggleable()) {
+ return mNfcAdapter.enableSecureNfc(isChecked);
+ } else {
+ return false;
+ }
}
@Override
@@ -94,4 +102,12 @@ public class SecureNfcPreferenceController extends TogglePreferenceController
mSecureNfcEnabler.pause();
}
}
+
+ private boolean isToggleable() {
+ if (mUserManager.isGuestUser()) {
+ return false;
+ }
+ return true;
+ }
+
}
diff --git a/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java b/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
index f7b32221ea2..db7f68ef729 100644
--- a/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
+++ b/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
@@ -26,8 +26,11 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
+import android.os.Binder;
import android.provider.Settings;
import android.service.notification.ConditionProviderService;
+import android.util.Log;
+import android.util.Slog;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
@@ -36,6 +39,7 @@ import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.Map;
+import java.util.Objects;
abstract public class AbstractZenModeAutomaticRulePreferenceController extends
AbstractZenModePreferenceController implements PreferenceControllerMixin {
@@ -92,7 +96,7 @@ abstract public class AbstractZenModeAutomaticRulePreferenceController extends
? ci.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE)
: ci.metaData.getString(NotificationManager.META_DATA_AUTOMATIC_RULE_TYPE);
- final ComponentName configurationActivity = getSettingsActivity(null, ci);
+ final ComponentName configurationActivity = getSettingsActivity(pm, null, ci);
if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) {
final ZenRuleInfo ri = new ZenRuleInfo();
ri.serviceComponent =
@@ -110,28 +114,44 @@ abstract public class AbstractZenModeAutomaticRulePreferenceController extends
return null;
}
- protected static ComponentName getSettingsActivity(AutomaticZenRule rule, ComponentInfo ci) {
+ protected static ComponentName getSettingsActivity(PackageManager pm, AutomaticZenRule rule,
+ ComponentInfo ci) {
+ String owner = rule != null ? rule.getPackageName() : ci.packageName;
+ ComponentName settingsActivity = null;
// prefer config activity on the rule itself; fallback to manifest definition
if (rule != null && rule.getConfigurationActivity() != null) {
- return rule.getConfigurationActivity();
- }
- if (ci == null) {
- return null;
+ settingsActivity = rule.getConfigurationActivity();
+ } else {
+ if (ci == null) {
+ settingsActivity = null;
+ } else if (ci instanceof ActivityInfo) {
+ // new activity backed rule
+ settingsActivity = new ComponentName(ci.packageName, ci.name);
+ } else if (ci.metaData != null) {
+ // old service backed rule
+ final String configurationActivity = ci.metaData.getString(
+ ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY);
+ if (configurationActivity != null) {
+ settingsActivity = ComponentName.unflattenFromString(configurationActivity);
+ }
+ }
}
- // new activity backed rule
- if (ci instanceof ActivityInfo) {
- return new ComponentName(ci.packageName, ci.name);
+ if (settingsActivity == null || owner == null) {
+ return settingsActivity;
}
- // old service backed rule
- if (ci.metaData != null) {
- final String configurationActivity = ci.metaData.getString(
- ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY);
- if (configurationActivity != null) {
- return ComponentName.unflattenFromString(configurationActivity);
+ try {
+ int ownerUid = pm.getPackageUid(owner, 0);
+ int configActivityOwnerUid = pm.getPackageUid(settingsActivity.getPackageName(), 0);
+ if (ownerUid == configActivityOwnerUid) {
+ return settingsActivity;
+ } else {
+ Log.w(TAG, "Config activity not in owner package for " + rule.getName());
+ return null;
}
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Failed to find config activity");
+ return null;
}
-
- return null;
}
public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener {
diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
index a7d9f6889cd..dfe6df2a5ca 100644
--- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
+++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
@@ -20,7 +20,6 @@ package com.android.settings.notification;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_COMPONENT_NAME;
-import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_PACKAGE_TITLE;
import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_USER_ID;
import android.Manifest;
@@ -30,10 +29,13 @@ import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -63,15 +65,38 @@ public class NotificationAccessConfirmationActivity extends Activity
mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME);
mUserId = getIntent().getIntExtra(EXTRA_USER_ID, UserHandle.USER_NULL);
- String pkgTitle = getIntent().getStringExtra(EXTRA_PACKAGE_TITLE);
+ CharSequence mAppLabel;
+
+ if (mComponentName == null || mComponentName.getPackageName() == null) {
+ finish();
+ return;
+ }
+
+ try {
+ ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
+ mComponentName.getPackageName(), 0);
+ mAppLabel = applicationInfo.loadSafeLabel(getPackageManager(),
+ PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+ | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(LOG_TAG, "Couldn't find app with package name for " + mComponentName, e);
+ finish();
+ return;
+ }
+
+ if (TextUtils.isEmpty(mAppLabel)) {
+ finish();
+ return;
+ }
AlertController.AlertParams p = new AlertController.AlertParams(this);
p.mTitle = getString(
R.string.notification_listener_security_warning_title,
- pkgTitle);
+ mAppLabel);
p.mMessage = getString(
R.string.notification_listener_security_warning_summary,
- pkgTitle);
+ mAppLabel);
p.mPositiveButtonText = getString(R.string.allow);
p.mPositiveButtonListener = (a, b) -> onAllow();
p.mNegativeButtonText = getString(R.string.deny);
diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java
index fb6e92a6344..7d3dae08b38 100644
--- a/src/com/android/settings/notification/ZenRulePreference.java
+++ b/src/com/android/settings/notification/ZenRulePreference.java
@@ -168,7 +168,7 @@ public class ZenRulePreference extends TwoTargetPreference {
: isEvent ? ZenModeEventRuleSettings.ACTION : "";
ComponentInfo si = mServiceListing.findService(rule.getOwner());
ComponentName settingsActivity = AbstractZenModeAutomaticRulePreferenceController.
- getSettingsActivity(rule, si);
+ getSettingsActivity(mPm, rule, si);
mIntent = AbstractZenModeAutomaticRulePreferenceController.getRuleIntent(action,
settingsActivity, mId);
if (mIntent.resolveActivity(mPm) == null) {
diff --git a/src/com/android/settings/security/CredentialStorage.java b/src/com/android/settings/security/CredentialStorage.java
index 0ea37b5bc7f..31460c448cc 100644
--- a/src/com/android/settings/security/CredentialStorage.java
+++ b/src/com/android/settings/security/CredentialStorage.java
@@ -92,7 +92,7 @@ public final class CredentialStorage extends FragmentActivity {
final String action = intent.getAction();
final UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
if (!userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) {
- if (ACTION_RESET.equals(action)) {
+ if (ACTION_RESET.equals(action) && checkCallerIsSelf()) {
new ResetDialog();
} else {
if (ACTION_INSTALL.equals(action) && checkCallerIsCertInstallerOrSelfInProfile()) {
@@ -342,6 +342,19 @@ public final class CredentialStorage extends FragmentActivity {
}
/**
+ * Check that the caller is Settings.
+ */
+ private boolean checkCallerIsSelf() {
+ try {
+ return Process.myUid() == android.app.ActivityManager.getService()
+ .getLaunchedFromUid(getActivityToken());
+ } catch (RemoteException re) {
+ // Error talking to ActivityManager, just give up
+ return false;
+ }
+ }
+
+ /**
* Check that the caller is either certinstaller or Settings running in a profile of this user.
*/
private boolean checkCallerIsCertInstallerOrSelfInProfile() {
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index 7b15e8a090b..7cf46b69245 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -18,6 +18,7 @@ package com.android.settings.users;
import android.app.Activity;
import android.app.settings.SettingsEnums;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -37,6 +38,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.EventLog;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
@@ -635,7 +637,15 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
} else if (restrictionsIntent != null) {
preference.setRestrictions(restrictions);
if (invokeIfCustom && AppRestrictionsFragment.this.isResumed()) {
- assertSafeToStartCustomActivity(restrictionsIntent);
+ try {
+ assertSafeToStartCustomActivity(restrictionsIntent);
+ } catch (ActivityNotFoundException | SecurityException e) {
+ // return without startActivity
+ Log.e(TAG, "Cannot start restrictionsIntent " + e);
+ EventLog.writeEvent(0x534e4554, "200688991", -1 /* UID */, "");
+ return;
+ }
+
int requestCode = generateCustomActivityRequestCode(
RestrictionsResultReceiver.this.preference);
AppRestrictionsFragment.this.startActivityForResult(
@@ -645,18 +655,15 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
}
private void assertSafeToStartCustomActivity(Intent intent) {
- // Activity can be started if it belongs to the same app
- if (intent.getPackage() != null && intent.getPackage().equals(packageName)) {
- return;
- }
- // Activity can be started if intent resolves to multiple activities
- List<ResolveInfo> resolveInfos = AppRestrictionsFragment.this.mPackageManager
- .queryIntentActivities(intent, 0 /* no flags */);
- if (resolveInfos.size() != 1) {
- return;
+ EventLog.writeEvent(0x534e4554, "223578534", -1 /* UID */, "");
+ ResolveInfo resolveInfo = mPackageManager.resolveActivity(
+ intent, PackageManager.MATCH_DEFAULT_ONLY);
+
+ if (resolveInfo == null) {
+ throw new ActivityNotFoundException("No result for resolving " + intent);
}
// Prevent potential privilege escalation
- ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
+ ActivityInfo activityInfo = resolveInfo.activityInfo;
if (!packageName.equals(activityInfo.packageName)) {
throw new SecurityException("Application " + packageName
+ " is not allowed to start activity " + intent);
diff --git a/src/com/android/settings/users/EditUserPhotoController.java b/src/com/android/settings/users/EditUserPhotoController.java
index f62a2d5970f..f1831f7120b 100644
--- a/src/com/android/settings/users/EditUserPhotoController.java
+++ b/src/com/android/settings/users/EditUserPhotoController.java
@@ -21,7 +21,9 @@ import android.content.ClipData;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
@@ -77,6 +79,7 @@ public class EditUserPhotoController {
private static final int REQUEST_CODE_TAKE_PHOTO = 1002;
private static final int REQUEST_CODE_CROP_PHOTO = 1003;
+ private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
private static final String NEW_USER_PHOTO_FILE_NAME = "NewUserPhoto.png";
@@ -87,6 +90,7 @@ public class EditUserPhotoController {
private final Fragment mFragment;
private final ImageView mImageView;
+ private final Uri mPreCropPictureUri;
private final Uri mCropPictureUri;
private final Uri mTakePictureUri;
@@ -98,6 +102,8 @@ public class EditUserPhotoController {
mContext = view.getContext();
mFragment = fragment;
mImageView = view;
+
+ mPreCropPictureUri = createTempImageUri(mContext, PRE_CROP_PICTURE_FILE_NAME, !waiting);
mCropPictureUri = createTempImageUri(mContext, CROP_PICTURE_FILE_NAME, !waiting);
mTakePictureUri = createTempImageUri(mContext, TAKE_PICTURE_FILE_NAME, !waiting);
mPhotoSize = getPhotoSize(mContext);
@@ -132,7 +138,7 @@ public class EditUserPhotoController {
case REQUEST_CODE_TAKE_PHOTO:
case REQUEST_CODE_CHOOSE_PHOTO:
if (mTakePictureUri.equals(pictureUri)) {
- cropPhoto();
+ cropPhoto(pictureUri);
} else {
copyAndCropPhoto(pictureUri);
}
@@ -241,7 +247,7 @@ public class EditUserPhotoController {
protected Void doInBackground(Void... params) {
final ContentResolver cr = mContext.getContentResolver();
try (InputStream in = cr.openInputStream(pictureUri);
- OutputStream out = cr.openOutputStream(mTakePictureUri)) {
+ OutputStream out = cr.openOutputStream(mPreCropPictureUri)) {
Streams.copy(in, out);
} catch (IOException e) {
Log.w(TAG, "Failed to copy photo", e);
@@ -252,27 +258,38 @@ public class EditUserPhotoController {
@Override
protected void onPostExecute(Void result) {
if (!mFragment.isAdded()) return;
- cropPhoto();
+ cropPhoto(mPreCropPictureUri);
}
}.execute();
}
- private void cropPhoto() {
+ private void cropPhoto(final Uri pictureUri) {
// TODO: Use a public intent, when there is one.
Intent intent = new Intent("com.android.camera.action.CROP");
- intent.setDataAndType(mTakePictureUri, "image/*");
+ intent.setDataAndType(pictureUri, "image/*");
appendOutputExtra(intent, mCropPictureUri);
appendCropExtras(intent);
- if (intent.resolveActivity(mContext.getPackageManager()) != null) {
- try {
- StrictMode.disableDeathOnFileUriExposure();
- mFragment.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
- } finally {
- StrictMode.enableDeathOnFileUriExposure();
+ try {
+ StrictMode.disableDeathOnFileUriExposure();
+ if (startSystemActivityForResult(intent, REQUEST_CODE_CROP_PHOTO)) {
+ return;
}
- } else {
- onPhotoCropped(mTakePictureUri, false);
+ } finally {
+ StrictMode.enableDeathOnFileUriExposure();
+ }
+ onPhotoCropped(mTakePictureUri, false);
+ }
+
+ private boolean startSystemActivityForResult(Intent intent, int code) {
+ List<ResolveInfo> resolveInfos = mContext.getPackageManager()
+ .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
+ if (resolveInfos.isEmpty()) {
+ Log.w(TAG, "No system package activity could be found for code " + code);
+ return false;
}
+ intent.setPackage(resolveInfos.get(0).activityInfo.packageName);
+ mFragment.startActivityForResult(intent, code);
+ return true;
}
private void appendOutputExtra(Intent intent, Uri pictureUri) {
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java
index 5f4644614c7..805ffb2854a 100644
--- a/src/com/android/settings/vpn2/AppManagementFragment.java
+++ b/src/com/android/settings/vpn2/AppManagementFragment.java
@@ -35,11 +35,13 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
+import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
import com.android.internal.net.VpnConfig;
import com.android.internal.util.ArrayUtils;
@@ -76,7 +78,6 @@ public class AppManagementFragment extends SettingsPreferenceFragment
private String mVpnLabel;
// UI preference
- private Preference mPreferenceVersion;
private RestrictedSwitchPreference mPreferenceAlwaysOn;
private RestrictedSwitchPreference mPreferenceLockdown;
private RestrictedPreference mPreferenceForget;
@@ -122,7 +123,6 @@ public class AppManagementFragment extends SettingsPreferenceFragment
mConnectivityService = IConnectivityManager.Stub
.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- mPreferenceVersion = findPreference(KEY_VERSION);
mPreferenceAlwaysOn = (RestrictedSwitchPreference) findPreference(KEY_ALWAYS_ON_VPN);
mPreferenceLockdown = (RestrictedSwitchPreference) findPreference(KEY_LOCKDOWN_VPN);
mPreferenceForget = (RestrictedPreference) findPreference(KEY_FORGET_VPN);
@@ -138,9 +138,52 @@ public class AppManagementFragment extends SettingsPreferenceFragment
boolean isInfoLoaded = loadInfo();
if (isInfoLoaded) {
- mPreferenceVersion.setTitle(
- getPrefContext().getString(R.string.vpn_version, mPackageInfo.versionName));
updateUI();
+
+ Preference version = getPreferenceScreen().findPreference(KEY_VERSION);
+ if (version != null) {
+ // Version field has been added.
+ return;
+ }
+
+ /**
+ * Create version field at runtime, and set max height on the display area.
+ *
+ * When long length of text given within version field, a large text area
+ * might be created and inconvenient to the user (User need to scroll
+ * for a long time in order to get to the Preferences after this field.)
+ */
+ version = new Preference(getPrefContext()) {
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ TextView titleView =
+ (TextView) holder.findViewById(android.R.id.title);
+ if (titleView != null) {
+ titleView.setTextAppearance(R.style.vpn_app_management_version_title);
+ }
+
+ TextView summaryView =
+ (TextView) holder.findViewById(android.R.id.summary);
+ if (summaryView != null) {
+ summaryView.setTextAppearance(R.style.vpn_app_management_version_summary);
+
+ // Set max height in summary area.
+ int versionMaxHeight = getListView().getHeight();
+ summaryView.setMaxHeight(versionMaxHeight);
+ summaryView.setVerticalScrollBarEnabled(false);
+ summaryView.setHorizontallyScrolling(false);
+ }
+ }
+ };
+ version.setOrder(0); // Set order to 0 in order to be placed
+ // in front of other Preference(s).
+ version.setKey(KEY_VERSION); // Set key to avoid from creating multi instance.
+ version.setTitle(R.string.vpn_version);
+ version.setSummary(mPackageInfo.versionName);
+ version.setSelectable(false);
+ getPreferenceScreen().addPreference(version);
} else {
finish();
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
index 232837539e6..4e4331e3774 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
@@ -51,16 +51,23 @@ import java.util.List;
ShadowConnectivityManager.class, ShadowBluetoothAdapter.class})
public class ConnectedDeviceDashboardFragmentTest {
private static final String KEY_NEARBY_DEVICES = "bt_nearby_slice";
+ private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
+ private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
+ private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
+ private static final String TEST_APP_NAME = "com.testapp.settings";
+ private static final String TEST_ACTION = "com.testapp.settings.ACTION_START";
@Mock
private PackageManager mPackageManager;
private Context mContext;
+ private ConnectedDeviceDashboardFragment mFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mFragment = new ConnectedDeviceDashboardFragment();
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
}
@@ -85,6 +92,26 @@ public class ConnectedDeviceDashboardFragmentTest {
}
@Test
+ public void isAlwaysDiscoverable_callingAppIsNotFromSystemApp_returnsFalse() {
+ assertThat(mFragment.isAlwaysDiscoverable(TEST_APP_NAME, TEST_ACTION)).isFalse();
+ }
+
+ @Test
+ public void isAlwaysDiscoverable_callingAppIsFromSettings_returnsTrue() {
+ assertThat(mFragment.isAlwaysDiscoverable(SETTINGS_PACKAGE_NAME, TEST_ACTION)).isTrue();
+ }
+
+ @Test
+ public void isAlwaysDiscoverable_callingAppIsFromSystemUI_returnsTrue() {
+ assertThat(mFragment.isAlwaysDiscoverable(SYSTEMUI_PACKAGE_NAME, TEST_ACTION)).isTrue();
+ }
+
+ @Test
+ public void isAlwaysDiscoverable_actionIsFromSlice_returnsFalse() {
+ assertThat(mFragment.isAlwaysDiscoverable(SYSTEMUI_PACKAGE_NAME, SLICE_ACTION)).isFalse();
+ }
+
+ @Test
public void getPreferenceControllers_containSlicePrefController() {
final List<BasePreferenceController> controllers =
PreferenceControllerListHelper.getPreferenceControllersFromXml(mContext,
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java
index 3cc125b4d25..a64b2935638 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java
@@ -18,6 +18,7 @@ package com.android.settings.connecteddevice;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -116,14 +117,17 @@ public class DiscoverableFooterPreferenceControllerTest {
}
@Test
- public void onResume() {
+ public void onResume_setAlwaysDiscoverableAsTrue_shouldRegisterBluetoothChanged() {
+ mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(true);
mDiscoverableFooterPreferenceController.onResume();
+
assertThat(getRegisteredBroadcastReceivers()).contains(mBluetoothChangedReceiver);
verify(mAlwaysDiscoverable).start();
}
@Test
- public void onPause() {
+ public void onPause_setAlwaysDiscoverableAsTrue_shouldUnregisterBluetoothChanged() {
+ mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(true);
mDiscoverableFooterPreferenceController.onResume();
mDiscoverableFooterPreferenceController.onPause();
@@ -132,6 +136,25 @@ public class DiscoverableFooterPreferenceControllerTest {
}
@Test
+ public void onResume_setAlwaysDiscoverableAsFalse_shouldNotRegisterBluetoothChanged() {
+ mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(false);
+ mDiscoverableFooterPreferenceController.onResume();
+
+ assertThat(getRegisteredBroadcastReceivers()).contains(mBluetoothChangedReceiver);
+ verify(mAlwaysDiscoverable, never()).start();
+ }
+
+ @Test
+ public void onPause_setAlwaysDiscoverableAsFalse_shouldNotUnregisterBluetoothChanged() {
+ mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(false);
+ mDiscoverableFooterPreferenceController.onResume();
+ mDiscoverableFooterPreferenceController.onPause();
+
+ assertThat(getRegisteredBroadcastReceivers()).doesNotContain(mBluetoothChangedReceiver);
+ verify(mAlwaysDiscoverable, never()).stop();
+ }
+
+ @Test
public void onBluetoothStateChanged_bluetoothOn_updateTitle() {
BluetoothAdapter.getDefaultAdapter().setName(DEVICE_NAME);
sendBluetoothStateChangedIntent(BluetoothAdapter.STATE_ON);
diff --git a/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java
index 15fa5de8673..2831a4a3f93 100644
--- a/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java
@@ -27,6 +27,7 @@ import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
@@ -36,6 +37,7 @@ import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
@@ -109,6 +111,8 @@ public class PrivateDnsPreferenceControllerTest {
private Network mNetwork;
@Mock
private Preference mPreference;
+ @Mock
+ private UserManager mUserManager;
@Captor
private ArgumentCaptor<NetworkCallback> mCallbackCaptor;
private PrivateDnsPreferenceController mController;
@@ -127,6 +131,7 @@ public class PrivateDnsPreferenceControllerTest {
mShadowContentResolver = Shadow.extract(mContentResolver);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(mConnectivityManager);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
doNothing().when(mConnectivityManager).registerDefaultNetworkCallback(
mCallbackCaptor.capture(), nullable(Handler.class));
@@ -174,6 +179,12 @@ public class PrivateDnsPreferenceControllerTest {
}
@Test
+ public void getAvailabilityStatus_disabledForGuestUser() {
+ doReturn(true).when(mUserManager).isGuestUser();
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_USER);
+ }
+
+ @Test
public void goThroughLifecycle_shouldRegisterUnregisterSettingsObserver() {
mLifecycle.handleLifecycleEvent(ON_START);
verify(mContext, atLeastOnce()).getContentResolver();
diff --git a/tests/robotests/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceControllerTest.java
new file mode 100644
index 00000000000..3f4826061e4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceControllerTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2021 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.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.ZenPolicy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class AbstractZenModeAutomaticRulePreferenceControllerTest {
+
+ @Mock
+ private PackageManager mPm;
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ }
+
+ @Test
+ public void testGetSettingsActivity_configActivity() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("name", null,
+ new ComponentName(mContext.getPackageName(), "test"), Uri.EMPTY,
+ new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ rule.setPackageName(mContext.getPackageName());
+
+ when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+ when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+ ComponentName actual = AbstractZenModeAutomaticRulePreferenceController
+ .getSettingsActivity(mPm, rule, null);
+
+ assertThat(actual).isEqualTo(new ComponentName(mContext.getPackageName(), "test"));
+ }
+
+ @Test
+ public void testGetSettingsActivity_configActivity_wrongPackage() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("name", null,
+ new ComponentName("another", "test"), Uri.EMPTY,
+ new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ rule.setPackageName(mContext.getPackageName());
+
+ when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+ when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+ ComponentName actual = AbstractZenModeAutomaticRulePreferenceController
+ .getSettingsActivity(mPm, rule, null);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void testGetSettingsActivity_configActivity_unspecifiedOwner() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("name", null,
+ new ComponentName("another", "test"), Uri.EMPTY,
+ new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+ when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+ when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+ ComponentName actual = AbstractZenModeAutomaticRulePreferenceController
+ .getSettingsActivity(mPm, rule, null);
+
+ assertThat(actual).isEqualTo(new ComponentName("another", "test"));
+ }
+
+ @Test
+ public void testGetSettingsActivity_cps() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("name",
+ new ComponentName(mContext.getPackageName(), "service"), null, Uri.EMPTY,
+ new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ rule.setPackageName(mContext.getPackageName());
+
+ ComponentInfo ci = new ComponentInfo();
+ ci.packageName = mContext.getPackageName();
+ ci.metaData = new Bundle();
+ ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY,
+ ComponentName.flattenToShortString(
+ new ComponentName(mContext.getPackageName(), "activity")));
+
+ when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+ when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+ ComponentName actual = AbstractZenModeAutomaticRulePreferenceController
+ .getSettingsActivity(mPm, rule, ci);
+
+ assertThat(actual).isEqualTo(new ComponentName(mContext.getPackageName(), "activity"));
+ }
+
+ @Test
+ public void testGetSettingsActivity_cps_wrongPackage() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("name",
+ new ComponentName(mContext.getPackageName(), "service"), null, Uri.EMPTY,
+ new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ rule.setPackageName("other");
+
+ ComponentInfo ci = new ComponentInfo();
+ ci.packageName = mContext.getPackageName();
+ ci.metaData = new Bundle();
+ ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY,
+ ComponentName.flattenToShortString(
+ new ComponentName(mContext.getPackageName(), "activity")));
+
+ when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+ when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+ ComponentName actual = AbstractZenModeAutomaticRulePreferenceController
+ .getSettingsActivity(mPm, rule, ci);
+
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void testGetSettingsActivity_cps_unspecifiedPackage() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("name",
+ new ComponentName(mContext.getPackageName(), "service"), null, Uri.EMPTY,
+ new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+ ComponentInfo ci = new ComponentInfo();
+ ci.packageName = mContext.getPackageName();
+ ci.metaData = new Bundle();
+ ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY,
+ ComponentName.flattenToShortString(
+ new ComponentName(mContext.getPackageName(), "activity")));
+
+ when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+ when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+ ComponentName actual = AbstractZenModeAutomaticRulePreferenceController
+ .getSettingsActivity(mPm, rule, ci);
+
+ assertThat(actual).isEqualTo(new ComponentName(mContext.getPackageName(), "activity"));
+ }
+} \ No newline at end of file
diff --git a/tests/unit/Android.mk b/tests/unit/Android.mk
index 35d220532be..c643c755381 100644
--- a/tests/unit/Android.mk
+++ b/tests/unit/Android.mk
@@ -14,10 +14,12 @@ LOCAL_JAVA_LIBRARIES := \
LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx.test.core \
androidx.test.rules \
androidx.test.espresso.core \
androidx.test.espresso.contrib-nodeps \
androidx.test.espresso.intents-nodeps \
+ androidx.test.ext.junit \
mockito-target-minus-junit4 \
platform-test-annotations \
truth-prebuilt \
diff --git a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java
new file mode 100644
index 00000000000..7877684dce6
--- /dev/null
+++ b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.settings;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.RingtoneManager;
+import android.net.Uri;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unittest for DefaultRingtonePreference. */
+@RunWith(AndroidJUnit4.class)
+public class DefaultRingtonePreferenceTest {
+
+ private DefaultRingtonePreference mDefaultRingtonePreference;
+
+ @Mock
+ private ContentResolver mContentResolver;
+ @Mock
+ private Uri mRingtoneUri;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ Context context = spy(ApplicationProvider.getApplicationContext());
+ doReturn(mContentResolver).when(context).getContentResolver();
+
+ mDefaultRingtonePreference = spy(new DefaultRingtonePreference(context, null /* attrs */));
+ doReturn(context).when(mDefaultRingtonePreference).getContext();
+ when(mDefaultRingtonePreference.getRingtoneType())
+ .thenReturn(RingtoneManager.TYPE_RINGTONE);
+ mDefaultRingtonePreference.setUserId(1);
+ mDefaultRingtonePreference.mUserContext = context;
+ }
+
+ @Test
+ public void onSaveRingtone_nullMimeType_shouldNotSetRingtone() {
+ when(mContentResolver.getType(mRingtoneUri)).thenReturn(null);
+
+ mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri);
+
+ verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri);
+ }
+
+ @Test
+ public void onSaveRingtone_notAudioMimeType_shouldNotSetRingtone() {
+ when(mContentResolver.getType(mRingtoneUri)).thenReturn("text/plain");
+
+ mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri);
+
+ verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri);
+ }
+}