diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-10-13 07:59:59 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-10-13 07:59:59 +0000 |
commit | 3ec694e35e992b60e58f2f3493f398235c073b9a (patch) | |
tree | 2778a1db372ae3113fd068ad7f5f4dcb9f14d00a | |
parent | d15ecd4c642d89af9213ef4803534cdffe2f1144 (diff) | |
parent | 05ea36ddc50c504fc21df11195ca5850396cdcd6 (diff) | |
download | Settings-android10-android13-mainline-tzdata-release.tar.gz |
Snap for 9170954 from 05ea36ddc50c504fc21df11195ca5850396cdcd6 to qt-aml-tzdata-releaseq_tzdata_aml_297100400q_tzdata_aml_297100300q_tzdata_aml_297100000q_tzdata_aml_296200000q_tzdata_aml_295600118q_tzdata_aml_295600110q_tzdata_aml_295500002q_tzdata_aml_295500001q_tzdata_aml_297100000android10-mainline-tzdata-releaseandroid10-android13-mainline-tzdata-release
Change-Id: I7ca721489510f79850728e299b0b2f6201010a23
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); + } +} |