diff --git a/res/layout/fingerprint_enroll_finish_base.xml b/res/layout/fingerprint_enroll_finish_base.xml index 262374d238e..48831dc36c2 100644 --- a/res/layout/fingerprint_enroll_finish_base.xml +++ b/res/layout/fingerprint_enroll_finish_base.xml @@ -52,6 +52,7 @@ android:layout_height="match_parent" android:padding="7dp" android:contentDescription="@android:string/fingerprint_icon_content_description" + android:importantForAccessibility="no" android:src="@drawable/fingerprint_enroll_finish" /> diff --git a/res/values/config.xml b/res/values/config.xml index d37db441ea4..21d9c7528d1 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -495,12 +495,6 @@ - - - - - - false diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 619728201bf..a9cda9e75ac 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -185,9 +185,6 @@ 32 - - 56dp - 58dip 16dip diff --git a/res/values/strings.xml b/res/values/strings.xml index 28b2e99f9d1..a34f909260c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -916,11 +916,11 @@ No thanks - Skip + No thanks Continue - Agree + I agree Skip @@ -1017,7 +1017,9 @@ It\u2019s on the back of your phone. Use your index finger. - The fingerprint sensor is on your screen. Move your finger across the screen to find it. + The fingerprint sensor is on your screen + + The fingerprint sensor is on your screen. Move your finger across the screen to find the sensor. Illustration with device and fingerprint sensor location @@ -1031,21 +1033,21 @@ Put your finger on the sensor and lift after you feel a vibration - Each time you touch, keep your finger on the icon until you feel a vibration + Keep your finger on the icon until you feel a vibration Lift, then touch again One more time - Touch the fingerprint icon as it moves + Follow the fingerprint icon Keep lifting your finger to add the different parts of your fingerprint - This helps capture your full fingerprint + Touch & hold each time the icon moves. This helps capture your full fingerprint. Fingerprint added - When you see this icon, use your fingerprint for identification or to approve purchases + Now you can use your fingerprint to unlock your phone or for authentication, like when you sign in to apps Do it later @@ -1505,7 +1507,7 @@ "Device protection features will not work without your screen lock.\n\nThis deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps." - Yes, remove + Delete Change unlock pattern diff --git a/res/values/styles.xml b/res/values/styles.xml index e8670f971f5..d9a55e6211b 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -145,7 +145,6 @@ 4dip viewStart @android:style/TextAppearance.DeviceDefault.Medium - ?android:attr/textColorSecondary @dimen/min_tap_target_size diff --git a/res/values/themes.xml b/res/values/themes.xml index af44276c281..555a0454a66 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -32,6 +32,7 @@ @android:color/transparent @style/PickerDialogTheme.Settings @style/HorizontalProgressBarStyle + ?android:attr/textColorSecondary @style/FingerprintLayoutTheme @style/FaceLayoutTheme diff --git a/res/xml/accounts_dashboard_settings.xml b/res/xml/accounts_dashboard_settings.xml index c50eca4761c..c8627e7e9e7 100644 --- a/res/xml/accounts_dashboard_settings.xml +++ b/res/xml/accounts_dashboard_settings.xml @@ -46,33 +46,27 @@ + android:key="dashboard_tile_placeholder" + android:order="130"/> - + - + - - - - + diff --git a/res/xml/accounts_personal_dashboard_settings.xml b/res/xml/accounts_personal_dashboard_settings.xml index 3d88cf9ec12..e0ba71bbef3 100644 --- a/res/xml/accounts_personal_dashboard_settings.xml +++ b/res/xml/accounts_personal_dashboard_settings.xml @@ -47,26 +47,20 @@ + android:key="dashboard_tile_placeholder" + android:order="130"/> - + - - - - + diff --git a/res/xml/accounts_work_dashboard_settings.xml b/res/xml/accounts_work_dashboard_settings.xml index 29e71e28258..1c4c6aa3f3d 100644 --- a/res/xml/accounts_work_dashboard_settings.xml +++ b/res/xml/accounts_work_dashboard_settings.xml @@ -33,7 +33,7 @@ + android:title="@string/autofill_app"> + android:key="dashboard_tile_placeholder" + android:order="130"/> - + - - - - + diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml index 5084d4d481a..9df195584d6 100644 --- a/res/xml/bluetooth_device_details_fragment.xml +++ b/res/xml/bluetooth_device_details_fragment.xml @@ -38,6 +38,11 @@ android:key="action_buttons" settings:allowDividerBelow="true"/> + + + + android:orderingFromXml="false" + android:title="@string/bluetooth_preference_found_media_devices" /> diff --git a/res/xml/gesture_navigation_settings.xml b/res/xml/gesture_navigation_settings.xml index b50954222ed..0515d78649f 100644 --- a/res/xml/gesture_navigation_settings.xml +++ b/res/xml/gesture_navigation_settings.xml @@ -49,7 +49,6 @@ android:key="gesture_navigation_settings_footer" android:title="@string/back_sensitivity_dialog_message" android:selectable="false" - settings:searchable="false" - settings:allowDividerAbove="true"/> + settings:searchable="false"/> diff --git a/res/xml/installed_app_launch_settings.xml b/res/xml/installed_app_launch_settings.xml index d631e56eaa0..7d971b07d2b 100644 --- a/res/xml/installed_app_launch_settings.xml +++ b/res/xml/installed_app_launch_settings.xml @@ -23,10 +23,6 @@ android:key="open_by_default_supported_links" android:title="@string/app_launch_open_domain_urls_title"/> - - + android:fragment="com.android.settings.applications.AppDashboardFragment" + android:icon="@drawable/ic_apps" + android:key="top_level_apps" + android:order="-130" + android:title="@string/apps_dashboard_title" + android:summary="@string/app_and_notification_dashboard_summary"/> + + - - - - + android:fragment="com.android.settings.notification.SoundSettings" + android:icon="@drawable/ic_volume_up_24dp" + android:key="top_level_sound" + android:order="-90" + android:title="@string/sound_settings" + android:summary="@string/sound_dashboard_summary"/> + android:fragment="com.android.settings.DisplaySettings" + android:icon="@drawable/ic_settings_display_white" + android:key="top_level_display" + android:order="-80" + android:title="@string/display_settings" + android:summary="@string/display_dashboard_summary" + settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/> + + + + + android:fragment="com.android.settings.privacy.PrivacyDashboardFragment" + android:icon="@drawable/ic_settings_privacy" + android:key="top_level_privacy" + android:order="-40" + android:title="@string/privacy_dashboard_title" + android:summary="@string/privacy_dashboard_summary"/> + android:fragment="com.android.settings.location.LocationSettings" + android:icon="@drawable/ic_settings_location" + android:key="top_level_location" + android:order="-30" + android:title="@string/location_settings_title" + android:summary="@string/location_settings_loading_app_permission_stats" + settings:controller="com.android.settings.location.TopLevelLocationPreferenceController"/> + android:fragment="com.android.settings.accounts.AccountDashboardFragment" + android:icon="@drawable/ic_settings_accounts" + android:key="top_level_accounts" + android:order="-10" + android:title="@string/account_dashboard_title" + android:summary="@string/summary_placeholder" + settings:controller="com.android.settings.accounts.TopLevelAccountEntryPreferenceController"/> + + diff --git a/res/xml/top_level_settings_grouped.xml b/res/xml/top_level_settings_grouped.xml deleted file mode 100644 index 7b4f8a10773..00000000000 --- a/res/xml/top_level_settings_grouped.xml +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java index 036df276877..42b2334f232 100644 --- a/src/com/android/settings/accounts/AccountPreferenceController.java +++ b/src/com/android/settings/accounts/AccountPreferenceController.java @@ -80,7 +80,6 @@ public class AccountPreferenceController extends AbstractPreferenceController private static final int ORDER_NEXT_TO_LAST = 1001; private static final int ORDER_NEXT_TO_NEXT_TO_LAST = 1000; - private static final String PREF_KEY_ACCOUNTS = "accounts_category"; private static final String PREF_KEY_ADD_ACCOUNT = "add_account"; private static final String PREF_KEY_REMOVE_PROFILE = "remove_profile"; private static final String PREF_KEY_WORK_PROFILE_SETTING = "work_profile_setting"; @@ -324,6 +323,7 @@ public class AccountPreferenceController extends AbstractPreferenceController mHelper.createAccessiblePreferenceCategory( mFragment.getPreferenceManager().getContext()); preferenceGroup.setOrder(mAccountProfileOrder++); + preferenceGroup.setTitle(R.string.account_settings); // default title; may be modified below if (isSingleProfile()) { final String title = context.getString(R.string.account_for_section_header, BidiFormatter.getInstance().unicodeWrap(userInfo.name)); @@ -349,10 +349,8 @@ public class AccountPreferenceController extends AbstractPreferenceController } } final PreferenceScreen screen = mFragment.getPreferenceScreen(); - final PreferenceGroup accounts = - screen == null ? null : screen.findPreference(PREF_KEY_ACCOUNTS); - if (accounts != null) { - accounts.addPreference(preferenceGroup); + if (screen != null) { + screen.addPreference(preferenceGroup); } profileData.preferenceGroup = preferenceGroup; if (userInfo.isEnabled()) { diff --git a/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java b/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java index 0f90c69c9ae..5f7e56fa0e4 100644 --- a/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java +++ b/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java @@ -158,6 +158,10 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc } public static CharSequence getSummary(Context context, AppEntry entry) { + if (entry == null) { + return ""; + } + OverlayState state; if (entry.extraInfo instanceof OverlayState) { state = (OverlayState) entry.extraInfo; diff --git a/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java b/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java index a2771697373..8683f56af79 100644 --- a/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java +++ b/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java @@ -191,12 +191,13 @@ public class AppLaunchSettings extends AppInfoBase implements return; } final Activity activity = getActivity(); + final String summary = activity.getString(R.string.app_launch_top_intro_message); final Preference pref = EntityHeaderController .newInstance(activity, this, null /* header */) .setRecyclerView(getListView(), getSettingsLifecycle()) .setIcon(Utils.getBadgedIcon(mContext, mPackageInfo.applicationInfo)) .setLabel(mPackageInfo.applicationInfo.loadLabel(mPm)) - .setSummary("" /* summary */) // no version number + .setSummary(summary) // add intro text .setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo)) .setPackageName(mPackageName) .setUid(mPackageInfo.applicationInfo.uid) diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java index 1ad34ba7cfa..6bdd3f7ddd1 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java @@ -52,6 +52,7 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupcompat.util.WizardManagerHelper; import java.util.List; @@ -109,6 +110,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { @Nullable private AnimatedVectorDrawable mIconBackgroundBlinksDrawable; private boolean mRestoring; private Vibrator mVibrator; + private boolean mIsSetupWizard; @Override protected void onCreate(Bundle savedInstanceState) { @@ -131,7 +133,12 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message); } - setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title); + mIsSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent()); + if (mCanAssumeUdfps && !mIsSetupWizard) { + setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title); + } else { + setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title); + } mErrorText = findViewById(R.id.error_text); mProgressBar = findViewById(R.id.fingerprint_progress_bar); @@ -280,7 +287,11 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message); } } else if (mCanAssumeUdfps && !isCenterEnrollmentComplete()) { - setHeaderText(R.string.security_settings_udfps_enroll_title_one_more_time); + if (mIsSetupWizard) { + setHeaderText(R.string.security_settings_udfps_enroll_title_one_more_time); + } else { + setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title); + } setDescriptionText(R.string.security_settings_udfps_enroll_start_message); } else { if (mCanAssumeUdfps) { diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java index 2cb5ff88691..aee2c9adf80 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java @@ -72,6 +72,8 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements if (mCanAssumeUdfps) { setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title); setDescriptionText(R.string.security_settings_udfps_enroll_find_sensor_message); + final CharSequence description = getString(R.string.security_settings_udfps_enroll_find_sensor_a11y); + getLayout().getDescriptionTextView().setContentDescription(description); } else { setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title); setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message); diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java index cc1458626c0..5851b506e4e 100644 --- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java +++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java @@ -274,37 +274,43 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont showBatteryPredictionIfNecessary(linearLayout, deviceId, batteryLevel); } final TextView batterySummaryView = linearLayout.findViewById(R.id.bt_battery_summary); - if (batteryLevel != BluetoothUtils.META_INT_ERROR) { - linearLayout.setVisibility(View.VISIBLE); - batterySummaryView.setText(com.android.settings.Utils.formatPercentage(batteryLevel)); - batterySummaryView.setVisibility(View.VISIBLE); - int lowBatteryLevel = BluetoothUtils.getIntMetaData(bluetoothDevice, lowBatteryMetaKey); - if (lowBatteryLevel == BluetoothUtils.META_INT_ERROR) { - if (batteryMetaKey == BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY) { - lowBatteryLevel = CASE_LOW_BATTERY_LEVEL; - } else { - lowBatteryLevel = LOW_BATTERY_LEVEL; - } - } - showBatteryIcon(linearLayout, batteryLevel, lowBatteryLevel, charging); - } else { - if (deviceId == MAIN_DEVICE_ID) { + if (isUntetheredHeadset(bluetoothDevice)) { + if (batteryLevel != BluetoothUtils.META_INT_ERROR) { linearLayout.setVisibility(View.VISIBLE); - linearLayout.findViewById(R.id.bt_battery_icon).setVisibility(View.GONE); - int level = bluetoothDevice.getBatteryLevel(); - if (level != BluetoothDevice.BATTERY_LEVEL_UNKNOWN - && level != BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF) { - batterySummaryView.setText(com.android.settings.Utils.formatPercentage(level)); - batterySummaryView.setVisibility(View.VISIBLE); - } else { - batterySummaryView.setVisibility(View.GONE); + batterySummaryView.setText( + com.android.settings.Utils.formatPercentage(batteryLevel)); + batterySummaryView.setVisibility(View.VISIBLE); + int lowBatteryLevel = BluetoothUtils.getIntMetaData(bluetoothDevice, + lowBatteryMetaKey); + if (lowBatteryLevel == BluetoothUtils.META_INT_ERROR) { + if (batteryMetaKey == BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY) { + lowBatteryLevel = CASE_LOW_BATTERY_LEVEL; + } else { + lowBatteryLevel = LOW_BATTERY_LEVEL; + } } + showBatteryIcon(linearLayout, batteryLevel, lowBatteryLevel, charging); } else { - // Hide it if it doesn't have battery information - linearLayout.setVisibility(View.GONE); + if (deviceId == MAIN_DEVICE_ID) { + linearLayout.setVisibility(View.VISIBLE); + linearLayout.findViewById(R.id.bt_battery_icon).setVisibility(View.GONE); + int level = bluetoothDevice.getBatteryLevel(); + if (level != BluetoothDevice.BATTERY_LEVEL_UNKNOWN + && level != BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF) { + batterySummaryView.setText( + com.android.settings.Utils.formatPercentage(level)); + batterySummaryView.setVisibility(View.VISIBLE); + } else { + batterySummaryView.setVisibility(View.GONE); + } + } else { + // Hide it if it doesn't have battery information + linearLayout.setVisibility(View.GONE); + } } + } else { + batterySummaryView.setVisibility(View.GONE); } - final TextView textView = linearLayout.findViewById(R.id.header_title); if (deviceId == MAIN_DEVICE_ID) { textView.setVisibility(View.GONE); @@ -314,6 +320,14 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont } } + private boolean isUntetheredHeadset(BluetoothDevice bluetoothDevice) { + return BluetoothUtils.getBooleanMetaData(bluetoothDevice, + BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET) + || TextUtils.equals(BluetoothUtils.getStringMetaData(bluetoothDevice, + BluetoothDevice.METADATA_DEVICE_TYPE), + BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET); + } + private void showBatteryPredictionIfNecessary(LinearLayout linearLayout, int batteryId, int batteryLevel) { ThreadUtils.postOnBackgroundThread(() -> { diff --git a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java index d7dad887fec..993f584dd36 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java @@ -31,38 +31,39 @@ import android.os.UserHandle; */ public final class BluetoothPairingRequest extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action == null || !action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { - return; - } - PowerManager powerManager = context.getSystemService(PowerManager.class); - BluetoothDevice device = - intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, - BluetoothDevice.ERROR); - String deviceAddress = device != null ? device.getAddress() : null; - String deviceName = device != null ? device.getName() : null; - boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground( - context, deviceAddress, deviceName); + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action == null || !action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { + return; + } - // Skips consent pairing dialog if the device was recently associated with CDM - if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT - && device.canBondWithoutDialog()) { - device.setPairingConfirmation(true); - } else if (powerManager.isInteractive() && shouldShowDialog) { - // Since the screen is on and the BT-related activity is in the foreground, - // just open the dialog - // convert broadcast intent into activity intent (same action string) - Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context, intent, - BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND); + PowerManager powerManager = context.getSystemService(PowerManager.class); + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, + BluetoothDevice.ERROR); + String deviceAddress = device != null ? device.getAddress() : null; + String deviceName = device != null ? device.getName() : null; + boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground( + context, deviceAddress, deviceName); - context.startActivityAsUser(pairingIntent, UserHandle.CURRENT); - } else { - // Put up a notification that leads to the dialog - intent.setClass(context, BluetoothPairingService.class); - context.startServiceAsUser(intent, UserHandle.CURRENT); + // Skips consent pairing dialog if the device was recently associated with CDM + if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT + && device.canBondWithoutDialog()) { + device.setPairingConfirmation(true); + } else if (powerManager.isInteractive() && shouldShowDialog) { + // Since the screen is on and the BT-related activity is in the foreground, + // just open the dialog + // convert broadcast intent into activity intent (same action string) + Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context, intent, + BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND); + + context.startActivityAsUser(pairingIntent, UserHandle.CURRENT); + } else { + // Put up a notification that leads to the dialog + intent.setClass(context, BluetoothPairingService.class); + intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST); + context.startServiceAsUser(intent, UserHandle.CURRENT); + } } - } } diff --git a/src/com/android/settings/bluetooth/BluetoothPairingService.java b/src/com/android/settings/bluetooth/BluetoothPairingService.java index c411b0cd0b4..0bff721b8a9 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingService.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingService.java @@ -31,6 +31,9 @@ import android.os.IBinder; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.VisibleForTesting; +import androidx.core.app.NotificationCompat; + import com.android.settings.R; /** @@ -39,10 +42,14 @@ import com.android.settings.R; */ public final class BluetoothPairingService extends Service { - private static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth; - - private static final String ACTION_DISMISS_PAIRING = + @VisibleForTesting + static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth; + @VisibleForTesting + static final String ACTION_DISMISS_PAIRING = "com.android.settings.bluetooth.ACTION_DISMISS_PAIRING"; + @VisibleForTesting + static final String ACTION_PAIRING_DIALOG = + "com.android.settings.bluetooth.ACTION_PAIRING_DIALOG"; private static final String BLUETOOTH_NOTIFICATION_CHANNEL = "bluetooth_notification_channel"; @@ -51,6 +58,9 @@ public final class BluetoothPairingService extends Service { private BluetoothDevice mDevice; + @VisibleForTesting + NotificationManager mNm; + public static Intent getPairingDialogIntent(Context context, Intent intent, int initiator) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, @@ -80,33 +90,35 @@ public final class BluetoothPairingService extends Service { if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); + Log.d(TAG, "onReceive() Bond state change : " + bondState + ", device name : " + + mDevice.getName()); if ((bondState != BluetoothDevice.BOND_NONE) && (bondState != BluetoothDevice.BOND_BONDED)) { return; } } else if (action.equals(ACTION_DISMISS_PAIRING)) { - Log.d(TAG, "Notification cancel " + mDevice.getAddress() + " (" + + Log.d(TAG, "Notification cancel " + " (" + mDevice.getName() + ")"); mDevice.cancelPairing(); } else { int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); - Log.d(TAG, "Dismiss pairing for " + mDevice.getAddress() + " (" + + Log.d(TAG, "Dismiss pairing for " + " (" + mDevice.getName() + "), BondState: " + bondState); } - stopForeground(true); + + mNm.cancel(NOTIFICATION_ID); stopSelf(); } }; @Override public void onCreate() { - NotificationManager mgr = (NotificationManager)this - .getSystemService(Context.NOTIFICATION_SERVICE); - NotificationChannel notificationChannel = new NotificationChannel( - BLUETOOTH_NOTIFICATION_CHANNEL, - this.getString(R.string.bluetooth), - NotificationManager.IMPORTANCE_HIGH); - mgr.createNotificationChannel(notificationChannel); + mNm = getSystemService(NotificationManager.class); + NotificationChannel notificationChannel = new NotificationChannel( + BLUETOOTH_NOTIFICATION_CHANNEL, + this.getString(R.string.bluetooth), + NotificationManager.IMPORTANCE_HIGH); + mNm.createNotificationChannel(notificationChannel); } @Override @@ -116,23 +128,8 @@ public final class BluetoothPairingService extends Service { stopSelf(); return START_NOT_STICKY; } - - Resources res = getResources(); - Notification.Builder builder = new Notification.Builder(this, - BLUETOOTH_NOTIFICATION_CHANNEL) - .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) - .setTicker(res.getString(R.string.bluetooth_notif_ticker)) - .setLocalOnly(true); - - PendingIntent pairIntent = PendingIntent.getActivity(this, 0, - getPairingDialogIntent(this, intent, - BluetoothDevice.EXTRA_PAIRING_INITIATOR_BACKGROUND), - PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT - | PendingIntent.FLAG_IMMUTABLE); - - PendingIntent dismissIntent = PendingIntent.getBroadcast(this, 0, - new Intent(ACTION_DISMISS_PAIRING), PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE); + String action = intent.getAction(); + Log.d(TAG, "onStartCommand() action : " + action); mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); @@ -142,36 +139,76 @@ public final class BluetoothPairingService extends Service { return START_NOT_STICKY; } + if (TextUtils.equals(action, BluetoothDevice.ACTION_PAIRING_REQUEST)) { + createPairingNotification(intent); + } else if (TextUtils.equals(action, ACTION_DISMISS_PAIRING)) { + Log.d(TAG, "Notification cancel " + " (" + mDevice.getName() + ")"); + mDevice.cancelPairing(); + mNm.cancel(NOTIFICATION_ID); + stopSelf(); + } else if (TextUtils.equals(action, ACTION_PAIRING_DIALOG)) { + Intent pairingDialogIntent = getPairingDialogIntent(this, intent, + BluetoothDevice.EXTRA_PAIRING_INITIATOR_BACKGROUND); + + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + filter.addAction(BluetoothDevice.ACTION_PAIRING_CANCEL); + filter.addAction(ACTION_DISMISS_PAIRING); + registerReceiver(mCancelReceiver, filter); + mRegistered = true; + + startActivity(pairingDialogIntent); + } + + return START_STICKY; + } + + private void createPairingNotification(Intent intent) { + Resources res = getResources(); + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, + BLUETOOTH_NOTIFICATION_CHANNEL) + .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) + .setTicker(res.getString(R.string.bluetooth_notif_ticker)) + .setLocalOnly(true); + + int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, + BluetoothDevice.ERROR); + Intent pairingDialogIntent = new Intent(ACTION_PAIRING_DIALOG); + pairingDialogIntent.setClass(this, BluetoothPairingService.class); + pairingDialogIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); + pairingDialogIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, type); + PendingIntent pairIntent = PendingIntent.getService(this, 0, pairingDialogIntent, + PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); + + Intent serviceIntent = new Intent(ACTION_DISMISS_PAIRING); + serviceIntent.setClass(this, BluetoothPairingService.class); + serviceIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); + PendingIntent dismissIntent = PendingIntent.getService(this, 0, + serviceIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); + String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME); if (TextUtils.isEmpty(name)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); name = device != null ? device.getAlias() : res.getString(android.R.string.unknownName); } - Log.d(TAG, "Show pairing notification for " + mDevice.getAddress() + " (" + name + ")"); + Log.d(TAG, "Show pairing notification for " + " (" + name + ")"); - Notification.Action pairAction = new Notification.Action.Builder(0, + NotificationCompat.Action pairAction = new NotificationCompat.Action.Builder(0, res.getString(R.string.bluetooth_device_context_pair_connect), pairIntent).build(); - Notification.Action dismissAction = new Notification.Action.Builder(0, + NotificationCompat.Action dismissAction = new NotificationCompat.Action.Builder(0, res.getString(android.R.string.cancel), dismissIntent).build(); builder.setContentTitle(res.getString(R.string.bluetooth_notif_title)) .setContentText(res.getString(R.string.bluetooth_notif_message, name)) .setContentIntent(pairIntent) .setDefaults(Notification.DEFAULT_SOUND) + .setOngoing(true) .setColor(getColor(com.android.internal.R.color.system_notification_accent_color)) .addAction(pairAction) .addAction(dismissAction); - IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); - filter.addAction(BluetoothDevice.ACTION_PAIRING_CANCEL); - filter.addAction(ACTION_DISMISS_PAIRING); - registerReceiver(mCancelReceiver, filter); - mRegistered = true; - - startForeground(NOTIFICATION_ID, builder.getNotification()); - return START_REDELIVER_INTENT; + mNm.notify(NOTIFICATION_ID, builder.build()); } @Override @@ -180,7 +217,6 @@ public final class BluetoothPairingService extends Service { unregisterReceiver(mCancelReceiver); mRegistered = false; } - stopForeground(true); } @Override diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java index b404ecccdc7..0de86f5b668 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java @@ -47,7 +47,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.FeatureFlagUtils; import android.util.Log; import android.util.Pair; import android.widget.Toast; @@ -60,7 +59,6 @@ import androidx.preference.SwitchPreference; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; -import com.android.settings.core.FeatureFlags; import com.android.settings.dashboard.profileselector.ProfileSelectDialog; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.PrimarySwitchPreference; @@ -185,9 +183,6 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { pref.setOrder(order + baseOrder); } } - - overrideTilePosition(tile, pref); - return outObservers.isEmpty() ? null : outObservers; } @@ -402,8 +397,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { private void setPreferenceIcon(Preference preference, Tile tile, boolean forceRoundedIcon, String iconPackage, Icon icon) { Drawable iconDrawable = icon.loadDrawable(preference.getContext()); - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME) - && TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) { + if (TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) { iconDrawable.setTint(Utils.getHomepageIconColor(preference.getContext())); } else if (forceRoundedIcon && !TextUtils.equals(mContext.getPackageName(), iconPackage)) { iconDrawable = new AdaptiveIcon(mContext, iconDrawable, @@ -457,25 +451,4 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { } return eligibleUsers; } - - private void overrideTilePosition(Tile tile, Preference pref) { - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME) - && TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) { - final String[] homepageTilePackages = mContext.getResources().getStringArray( - R.array.config_homepage_tile_packages); - final int[] homepageTileOrders = mContext.getResources().getIntArray( - R.array.config_homepage_tile_orders); - if (homepageTilePackages.length == 0 - || homepageTilePackages.length != homepageTileOrders.length) { - return; - } - - for (int i = 0; i < homepageTilePackages.length; i++) { - if (TextUtils.equals(tile.getPackageName(), homepageTilePackages[i])) { - pref.setOrder(homepageTileOrders[i]); - return; - } - } - } - } } diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java index 90b0d55efc8..61bbd185979 100644 --- a/src/com/android/settings/display/SmartAutoRotateController.java +++ b/src/com/android/settings/display/SmartAutoRotateController.java @@ -18,6 +18,9 @@ package com.android.settings.display; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static android.provider.Settings.Secure.CAMERA_AUTOROTATE; +import static androidx.lifecycle.Lifecycle.Event.ON_START; +import static androidx.lifecycle.Lifecycle.Event.ON_STOP; + import android.Manifest; import android.app.settings.SettingsEnums; import android.content.BroadcastReceiver; @@ -32,7 +35,9 @@ import android.provider.Settings; import android.service.rotationresolver.RotationResolverService; import android.text.TextUtils; +import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -41,14 +46,12 @@ import com.android.internal.view.RotationPolicy; import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.core.lifecycle.events.OnStart; -import com.android.settingslib.core.lifecycle.events.OnStop; /** * SmartAutoRotateController controls whether auto rotation is enabled */ public class SmartAutoRotateController extends TogglePreferenceController implements - Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart, OnStop { + Preference.OnPreferenceChangeListener, LifecycleObserver { private final MetricsFeatureProvider mMetricsFeatureProvider; private final SensorPrivacyManager mPrivacyManager; @@ -60,6 +63,7 @@ public class SmartAutoRotateController extends TogglePreferenceController implem } }; private Preference mPreference; + private RotationPolicy.RotationPolicyListener mRotationPolicyListener; public SmartAutoRotateController(Context context, String preferenceKey) { super(context, preferenceKey); @@ -70,6 +74,10 @@ public class SmartAutoRotateController extends TogglePreferenceController implem mPowerManager = context.getSystemService(PowerManager.class); } + public void init(Lifecycle lifecycle) { + lifecycle.addObserver(this); + } + @Override public int getAvailabilityStatus() { if (!isRotationResolverServiceAvailable(mContext)) { @@ -101,22 +109,36 @@ public class SmartAutoRotateController extends TogglePreferenceController implem return mPowerManager.isPowerSaveMode(); } - @Override + @OnLifecycleEvent(ON_START) public void onStart() { mContext.registerReceiver(mReceiver, new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); + if (mRotationPolicyListener == null) { + mRotationPolicyListener = new RotationPolicy.RotationPolicyListener() { + @Override + public void onChange() { + updateState(mPreference); + } + }; + } + RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener); } - @Override + @OnLifecycleEvent(ON_STOP) public void onStop() { mContext.unregisterReceiver(mReceiver); + if (mRotationPolicyListener != null) { + RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener); + mRotationPolicyListener = null; + } } @Override public boolean isChecked() { - return hasSufficientPermission(mContext) && !isCameraLocked() && !isPowerSaveMode() - && Settings.Secure.getInt(mContext.getContentResolver(), - CAMERA_AUTOROTATE, 0) == 1; + return !RotationPolicy.isRotationLocked(mContext) && hasSufficientPermission(mContext) + && !isCameraLocked() && !isPowerSaveMode() && Settings.Secure.getInt( + mContext.getContentResolver(), + CAMERA_AUTOROTATE, 0) == 1; } @Override diff --git a/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java b/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java index f697a8c7c48..d56b21e1c76 100644 --- a/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java +++ b/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java @@ -15,13 +15,11 @@ */ package com.android.settings.display; -import static com.android.settings.display.SmartAutoRotateController.hasSufficientPermission; import static com.android.settings.display.SmartAutoRotateController.isRotationResolverServiceAvailable; import android.app.settings.SettingsEnums; -import android.hardware.SensorPrivacyManager; +import android.content.Context; import android.os.Bundle; -import android.os.PowerManager; import android.text.Html; import android.view.LayoutInflater; import android.view.View; @@ -49,16 +47,19 @@ public class SmartAutoRotatePreferenceFragment extends DashboardFragment { private static final String TAG = "SmartAutoRotatePreferenceFragment"; private RotationPolicy.RotationPolicyListener mRotationPolicyListener; - private SensorPrivacyManager mPrivacyManager; private AutoRotateSwitchBarController mSwitchBarController; - private PowerManager mPowerManager; - private static final String FACE_SWITCH_PREFERENCE_ID = "face_based_rotate"; @Override protected int getPreferenceScreenResId() { return R.xml.auto_rotate_settings; } + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(SmartAutoRotateController.class).init(getLifecycle()); + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -70,8 +71,6 @@ public class SmartAutoRotatePreferenceFragment extends DashboardFragment { switchBar.show(); mSwitchBarController = new AutoRotateSwitchBarController(activity, switchBar, getSettingsLifecycle()); - mPrivacyManager = SensorPrivacyManager.getInstance(activity); - mPowerManager = getSystemService(PowerManager.class); final Preference footerPreference = findPreference(FooterPreference.KEY_FOOTER); if (footerPreference != null) { footerPreference.setTitle(Html.fromHtml(getString(R.string.smart_rotate_text_headline), @@ -89,14 +88,6 @@ public class SmartAutoRotatePreferenceFragment extends DashboardFragment { @Override public void onChange() { mSwitchBarController.onChange(); - final boolean isLocked = RotationPolicy.isRotationLocked(getContext()); - final boolean isCameraLocked = mPrivacyManager.isSensorPrivacyEnabled( - SensorPrivacyManager.Sensors.CAMERA); - final boolean isBatterySaver = mPowerManager.isPowerSaveMode(); - final Preference preference = findPreference(FACE_SWITCH_PREFERENCE_ID); - if (preference != null && hasSufficientPermission(getContext())) { - preference.setEnabled(!isLocked && !isCameraLocked && !isBatterySaver); - } } }; } diff --git a/src/com/android/settings/dream/StartNowPreferenceController.java b/src/com/android/settings/dream/StartNowPreferenceController.java index ed0a4dbeece..f6a79ccea01 100644 --- a/src/com/android/settings/dream/StartNowPreferenceController.java +++ b/src/com/android/settings/dream/StartNowPreferenceController.java @@ -59,8 +59,10 @@ public class StartNowPreferenceController extends SettingsMainSwitchPreferenceCo @Override public boolean setChecked(boolean isChecked) { if (isChecked) { - mMetricsFeatureProvider.logClickedPreference(mSwitchPreference, - mSwitchPreference.getExtras().getInt(DashboardFragment.CATEGORY)); + if (mSwitchPreference != null) { + mMetricsFeatureProvider.logClickedPreference(mSwitchPreference, + mSwitchPreference.getExtras().getInt(DashboardFragment.CATEGORY)); + } mBackend.startDreaming(); } return true; diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java index 1b5c7795022..7486f22d0a8 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.fuelgauge; +import android.app.settings.SettingsEnums; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; @@ -35,7 +36,9 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnCreate; @@ -88,9 +91,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll private final String mPreferenceKey; private final SettingsActivity mActivity; private final InstrumentedPreferenceFragment mFragment; - private final Handler mHandler = new Handler(Looper.getMainLooper()); - private final CharSequence[] mNotAllowShowSummaryPackages; private final CharSequence[] mNotAllowShowEntryPackages; + private final CharSequence[] mNotAllowShowSummaryPackages; + private final MetricsFeatureProvider mMetricsFeatureProvider; + private final Handler mHandler = new Handler(Looper.getMainLooper()); // Preference cache to avoid create new instance each time. @VisibleForTesting @@ -110,6 +114,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll .getTextArray(R.array.allowlist_hide_summary_in_battery_usage); mNotAllowShowEntryPackages = context.getResources() .getTextArray(R.array.allowlist_hide_entry_in_battery_usage); + mMetricsFeatureProvider = + FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(); if (lifecycle != null) { lifecycle.addObserver(this); } @@ -126,6 +132,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll savedInstanceState.getBoolean(KEY_EXPAND_SYSTEM_INFO, mIsExpanded); Log.d(TAG, String.format("onCreate() slotIndex=%d isExpanded=%b", mTrapezoidIndex, mIsExpanded)); + mMetricsFeatureProvider.action(mPrefContext, SettingsEnums.OPEN_BATTERY_USAGE); } @Override @@ -190,15 +197,22 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll final BatteryDiffEntry diffEntry = powerPref.getBatteryDiffEntry(); final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry; final String packageName = histEntry.mPackageName; + final boolean isAppEntry = histEntry.isAppEntry(); // Checks whether the package is installed or not. boolean isValidPackage = true; - if (histEntry.isAppEntry()) { + if (isAppEntry) { if (mBatteryUtils == null) { mBatteryUtils = BatteryUtils.getInstance(mPrefContext); } isValidPackage = mBatteryUtils.getPackageUid(packageName) != BatteryUtils.UID_NULL; } + mMetricsFeatureProvider.action( + mPrefContext, + isAppEntry + ? SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM + : SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM, + packageName); Log.d(TAG, String.format("handleClick() label=%s key=%s isValid:%b\n%s", diffEntry.getAppLabel(), histEntry.getKey(), isValidPackage, histEntry)); if (isValidPackage) { @@ -214,11 +228,20 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll public void onSelect(int trapezoidIndex) { Log.d(TAG, "onChartSelect:" + trapezoidIndex); refreshUi(trapezoidIndex, /*isForce=*/ false); + mMetricsFeatureProvider.action( + mPrefContext, + trapezoidIndex == BatteryChartView.SELECTED_INDEX_ALL + ? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL + : SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT); } @Override public void onExpand(boolean isExpanded) { mIsExpanded = isExpanded; + mMetricsFeatureProvider.action( + mPrefContext, + SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM, + isExpanded); refreshExpandUi(); } @@ -236,16 +259,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll mBatteryHistoryLevels = null; return; } - // Generates battery history timestamp slots. - final List batteryHistoryKeyList = - new ArrayList<>(batteryHistoryMap.keySet()); - Collections.sort(batteryHistoryKeyList); - mBatteryHistoryKeys = new long[CHART_KEY_ARRAY_SIZE]; - for (int index = 0; index < CHART_KEY_ARRAY_SIZE; index++) { - mBatteryHistoryKeys[index] = batteryHistoryKeyList.get(index); - } - - // Generates the battery history levels for chart graph. + mBatteryHistoryKeys = getBatteryHistoryKeys(batteryHistoryMap); mBatteryHistoryLevels = new int[CHART_LEVEL_ARRAY_SIZE]; for (int index = 0; index < CHART_LEVEL_ARRAY_SIZE; index++) { final long timestamp = mBatteryHistoryKeys[index * 2]; @@ -273,7 +287,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll Log.d(TAG, String.format( "setBatteryHistoryMap() size=%d\nkeys=%s\nlevels=%s", - batteryHistoryKeyList.size(), + batteryHistoryMap.size(), utcToLocalTime(mBatteryHistoryKeys), Arrays.toString(mBatteryHistoryLevels))); } @@ -599,4 +613,37 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll } return true; } + + static List getBatteryLast24HrUsageData(Context context) { + final long start = System.currentTimeMillis(); + final Map> batteryHistoryMap = + FeatureFactory.getFactory(context) + .getPowerUsageFeatureProvider(context) + .getBatteryHistory(context); + if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) { + return null; + } + Log.d(TAG, String.format("getBatteryLast24HrData() size=%d time=&d/ms", + batteryHistoryMap.size(), (System.currentTimeMillis() - start))); + final Map> batteryIndexedMap = + ConvertUtils.getIndexedUsageMap( + context, + /*timeSlotSize=*/ CHART_LEVEL_ARRAY_SIZE - 1, + getBatteryHistoryKeys(batteryHistoryMap), + batteryHistoryMap, + /*purgeLowPercentageAndFakeData=*/ true); + return batteryIndexedMap.get(BatteryChartView.SELECTED_INDEX_ALL); + } + + private static long[] getBatteryHistoryKeys( + final Map> batteryHistoryMap) { + final List batteryHistoryKeyList = + new ArrayList<>(batteryHistoryMap.keySet()); + Collections.sort(batteryHistoryKeyList); + final long[] batteryHistoryKeys = new long[CHART_KEY_ARRAY_SIZE]; + for (int index = 0; index < CHART_KEY_ARRAY_SIZE; index++) { + batteryHistoryKeys[index] = batteryHistoryKeyList.get(index); + } + return batteryHistoryKeys; + } } diff --git a/src/com/android/settings/fuelgauge/BatteryChartView.java b/src/com/android/settings/fuelgauge/BatteryChartView.java index 104801704d1..1590a57818d 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartView.java +++ b/src/com/android/settings/fuelgauge/BatteryChartView.java @@ -24,6 +24,7 @@ import android.graphics.CornerPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; +import android.os.Handler; import android.util.AttributeSet; import android.util.Log; import android.view.HapticFeedbackConstants; @@ -44,7 +45,8 @@ import java.util.List; import java.util.Locale; /** A widget component to draw chart graph. */ -public class BatteryChartView extends AppCompatImageView implements View.OnClickListener { +public class BatteryChartView extends AppCompatImageView implements View.OnClickListener, + AccessibilityManager.AccessibilityStateChangeListener { private static final String TAG = "BatteryChartView"; private static final List ACCESSIBILITY_SERVICE_NAMES = Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService"); @@ -52,6 +54,8 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick private static final String[] PERCENTAGES = new String[] {"100%", "50%", "0%"}; private static final int DEFAULT_TRAPEZOID_COUNT = 12; private static final int DEFAULT_TIMESTAMP_COUNT = 4; + private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5"); + private static final long UPDATE_STATE_DELAYED_TIME = 500L; /** Selects all trapezoid shapes. */ public static final int SELECTED_INDEX_ALL = -1; @@ -74,7 +78,6 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick // Colors for drawing the trapezoid shape and dividers. private int mTrapezoidColor; private int mTrapezoidSolidColor; - private final int mDividerColor = Color.parseColor("#CDCCC5"); // For drawing the percentage information. private int mTextPadding; private final Rect mIndent = new Rect(); @@ -85,11 +88,17 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick private final Rect[] mTimestampsBounds = new Rect[] {new Rect(), new Rect(), new Rect(), new Rect()}; + @VisibleForTesting + Handler mHandler = new Handler(); + @VisibleForTesting + final Runnable mUpdateClickableStateRun = () -> updateClickableState(); + private int[] mLevels; private Paint mTextPaint; private Paint mDividerPaint; private Paint mTrapezoidPaint; - private Paint mTrapezoidCurvePaint = null; + @VisibleForTesting + Paint mTrapezoidCurvePaint = null; private TrapezoidSlot[] mTrapezoidSlots; // Records the location to calculate selected index. private MotionEvent mTouchUpEvent; @@ -257,6 +266,26 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick public void onAttachedToWindow() { super.onAttachedToWindow(); updateClickableState(); + mContext.getSystemService(AccessibilityManager.class) + .addAccessibilityStateChangeListener(/*listener=*/ this); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mContext.getSystemService(AccessibilityManager.class) + .removeAccessibilityStateChangeListener(/*listener=*/ this); + mHandler.removeCallbacks(mUpdateClickableStateRun); + } + + @Override + public void onAccessibilityStateChanged(boolean enabled) { + Log.d(TAG, "onAccessibilityStateChanged:" + enabled); + mHandler.removeCallbacks(mUpdateClickableStateRun); + // We should delay it a while since accessibility manager will spend + // some times to bind with new enabled accessibility services. + mHandler.postDelayed( + mUpdateClickableStateRun, UPDATE_STATE_DELAYED_TIME); } private void updateClickableState() { @@ -275,6 +304,10 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick mTrapezoidCurvePaint.setColor(mTrapezoidSolidColor); mTrapezoidCurvePaint.setStyle(Paint.Style.STROKE); mTrapezoidCurvePaint.setStrokeWidth(mDividerWidth * 2); + } else if (mIsSlotsClickabled) { + mTrapezoidCurvePaint = null; + // Sets levels again to force update the click state. + setLevels(mLevels); } invalidate(); } @@ -299,7 +332,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick mDividerHeight = resources.getDimensionPixelSize(R.dimen.chartview_divider_height); mDividerPaint = new Paint(); mDividerPaint.setAntiAlias(true); - mDividerPaint.setColor(mDividerColor); + mDividerPaint.setColor(DIVIDER_COLOR); mDividerPaint.setStyle(Paint.Style.STROKE); mDividerPaint.setStrokeWidth(mDividerWidth); Log.i(TAG, "mDividerWidth:" + mDividerWidth); diff --git a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java index 99eb05d8116..2eb7cf413fc 100644 --- a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java +++ b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java @@ -16,7 +16,9 @@ package com.android.settings.fuelgauge; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -29,6 +31,8 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; +import java.util.HashMap; + public class TopLevelBatteryPreferenceController extends BasePreferenceController implements LifecycleObserver, OnStart, OnStop, BatteryPreferenceController { @@ -37,9 +41,13 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle private final BatteryBroadcastReceiver mBatteryBroadcastReceiver; private Preference mPreference; private BatteryInfo mBatteryInfo; + private BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; private BatteryStatusFeatureProvider mBatteryStatusFeatureProvider; private String mBatteryStatusLabel; + @VisibleForTesting + protected static HashMap sReplacingActivityMap = new HashMap<>(); + public TopLevelBatteryPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext); @@ -53,6 +61,8 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle }, true /* shortString */); }); + mBatterySettingsFeatureProvider = FeatureFactory.getFactory(context) + .getBatterySettingsFeatureProvider(context); mBatteryStatusFeatureProvider = FeatureFactory.getFactory(context) .getBatteryStatusFeatureProvider(context); } @@ -69,6 +79,37 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle mPreference = screen.findPreference(getPreferenceKey()); } + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + String prefFrag = preference.getFragment(); + if (prefFrag == null || prefFrag.isEmpty()) { + // Not a redirect, so use the default. + return super.handlePreferenceTreeClick(preference); + } + + ComponentName currentFragmentName = convertClassPathToComponentName(prefFrag); + if (currentFragmentName == null) { + return super.handlePreferenceTreeClick(preference); + } + + ComponentName replacingActivity; + if (sReplacingActivityMap.containsKey(prefFrag)) { + replacingActivity = sReplacingActivityMap.get(prefFrag); + } else { + replacingActivity = mBatterySettingsFeatureProvider.getReplacingActivity( + currentFragmentName); + sReplacingActivityMap.put(prefFrag, replacingActivity); + } + + if (replacingActivity == null || currentFragmentName.compareTo(replacingActivity) == 0) { + return super.handlePreferenceTreeClick(preference); + } + Intent intent = new Intent(); + intent.setComponent(currentFragmentName); + mContext.startActivity(intent); + return true; + } + @Override public void onStart() { mBatteryBroadcastReceiver.register(); @@ -133,4 +174,19 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle } } } + + @VisibleForTesting + protected static ComponentName convertClassPathToComponentName(String classPath) { + if (classPath == null || classPath.isEmpty()) { + return null; + } + String[] split = classPath.split("\\."); + int classNameIndex = split.length - 1; + if (classNameIndex < 0) { + return null; + } + int lastPkgIndex = classPath.length() - split[classNameIndex].length() - 1; + String pkgName = lastPkgIndex > 0 ? classPath.substring(0, lastPkgIndex) : ""; + return new ComponentName(pkgName, split[classNameIndex]); + } } diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index c59b805c437..5950e4b8ba1 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -96,12 +96,7 @@ public class SettingsHomepageActivity extends FragmentActivity { getLifecycle().addObserver(new AvatarViewMixin(this, avatarView)); } - if (FeatureFlagUtils.isEnabled(this, FeatureFlags.SILKY_HOME)) { - showSuggestionFragment(); - } else { - findViewById(R.id.homepage_title).setVisibility(View.GONE); - avatarView.setVisibility(View.GONE); - } + showSuggestionFragment(); if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) { showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content); diff --git a/src/com/android/settings/homepage/TopLevelSettings.java b/src/com/android/settings/homepage/TopLevelSettings.java index f4f7f61cd1d..681ea5111c7 100644 --- a/src/com/android/settings/homepage/TopLevelSettings.java +++ b/src/com/android/settings/homepage/TopLevelSettings.java @@ -23,8 +23,6 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.provider.SearchIndexableResource; -import android.util.FeatureFlagUtils; import androidx.fragment.app.Fragment; import androidx.preference.Preference; @@ -33,7 +31,6 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.core.FeatureFlags; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; @@ -41,9 +38,6 @@ import com.android.settings.support.SupportPreferenceController; import com.android.settingslib.core.instrumentation.Instrumentable; import com.android.settingslib.search.SearchIndexable; -import java.util.Arrays; -import java.util.List; - @SearchIndexable(forTarget = MOBILE) public class TopLevelSettings extends DashboardFragment implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { @@ -59,9 +53,6 @@ public class TopLevelSettings extends DashboardFragment implements @Override protected int getPreferenceScreenResId() { - if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.SILKY_HOME)) { - return R.xml.top_level_settings_grouped; - } return R.xml.top_level_settings; } @@ -108,9 +99,6 @@ public class TopLevelSettings extends DashboardFragment implements @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { super.onCreatePreferences(savedInstanceState, rootKey); - if (!FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.SILKY_HOME)) { - return; - } final PreferenceScreen screen = getPreferenceScreen(); if (screen == null) { return; @@ -137,16 +125,7 @@ public class TopLevelSettings extends DashboardFragment implements } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - - @Override - public List getXmlResourcesToIndex( - Context context, boolean enabled) { - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME) - ? R.xml.top_level_settings_grouped : R.xml.top_level_settings; - return Arrays.asList(sir); - } + new BaseSearchIndexProvider(R.xml.top_level_settings) { @Override protected boolean isPageSearchEnabled(Context context) { diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index bbe36d13b6e..2c806688d1c 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -306,12 +306,6 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { super.onDestroy(); } - @Override - public boolean onNavigateUp() { - finish(); - return true; - } - private @ColorInt int obtainThemeColor(@AttrRes int attrRes) { Resources.Theme theme = new ContextThemeWrapper(this, android.R.style.Theme_DeviceDefault_DayNight).getTheme(); diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index 01cdba7b3ca..8a03a04f34d 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -31,6 +31,7 @@ import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceCo import com.android.settings.dashboard.DashboardFragment; import com.android.settings.enterprise.EnterprisePrivacyPreferenceController; import com.android.settings.enterprise.FinancedPrivacyPreferenceController; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController; import com.android.settings.security.trustagent.TrustAgentListPreferenceController; @@ -152,5 +153,11 @@ public class SecuritySettings extends DashboardFragment { return buildPreferenceControllers(context, null /* lifecycle */, null /* host*/); } + + @Override + protected boolean isPageSearchEnabled(Context context) { + return !FeatureFactory.getFactory(context).getSecuritySettingsFeatureProvider() + .hasAlternativeSecuritySettingsFragment(); + } }; } diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml index af02d4523dc..b1d4be9ea1c 100644 --- a/tests/robotests/res/values-mcc999/config.xml +++ b/tests/robotests/res/values-mcc999/config.xml @@ -100,14 +100,4 @@ content://com.android.settings.slices/test - - - - com.android.settings - - - - - 100 - diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java index 4b6a6a8d702..b22b1562be2 100644 --- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java @@ -39,7 +39,6 @@ import android.os.UserManager; import android.text.TextUtils; import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; @@ -73,13 +72,9 @@ import java.util.List; ShadowSettingsLibUtils.class}) public class AccountPreferenceControllerTest { - private static final String PREF_KEY_ACCOUNTS = "accounts_category"; - @Mock(answer = RETURNS_DEEP_STUBS) private PreferenceScreen mScreen; @Mock(answer = RETURNS_DEEP_STUBS) - private PreferenceCategory mAccountsCategory; - @Mock(answer = RETURNS_DEEP_STUBS) private UserManager mUserManager; @Mock(answer = RETURNS_DEEP_STUBS) private SettingsPreferenceFragment mFragment; @@ -100,9 +95,6 @@ public class AccountPreferenceControllerTest { shadowApp.setSystemService(Context.ACCOUNT_SERVICE, mAccountManager); when(mFragment.getPreferenceScreen()).thenReturn(mScreen); - // This is a bit ugly, but hard to avoid because of how the mocks are used in these tests. - // TODO: Refactor these tests to not use RETURNS_DEEP_STUBS. - when(mScreen.findPreference(PREF_KEY_ACCOUNTS)).thenReturn(mScreen); when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext); when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())) .thenReturn(new AuthenticatorDescription[0]); @@ -174,7 +166,6 @@ public class AccountPreferenceControllerTest { // First time resume will build the UI mController.onResume(); reset(mScreen); - when(mScreen.findPreference(PREF_KEY_ACCOUNTS)).thenReturn(mScreen); mController.onResume(); verify(mScreen, never()).addPreference(any(PreferenceGroup.class)); @@ -193,7 +184,6 @@ public class AccountPreferenceControllerTest { // add a new profile infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE)); reset(mScreen); - when(mScreen.findPreference(PREF_KEY_ACCOUNTS)).thenReturn(mScreen); mController.onResume(); verify(mScreen, times(1)).addPreference(any(PreferenceGroup.class)); diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingServiceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingServiceTest.java new file mode 100644 index 00000000000..e73b447728e --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingServiceTest.java @@ -0,0 +1,125 @@ +/* + * 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.bluetooth; + +import static com.android.settings.bluetooth.BluetoothPairingService.ACTION_DISMISS_PAIRING; +import static com.android.settings.bluetooth.BluetoothPairingService.ACTION_PAIRING_DIALOG; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Application; +import android.app.NotificationManager; +import android.bluetooth.BluetoothDevice; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.util.DisplayMetrics; + +import com.android.settings.R; + +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; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothPairingServiceTest { + + private final String mFakeTicker = "fake_ticker"; + + @Mock + private NotificationManager mNm; + @Mock + private BluetoothDevice mDevice; + @Mock + private Context mContext; + @Mock + private Resources mResources; + @Mock + private PackageManager mPackageManager; + @Mock + private DisplayMetrics mDisplayMetrics; + + private BluetoothPairingService mBluetoothPairingService; + private Application mApplication; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mBluetoothPairingService = new BluetoothPairingService(); + mBluetoothPairingService.mNm = mNm; + mApplication = RuntimeEnvironment.application; + + ReflectionHelpers.setField(mBluetoothPairingService, "mBase", mContext); + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getString(R.string.bluetooth_notif_ticker)).thenReturn(mFakeTicker); + when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo()); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics); + mDisplayMetrics.density = 1.5f; + } + + @Test + public void receivePairingRequestAction_notificationShown() { + Intent intent = new Intent(); + intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); + intent.putExtra(BluetoothDevice.EXTRA_NAME, "fake_name"); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING); + + mBluetoothPairingService.onStartCommand(intent, /* flags */ 0, /* startId */ 0); + + verify(mNm).notify(eq(mBluetoothPairingService.NOTIFICATION_ID), any()); + } + + @Test + public void receiveDismissPairingAction_cancelPairing() { + Intent intent = new Intent(); + intent.setAction(ACTION_DISMISS_PAIRING); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); + intent.putExtra(BluetoothDevice.EXTRA_NAME, "fake_name"); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING); + + mBluetoothPairingService.onStartCommand(intent, /* flags */ 0, /* startId */ 0); + + verify(mDevice).cancelPairing(); + verify(mNm).cancel(mBluetoothPairingService.NOTIFICATION_ID); + } + + @Test + public void receivePairingDialogAction_startActivity() { + Intent intent = new Intent(); + intent.setAction(ACTION_PAIRING_DIALOG); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); + intent.putExtra(BluetoothDevice.EXTRA_NAME, "fake_name"); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING); + + mBluetoothPairingService.onStartCommand(intent, /* flags */ 0, /* startId */ 0); + + verify(mContext).startActivity(any()); + } +} diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java index c4f15874503..ea6947e2dee 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java @@ -53,6 +53,7 @@ public class ConnectedDeviceDashboardFragmentTest { private static final String KEY_NEARBY_DEVICES = "bt_nearby_slice"; private static final String KEY_DISCOVERABLE_FOOTER = "discoverable_footer"; private static final String KEY_SEE_ALL = "previously_connected_devices_see_all"; + private static final String KEY_ADD_BT_DEVICES = "add_bt_devices"; @Mock private PackageManager mPackageManager; @@ -83,7 +84,7 @@ public class ConnectedDeviceDashboardFragmentTest { .getNonIndexableKeys(mContext); assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_AVAILABLE_DEVICES, - KEY_NEARBY_DEVICES, KEY_DISCOVERABLE_FOOTER, KEY_SEE_ALL); + KEY_NEARBY_DEVICES, KEY_DISCOVERABLE_FOOTER, KEY_SEE_ALL, KEY_ADD_BT_DEVICES); } @Test diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java index 1fba12ba979..b2d11dc8cd0 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java @@ -672,18 +672,4 @@ public class DashboardFeatureProviderImplTest { assertThat(argument.getValue().getIdentifier()).isEqualTo(0); verify(mActivity, never()).getSupportFragmentManager(); } - - @Test - @Config(qualifiers = "mcc999") - public void bindPreference_specificHomepageTile_shouldOverridePosition() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - final Preference preference = new Preference(RuntimeEnvironment.application); - final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - - mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, - MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */, - Preference.DEFAULT_ORDER); - - assertThat(preference.getOrder()).isEqualTo(100); - } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java index 3c371a068c8..43714727b9a 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.settings.SettingsEnums; import android.content.Context; import android.content.ContentValues; import android.content.pm.PackageManager; @@ -43,6 +44,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; @@ -82,12 +84,16 @@ public final class BatteryChartPreferenceControllerTest { @Mock private Resources mResources; private Context mContext; + private FakeFeatureFactory mFeatureFactory; private BatteryDiffEntry mBatteryDiffEntry; + private MetricsFeatureProvider mMetricsFeatureProvider; private BatteryChartPreferenceController mBatteryChartPreferenceController; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider; mContext = spy(RuntimeEnvironment.application); mBatteryChartPreferenceController = createController(); mBatteryChartPreferenceController.mPrefContext = mContext; @@ -331,9 +337,14 @@ public final class BatteryChartPreferenceControllerTest { } @Test - public void testHandlePreferenceTreeClick_notPowerGaugePreference_returnFalse() { + public void testHandlePreferenceTreeiClick_notPowerGaugePreference_returnFalse() { assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(mAppListGroup)) .isFalse(); + + verify(mMetricsFeatureProvider, never()) + .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM); + verify(mMetricsFeatureProvider, never()) + .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM); } @Test @@ -343,6 +354,11 @@ public final class BatteryChartPreferenceControllerTest { assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick( mPowerGaugePreference)).isTrue(); + verify(mMetricsFeatureProvider) + .action( + mContext, + SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM, + mBatteryHistEntry.mPackageName); } @Test @@ -355,6 +371,11 @@ public final class BatteryChartPreferenceControllerTest { assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick( mPowerGaugePreference)).isFalse(); + verify(mMetricsFeatureProvider) + .action( + mContext, + SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM, + mBatteryHistEntry.mPackageName); } @Test @@ -474,6 +495,11 @@ public final class BatteryChartPreferenceControllerTest { verify(mAppListGroup).addPreference(captor.capture()); // Verifies the added preference. assertThat(captor.getValue().getKey()).isEqualTo(PREF_KEY); + verify(mMetricsFeatureProvider) + .action( + mContext, + SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM, + true /*isExpanded*/); } @Test @@ -489,6 +515,28 @@ public final class BatteryChartPreferenceControllerTest { verify(mAppListGroup).findPreference(PREF_KEY); verify(mAppListGroup).removePreference(mPowerGaugePreference); assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1); + verify(mMetricsFeatureProvider) + .action( + mContext, + SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM, + false /*isExpanded*/); + } + + @Test + public void testOnSelect_selectSpecificTimeSlot_logMetric() { + mBatteryChartPreferenceController.onSelect(1 /*slot index*/); + + verify(mMetricsFeatureProvider) + .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT); + } + + @Test + public void testOnSelect_selectAll_logMetric() { + mBatteryChartPreferenceController.onSelect( + BatteryChartView.SELECTED_INDEX_ALL /*slot index*/); + + verify(mMetricsFeatureProvider) + .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL); } @Test @@ -610,6 +658,8 @@ public final class BatteryChartPreferenceControllerTest { assertThat(mBatteryChartPreferenceController.mTrapezoidIndex) .isEqualTo(expectedIndex); assertThat(mBatteryChartPreferenceController.mIsExpanded).isTrue(); + verify(mMetricsFeatureProvider) + .action(mContext, SettingsEnums.OPEN_BATTERY_USAGE); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java index 877ebc28734..3998a332630 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartViewTest.java @@ -130,6 +130,7 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isFalse(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull(); } @Test @@ -141,6 +142,7 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isTrue(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull(); } @Test @@ -155,6 +157,7 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isTrue(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull(); } @Test @@ -166,5 +169,62 @@ public final class BatteryChartViewTest { mBatteryChartView.onAttachedToWindow(); assertThat(mBatteryChartView.isClickable()).isFalse(); + assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull(); + } + + @Test + public void testClickable_restoreFromNonClickableState() { + final int[] levels = new int[13]; + for (int index = 0; index < levels.length; index++) { + levels[index] = index + 1; + } + mBatteryChartView.setTrapezoidCount(12); + mBatteryChartView.setLevels(levels); + mBatteryChartView.setClickableForce(true); + when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext)) + .thenReturn(true); + doReturn(true).when(mockAccessibilityManager).isEnabled(); + mBatteryChartView.onAttachedToWindow(); + // Ensures the testing environment is correct. + assertThat(mBatteryChartView.isClickable()).isFalse(); + // Turns off accessibility service. + doReturn(false).when(mockAccessibilityManager).isEnabled(); + + mBatteryChartView.onAttachedToWindow(); + + assertThat(mBatteryChartView.isClickable()).isTrue(); + } + + @Test + public void testOnAttachedToWindow_addAccessibilityStateChangeListener() { + mBatteryChartView.onAttachedToWindow(); + verify(mockAccessibilityManager) + .addAccessibilityStateChangeListener(mBatteryChartView); + } + + @Test + public void testOnDetachedFromWindow_removeAccessibilityStateChangeListener() { + mBatteryChartView.onAttachedToWindow(); + mBatteryChartView.mHandler.postDelayed( + mBatteryChartView.mUpdateClickableStateRun, 1000); + + mBatteryChartView.onDetachedFromWindow(); + + verify(mockAccessibilityManager) + .removeAccessibilityStateChangeListener(mBatteryChartView); + assertThat(mBatteryChartView.mHandler.hasCallbacks( + mBatteryChartView.mUpdateClickableStateRun)) + .isFalse(); + } + + @Test + public void testOnAccessibilityStateChanged_postUpdateStateRunnable() { + mBatteryChartView.mHandler = spy(mBatteryChartView.mHandler); + mBatteryChartView.onAccessibilityStateChanged(/*enabled=*/ true); + + verify(mBatteryChartView.mHandler) + .removeCallbacks(mBatteryChartView.mUpdateClickableStateRun); + verify(mBatteryChartView.mHandler) + .postDelayed(mBatteryChartView.mUpdateClickableStateRun, 500L); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java index 216b118a029..63a0b3d71d1 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java @@ -26,6 +26,8 @@ import android.os.BatteryManager; import android.os.BatteryUsageStats; import android.os.UserHandle; +import com.android.settings.testutils.FakeFeatureFactory; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,15 +47,18 @@ import java.util.TimeZone; public final class ConvertUtilsTest { private Context mContext; - @Mock - private BatteryUsageStats mBatteryUsageStats; - @Mock - private BatteryEntry mockBatteryEntry; + @Mock private BatteryUsageStats mBatteryUsageStats; + @Mock private BatteryEntry mockBatteryEntry; + + private FakeFeatureFactory mFeatureFactory; + private PowerUsageFeatureProvider mPowerUsageFeatureProvider; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider; } @Test @@ -250,6 +255,21 @@ public final class ConvertUtilsTest { // Verifies the fake data is cleared out. assertThat(entryList.get(0).getPackageName()) .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME); + + // Adds lacked data into the battery history map. + final int remainingSize = 25 - batteryHistoryKeys.length; + for (int index = 0; index < remainingSize; index++) { + batteryHistoryMap.put(105L + index + 1, new HashMap<>()); + } + when(mPowerUsageFeatureProvider.getBatteryHistory(mContext)) + .thenReturn(batteryHistoryMap); + + final List batteryDiffEntryList = + BatteryChartPreferenceController.getBatteryLast24HrUsageData(mContext); + + assertThat(batteryDiffEntryList).isNotEmpty(); + final BatteryDiffEntry resultEntry = batteryDiffEntryList.get(0); + assertThat(resultEntry.getPackageName()).isEqualTo("package2"); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java index 1a3c98f8ba1..af4ab0f9198 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java @@ -21,26 +21,55 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_ import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.content.ComponentName; import android.content.Context; +import android.util.FeatureFlagUtils; + +import androidx.preference.Preference; import com.android.settings.R; +import com.android.settings.core.FeatureFlags; +import com.android.settings.testutils.FakeFeatureFactory; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) public class TopLevelBatteryPreferenceControllerTest { private Context mContext; + private FakeFeatureFactory mFeatureFactory; private TopLevelBatteryPreferenceController mController; + private BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; @Before public void setUp() { - mContext = RuntimeEnvironment.application; + MockitoAnnotations.initMocks(this); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + mContext = spy(Robolectric.setupActivity(Activity.class)); mController = new TopLevelBatteryPreferenceController(mContext, "test_key"); + mBatterySettingsFeatureProvider = + mFeatureFactory.batterySettingsFeatureProvider; + FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); + } + + @After + public void cleanUp() { + TopLevelBatteryPreferenceController.sReplacingActivityMap.clear(); } @Test @@ -54,6 +83,80 @@ public class TopLevelBatteryPreferenceControllerTest { assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } + @Test + public void handlePreferenceTreeClick_noFragment_noCustomActivityCalled() { + Preference preference = new Preference(mContext); + + assertThat(mController.handlePreferenceTreeClick(preference)).isFalse(); + } + + @Test + public void handlePreferenceTreeClick_sameActivityReturned_noCustomActivityCalled() { + String fragmentPath = "my.fragment.ClassName"; + Preference preference = mock(Preference.class); + when(preference.getFragment()).thenReturn(fragmentPath); + ComponentName pathName = mController.convertClassPathToComponentName(fragmentPath); + when(mBatterySettingsFeatureProvider.getReplacingActivity(any())).thenReturn(pathName); + + assertThat(mController.handlePreferenceTreeClick(preference)).isFalse(); + } + + @Test + public void handlePreferenceTreeClick_newActivityReturned_newActivityRedirected() { + String fragmentPath = "my.fragment.ClassName"; + Preference preference = mock(Preference.class); + when(preference.getFragment()).thenReturn(fragmentPath); + String newFragmentPath = "my.fragment.NewClassName"; + ComponentName newPathName = mController.convertClassPathToComponentName(newFragmentPath); + when(mBatterySettingsFeatureProvider.getReplacingActivity(any())).thenReturn( + newPathName); + doNothing().when(mContext).startActivity(any()); + + assertThat(mController.handlePreferenceTreeClick(preference)).isTrue(); + } + + @Test + public void handlePreferenceTreeClick_calledMultipleTimes_fetchedFromCache() { + String fragmentPath = "my.fragment.ClassName"; + Preference preference = mock(Preference.class); + when(preference.getFragment()).thenReturn(fragmentPath); + String newFragmentPath = "my.fragment.NewClassName"; + ComponentName newPathName = mController.convertClassPathToComponentName(newFragmentPath); + when(mBatterySettingsFeatureProvider.getReplacingActivity(any())).thenReturn( + newPathName); + doNothing().when(mContext).startActivity(any()); + + assertThat(mController.handlePreferenceTreeClick(preference)).isTrue(); + assertThat(mController.handlePreferenceTreeClick(preference)).isTrue(); + verify(mBatterySettingsFeatureProvider, times(1)).getReplacingActivity(any()); + } + + @Test + public void convertClassPathToComponentName_nullInput_returnsNull() { + assertThat(mController.convertClassPathToComponentName(null)).isNull(); + } + + @Test + public void convertClassPathToComponentName_emptyStringInput_returnsNull() { + assertThat(mController.convertClassPathToComponentName("")).isNull(); + } + + @Test + public void convertClassPathToComponentName_singleClassName_returnsCorrectComponentName() { + ComponentName output = mController.convertClassPathToComponentName("ClassName"); + + assertThat(output.getPackageName()).isEqualTo(""); + assertThat(output.getClassName()).isEqualTo("ClassName"); + } + + @Test + public void convertClassPathToComponentName_validAddress_returnsCorrectComponentName() { + ComponentName output = mController.convertClassPathToComponentName("my.fragment.ClassName"); + + assertThat(output.getPackageName()).isEqualTo("my.fragment"); + assertThat(output.getClassName()).isEqualTo("ClassName"); + } + @Test public void getDashboardLabel_returnsCorrectLabel() { BatteryInfo info = new BatteryInfo(); diff --git a/tests/robotests/src/com/android/settings/homepage/TopLevelSettingsTest.java b/tests/robotests/src/com/android/settings/homepage/TopLevelSettingsTest.java index 663d7f72a1a..da2f8b5e566 100644 --- a/tests/robotests/src/com/android/settings/homepage/TopLevelSettingsTest.java +++ b/tests/robotests/src/com/android/settings/homepage/TopLevelSettingsTest.java @@ -28,13 +28,11 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.util.FeatureFlagUtils; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; @@ -65,19 +63,6 @@ public class TopLevelSettingsTest { assertThat(mSettings.shouldForceRoundedIcon()).isTrue(); } - @Test - public void getPreferenceScreenResId_silkyHomeDisabled_defaultSettings() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); - assertThat(mSettings.getPreferenceScreenResId()).isEqualTo(R.xml.top_level_settings); - } - - @Test - public void getPreferenceScreenResId_silkyHomeEnabled_groupedSettings() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - assertThat(mSettings.getPreferenceScreenResId()).isEqualTo( - R.xml.top_level_settings_grouped); - } - @Test public void onCreatePreferences_shouldTintPreferenceIcon() { final Preference preference = new Preference(mContext); diff --git a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java index 70ae26b579b..7354d85bc7a 100644 --- a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java +++ b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java @@ -1048,8 +1048,7 @@ public class WifiDetailPreferenceController2Test { } private NetworkCapabilities makeNetworkCapabilities() { - final NetworkCapabilities nc = new NetworkCapabilities.Builder() - .clearAll() + final NetworkCapabilities nc = NetworkCapabilities.Builder.withoutDefaultCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); return nc; diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java index dc520ab9c3f..32bf5090ddf 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java @@ -144,8 +144,7 @@ public class ContextualWifiSliceTest { } private NetworkCapabilities makeValidatedNetworkCapabilities() { - final NetworkCapabilities nc = new NetworkCapabilities.Builder() - .clearAll() + final NetworkCapabilities nc = NetworkCapabilities.Builder.withoutDefaultCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) .build(); diff --git a/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java new file mode 100644 index 00000000000..c50d99312ae --- /dev/null +++ b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java @@ -0,0 +1,119 @@ +/* + * 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.security; + +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_INCLUDE_PREF_SCREEN; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.annotation.XmlRes; +import android.content.Context; +import android.os.Bundle; +import android.provider.SearchIndexableResource; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settings.core.PreferenceXmlParserUtils; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.security.trustagent.TrustAgentManager; +import com.android.settings.testutils.FakeFeatureFactory; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + + +@RunWith(AndroidJUnit4.class) +public class SecuritySettingsTest { + + private Context mContext; + private SecuritySettingsFeatureProvider mSecuritySettingsFeatureProvider; + + @Mock + private TrustAgentManager mTrustAgentManager; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = ApplicationProvider.getApplicationContext(); + FakeFeatureFactory mFeatureFactory = FakeFeatureFactory.setupForTest(); + mSecuritySettingsFeatureProvider = mFeatureFactory.getSecuritySettingsFeatureProvider(); + SecurityFeatureProvider mSecurityFeatureProvider = + mFeatureFactory.getSecurityFeatureProvider(); + + when(mSecurityFeatureProvider.getTrustAgentManager()).thenReturn(mTrustAgentManager); + } + + @Test + public void noAlternativeFragmentAvailable_pageIndexIncluded() throws Exception { + when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()) + .thenReturn(false); + BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER; + + List allXmlKeys = getAllXmlKeys(indexProvider); + List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); + allXmlKeys.removeAll(nonIndexableKeys); + + assertThat(allXmlKeys).isNotEmpty(); + } + + @Test + public void alternativeFragmentAvailable_pageIndexExcluded() throws Exception { + when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()) + .thenReturn(true); + BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER; + + List allXmlKeys = getAllXmlKeys(indexProvider); + List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); + allXmlKeys.removeAll(nonIndexableKeys); + + assertThat(allXmlKeys).isEmpty(); + } + + private List getAllXmlKeys(BaseSearchIndexProvider indexProvider) throws Exception { + final List resources = indexProvider.getXmlResourcesToIndex( + mContext, true /* not used*/); + if (resources == null || resources.isEmpty()) { + return new ArrayList<>(); + } + final List keys = new ArrayList<>(); + for (SearchIndexableResource res : resources) { + keys.addAll(getKeysFromXml(res.xmlResId)); + } + return keys; + } + + private List getKeysFromXml(@XmlRes int xmlResId) throws Exception { + final List keys = new ArrayList<>(); + final List metadata = PreferenceXmlParserUtils + .extractMetadata(mContext, xmlResId, FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN); + for (Bundle bundle : metadata) { + keys.add(bundle.getString(METADATA_KEY)); + } + return keys; + } +}