diff options
| -rw-r--r-- | packages/SettingsLib/src/com/android/settingslib/Utils.java | 309 | ||||
| -rw-r--r-- | packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java | 295 |
2 files changed, 414 insertions, 190 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index fb14a172d76c..58e0a89d5387 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -41,6 +41,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.print.PrintManager; import android.provider.Settings; +import android.provider.Settings.Secure; import android.telephony.AccessNetworkConstants; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; @@ -66,18 +67,29 @@ import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.settingslib.utils.BuildCompatUtils; import java.text.NumberFormat; +import java.time.Duration; import java.util.List; public class Utils { private static final String TAG = "Utils"; - @VisibleForTesting - static final String STORAGE_MANAGER_ENABLED_PROPERTY = - "ro.storage_manager.enabled"; - public static final String INCOMPATIBLE_CHARGER_WARNING_DISABLED = "incompatible_charger_warning_disabled"; + public static final String WIRELESS_CHARGING_NOTIFICATION_TIMESTAMP = + "wireless_charging_notification_timestamp"; + + @VisibleForTesting + static final String STORAGE_MANAGER_ENABLED_PROPERTY = "ro.storage_manager.enabled"; + + @VisibleForTesting static final long WIRELESS_CHARGING_DEFAULT_TIMESTAMP = -1L; + + @VisibleForTesting + static final long WIRELESS_CHARGING_NOTIFICATION_THRESHOLD_MILLIS = + Duration.ofDays(30).toMillis(); + + @VisibleForTesting + static final String WIRELESS_CHARGING_WARNING_ENABLED = "wireless_charging_warning_enabled"; private static Signature[] sSystemSignature; private static String sPermissionControllerPackageName; @@ -101,19 +113,19 @@ public class Utils { R.drawable.ic_show_x_wifi_signal_4 }; - public static void updateLocationEnabled(Context context, boolean enabled, int userId, - int source) { + /** Update the location enable state. */ + public static void updateLocationEnabled( + @NonNull Context context, boolean enabled, int userId, int source) { Settings.Secure.putIntForUser( - context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source, - userId); + context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source, userId); LocationManager locationManager = context.getSystemService(LocationManager.class); locationManager.setLocationEnabledForUser(enabled, UserHandle.of(userId)); } /** - * Return string resource that best describes combination of tethering - * options available on this device. + * Return string resource that best describes combination of tethering options available on this + * device. */ public static int getTetheringLabel(TetheringManager tm) { String[] usbRegexs = tm.getTetherableUsbRegexs(); @@ -141,14 +153,12 @@ public class Utils { } } - /** - * Returns a label for the user, in the form of "User: user name" or "Work profile". - */ + /** Returns a label for the user, in the form of "User: user name" or "Work profile". */ public static String getUserLabel(Context context, UserInfo info) { String name = info != null ? info.name : null; if (info.isManagedProfile()) { // We use predefined values for managed profiles - return BuildCompatUtils.isAtLeastT() + return BuildCompatUtils.isAtLeastT() ? getUpdatableManagedUserTitle(context) : context.getString(R.string.managed_user_title); } else if (info.isGuest()) { @@ -164,14 +174,14 @@ public class Utils { @RequiresApi(Build.VERSION_CODES.TIRAMISU) private static String getUpdatableManagedUserTitle(Context context) { - return context.getSystemService(DevicePolicyManager.class).getResources().getString( - WORK_PROFILE_USER_LABEL, - () -> context.getString(R.string.managed_user_title)); + return context.getSystemService(DevicePolicyManager.class) + .getResources() + .getString( + WORK_PROFILE_USER_LABEL, + () -> context.getString(R.string.managed_user_title)); } - /** - * Returns a circular icon for a user. - */ + /** Returns a circular icon for a user. */ public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) { final int iconSize = UserIconDrawable.getDefaultSize(context); if (user.isManagedProfile()) { @@ -185,12 +195,14 @@ public class Utils { return new UserIconDrawable(iconSize).setIcon(icon).bake(); } } - return new UserIconDrawable(iconSize).setIconDrawable( - UserIcons.getDefaultUserIcon(context.getResources(), user.id, /* light= */ false)) + return new UserIconDrawable(iconSize) + .setIconDrawable( + UserIcons.getDefaultUserIcon( + context.getResources(), user.id, /* light= */ false)) .bake(); } - /** Formats a double from 0.0..100.0 with an option to round **/ + /** Formats a double from 0.0..100.0 with an option to round */ public static String formatPercentage(double percentage, boolean round) { final int localPercentage = round ? Math.round((float) percentage) : (int) percentage; return formatPercentage(localPercentage); @@ -222,23 +234,27 @@ public class Utils { * * @param context the context * @param batteryChangedIntent battery broadcast intent received from {@link - * Intent.ACTION_BATTERY_CHANGED}. + * Intent.ACTION_BATTERY_CHANGED}. * @param compactStatus to present compact battery charging string if {@code true} * @return battery status string */ - public static String getBatteryStatus(Context context, Intent batteryChangedIntent, - boolean compactStatus) { - final int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS, - BatteryManager.BATTERY_STATUS_UNKNOWN); + @NonNull + public static String getBatteryStatus( + @NonNull Context context, @NonNull Intent batteryChangedIntent, boolean compactStatus) { + final int status = + batteryChangedIntent.getIntExtra( + BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN); final Resources res = context.getResources(); String statusString = res.getString(R.string.battery_info_status_unknown); final BatteryStatus batteryStatus = new BatteryStatus(batteryChangedIntent); if (batteryStatus.isCharged()) { - statusString = res.getString(compactStatus - ? R.string.battery_info_status_full_charged - : R.string.battery_info_status_full); + statusString = + res.getString( + compactStatus + ? R.string.battery_info_status_full_charged + : R.string.battery_info_status_full); } else { if (status == BatteryManager.BATTERY_STATUS_CHARGING) { if (compactStatus) { @@ -246,12 +262,12 @@ public class Utils { } else if (batteryStatus.isPluggedInWired()) { switch (batteryStatus.getChargingSpeed(context)) { case BatteryStatus.CHARGING_FAST: - statusString = res.getString( - R.string.battery_info_status_charging_fast); + statusString = + res.getString(R.string.battery_info_status_charging_fast); break; case BatteryStatus.CHARGING_SLOWLY: - statusString = res.getString( - R.string.battery_info_status_charging_slow); + statusString = + res.getString(R.string.battery_info_status_charging_slow); break; default: statusString = res.getString(R.string.battery_info_status_charging); @@ -311,7 +327,7 @@ public class Utils { @ColorInt public static int applyAlphaAttr(Context context, int attr, int inputColor) { - TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); + TypedArray ta = context.obtainStyledAttributes(new int[] {attr}); float alpha = ta.getFloat(0, 0); ta.recycle(); return applyAlpha(alpha, inputColor); @@ -320,7 +336,10 @@ public class Utils { @ColorInt public static int applyAlpha(float alpha, int inputColor) { alpha *= Color.alpha(inputColor); - return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor), + return Color.argb( + (int) (alpha), + Color.red(inputColor), + Color.green(inputColor), Color.blue(inputColor)); } @@ -329,19 +348,17 @@ public class Utils { return getColorAttrDefaultColor(context, attr, 0); } - /** - * Get color styled attribute {@code attr}, default to {@code defValue} if not found. - */ + /** Get color styled attribute {@code attr}, default to {@code defValue} if not found. */ @ColorInt public static int getColorAttrDefaultColor(Context context, int attr, @ColorInt int defValue) { - TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); + TypedArray ta = context.obtainStyledAttributes(new int[] {attr}); @ColorInt int colorAccent = ta.getColor(0, defValue); ta.recycle(); return colorAccent; } public static ColorStateList getColorAttr(Context context, int attr) { - TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); + TypedArray ta = context.obtainStyledAttributes(new int[] {attr}); ColorStateList stateList = null; try { stateList = ta.getColorStateList(0); @@ -356,35 +373,38 @@ public class Utils { } public static int getThemeAttr(Context context, int attr, int defaultValue) { - TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); + TypedArray ta = context.obtainStyledAttributes(new int[] {attr}); int theme = ta.getResourceId(0, defaultValue); ta.recycle(); return theme; } public static Drawable getDrawable(Context context, int attr) { - TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); + TypedArray ta = context.obtainStyledAttributes(new int[] {attr}); Drawable drawable = ta.getDrawable(0); ta.recycle(); return drawable; } /** - * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but - * preserves the alpha for a given drawable - * @param color - * @return a color matrix that uses the source alpha and given color - */ + * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but + * preserves the alpha for a given drawable + * + * @return a color matrix that uses the source alpha and given color + */ public static ColorMatrix getAlphaInvariantColorMatrixForColor(@ColorInt int color) { int r = Color.red(color); int g = Color.green(color); int b = Color.blue(color); - ColorMatrix cm = new ColorMatrix(new float[] { - 0, 0, 0, 0, r, - 0, 0, 0, 0, g, - 0, 0, 0, 0, b, - 0, 0, 0, 1, 0 }); + ColorMatrix cm = + new ColorMatrix( + new float[] { + 0, 0, 0, 0, r, + 0, 0, 0, 0, g, + 0, 0, 0, 0, b, + 0, 0, 0, 1, 0 + }); return cm; } @@ -393,7 +413,7 @@ public class Utils { * Create a ColorMatrixColorFilter to tint a drawable but retain its alpha characteristics * * @return a ColorMatrixColorFilter which changes the color of the output but is invariant on - * the source alpha + * the source alpha */ public static ColorFilter getAlphaInvariantColorFilterForColor(@ColorInt int color) { return new ColorMatrixColorFilter(getAlphaInvariantColorMatrixForColor(color)); @@ -402,16 +422,17 @@ public class Utils { /** * Determine whether a package is a "system package", in which case certain things (like * disabling notifications or disabling the package altogether) should be disallowed. - * <p> - * Note: This function is just for UI treatment, and should not be used for security purposes. * - * @deprecated Use {@link ApplicationInfo#isSignedWithPlatformKey()} and - * {@link #isEssentialPackage} instead. + * <p>Note: This function is just for UI treatment, and should not be used for security + * purposes. + * + * @deprecated Use {@link ApplicationInfo#isSignedWithPlatformKey()} and {@link + * #isEssentialPackage} instead. */ @Deprecated public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) { if (sSystemSignature == null) { - sSystemSignature = new Signature[]{getSystemSignature(pm)}; + sSystemSignature = new Signature[] {getSystemSignature(pm)}; } return (sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg))) || isEssentialPackage(resources, pm, pkg.packageName); @@ -435,8 +456,8 @@ public class Utils { /** * Determine whether a package is a "essential package". - * <p> - * In which case certain things (like disabling the package) should be disallowed. + * + * <p>In which case certain things (like disabling the package) should be disallowed. */ public static boolean isEssentialPackage( Resources resources, PackageManager pm, String packageName) { @@ -462,14 +483,12 @@ public class Utils { * returns {@code false}. */ public static boolean isDeviceProvisioningPackage(Resources resources, String packageName) { - String deviceProvisioningPackage = resources.getString( - com.android.internal.R.string.config_deviceProvisioningPackage); + String deviceProvisioningPackage = + resources.getString(com.android.internal.R.string.config_deviceProvisioningPackage); return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName); } - /** - * Fetch the package name of the default WebView provider. - */ + /** Fetch the package name of the default WebView provider. */ @Nullable private static String getDefaultWebViewPackageName() { if (sDefaultWebViewPackageName != null) { @@ -503,8 +522,8 @@ public class Utils { /** * Returns the Wifi icon resource for a given RSSI level. * - * @param showX True if a connected Wi-Fi network has the problem which should show Pie+x - * signal icon to users. + * @param showX True if a connected Wi-Fi network has the problem which should show Pie+x signal + * icon to users. * @param level The number of bars to show (0-4) * @throws IllegalArgumentException if an invalid RSSI level is given. */ @@ -520,10 +539,7 @@ public class Utils { try { defaultDays = resources.getInteger( - com.android - .internal - .R - .integer + com.android.internal.R.integer .config_storageManagerDaystoRetainDefault); } catch (Resources.NotFoundException e) { // We are likely in a test environment. @@ -535,7 +551,7 @@ public class Utils { return !context.getSystemService(TelephonyManager.class).isDataCapable(); } - /** Returns if the automatic storage management feature is turned on or not. **/ + /** Returns if the automatic storage management feature is turned on or not. */ public static boolean isStorageManagerEnabled(Context context) { boolean isDefaultOn; try { @@ -543,15 +559,14 @@ public class Utils { } catch (Resources.NotFoundException e) { isDefaultOn = false; } - return Settings.Secure.getInt(context.getContentResolver(), - Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, - isDefaultOn ? 1 : 0) + return Settings.Secure.getInt( + context.getContentResolver(), + Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, + isDefaultOn ? 1 : 0) != 0; } - /** - * get that {@link AudioManager#getMode()} is in ringing/call/communication(VoIP) status. - */ + /** get that {@link AudioManager#getMode()} is in ringing/call/communication(VoIP) status. */ public static boolean isAudioModeOngoingCall(Context context) { final AudioManager audioManager = context.getSystemService(AudioManager.class); final int audioMode = audioManager.getMode(); @@ -561,8 +576,8 @@ public class Utils { } /** - * Return the service state is in-service or not. - * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI + * Return the service state is in-service or not. To make behavior consistent with SystemUI and + * Settings/AboutPhone/SIM status UI * * @param serviceState Service state. {@link ServiceState} */ @@ -581,13 +596,12 @@ public class Utils { } /** - * Return the combined service state. - * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI. + * Return the combined service state. To make behavior consistent with SystemUI and + * Settings/AboutPhone/SIM status UI. * - * This method returns a single service state int if either the voice reg state is - * {@link ServiceState#STATE_IN_SERVICE} or if data network is registered via a - * WWAN transport type. We consider the combined service state of an IWLAN network - * to be OOS. + * <p>This method returns a single service state int if either the voice reg state is {@link + * ServiceState#STATE_IN_SERVICE} or if data network is registered via a WWAN transport type. We + * consider the combined service state of an IWLAN network to be OOS. * * @param serviceState Service state. {@link ServiceState} */ @@ -618,9 +632,10 @@ public class Utils { // on either a WLAN or WWAN network. Since we want to exclude the WLAN network, we can // query the WWAN network directly and check for its registration state private static boolean isDataRegInWwanAndInService(ServiceState serviceState) { - final NetworkRegistrationInfo networkRegWwan = serviceState.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + final NetworkRegistrationInfo networkRegWwan = + serviceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (networkRegWwan == null) { return false; @@ -633,8 +648,8 @@ public class Utils { public static Drawable getBadgedIcon(Context context, Drawable icon, UserHandle user) { int userType = UserIconInfo.TYPE_MAIN; try { - UserInfo ui = context.getSystemService(UserManager.class).getUserInfo( - user.getIdentifier()); + UserInfo ui = + context.getSystemService(UserManager.class).getUserInfo(user.getIdentifier()); if (ui != null) { if (ui.isCloneProfile()) { userType = UserIconInfo.TYPE_CLONED; @@ -650,15 +665,16 @@ public class Utils { try (IconFactory iconFactory = IconFactory.obtain(context)) { return iconFactory .createBadgedIconBitmap( - icon, - new IconOptions().setUser(new UserIconInfo(user, userType))) + icon, new IconOptions().setUser(new UserIconInfo(user, userType))) .newIcon(context); } } /** Get the {@link Drawable} that represents the app icon */ public static Drawable getBadgedIcon(Context context, ApplicationInfo appInfo) { - return getBadgedIcon(context, appInfo.loadUnbadgedIcon(context.getPackageManager()), + return getBadgedIcon( + context, + appInfo.loadUnbadgedIcon(context.getPackageManager()), UserHandle.getUserHandleForUid(appInfo.uid)); } @@ -669,10 +685,11 @@ public class Utils { * @param source bitmap to apply round corner. * @param cornerRadius corner radius value. */ - public static Bitmap convertCornerRadiusBitmap(@NonNull Context context, - @NonNull Bitmap source, @NonNull float cornerRadius) { - final Bitmap roundedBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), - Bitmap.Config.ARGB_8888); + @NonNull + public static Bitmap convertCornerRadiusBitmap( + @NonNull Context context, @NonNull Bitmap source, @NonNull float cornerRadius) { + final Bitmap roundedBitmap = + Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); final RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(), source); drawable.setAntiAlias(true); @@ -687,9 +704,6 @@ public class Utils { * Returns the WifiInfo for the underlying WiFi network of the VCN network, returns null if the * input NetworkCapabilities is not for a VCN network with underlying WiFi network. * - * TODO(b/238425913): Move this method to be inside systemui not settingslib once we've migrated - * off of {@link WifiStatusTracker} and {@link NetworkControllerImpl}. - * * @param networkCapabilities NetworkCapabilities of the network. */ @Nullable @@ -708,8 +722,9 @@ public class Utils { // Avoid the caller doesn't have permission to read the "Settings.Secure" data. try { // Whether the incompatible charger warning is disabled or not - if (Settings.Secure.getInt(context.getContentResolver(), - INCOMPATIBLE_CHARGER_WARNING_DISABLED, 0) == 1) { + if (Settings.Secure.getInt( + context.getContentResolver(), INCOMPATIBLE_CHARGER_WARNING_DISABLED, 0) + == 1) { Log.d(tag, "containsIncompatibleChargers: disabled"); return false; } @@ -718,8 +733,7 @@ public class Utils { return false; } - final List<UsbPort> usbPortList = - context.getSystemService(UsbManager.class).getPorts(); + final List<UsbPort> usbPortList = context.getSystemService(UsbManager.class).getPorts(); if (usbPortList == null || usbPortList.isEmpty()) { return false; } @@ -760,4 +774,85 @@ public class Utils { return false; } + /** Whether to show the wireless charging notification. */ + public static boolean shouldShowWirelessChargingNotification( + @NonNull Context context, @NonNull String tag) { + try { + return shouldShowWirelessChargingNotificationInternal(context, tag); + } catch (Exception e) { + Log.e(tag, "shouldShowWirelessChargingNotification()", e); + return false; + } + } + + /** Stores the timestamp of the wireless charging notification. */ + public static void updateWirelessChargingNotificationTimestamp( + @NonNull Context context, long timestamp, @NonNull String tag) { + try { + Secure.putLong( + context.getContentResolver(), + WIRELESS_CHARGING_NOTIFICATION_TIMESTAMP, + timestamp); + } catch (Exception e) { + Log.e(tag, "setWirelessChargingNotificationTimestamp()", e); + } + } + + /** Whether to show the wireless charging warning in Settings. */ + public static boolean shouldShowWirelessChargingWarningTip( + @NonNull Context context, @NonNull String tag) { + try { + return Secure.getInt(context.getContentResolver(), WIRELESS_CHARGING_WARNING_ENABLED, 0) + == 1; + } catch (Exception e) { + Log.e(tag, "shouldShowWirelessChargingWarningTip()", e); + } + return false; + } + + /** Stores the state of whether the wireless charging warning in Settings is enabled. */ + public static void updateWirelessChargingWarningEnabled( + @NonNull Context context, boolean enabled, @NonNull String tag) { + try { + Secure.putInt( + context.getContentResolver(), + WIRELESS_CHARGING_WARNING_ENABLED, + enabled ? 1 : 0); + } catch (Exception e) { + Log.e(tag, "setWirelessChargingWarningEnabled()", e); + } + } + + private static boolean shouldShowWirelessChargingNotificationInternal( + @NonNull Context context, @NonNull String tag) { + final long lastNotificationTimeMillis = + Secure.getLong( + context.getContentResolver(), + WIRELESS_CHARGING_NOTIFICATION_TIMESTAMP, + WIRELESS_CHARGING_DEFAULT_TIMESTAMP); + if (isWirelessChargingNotificationDisabled(lastNotificationTimeMillis)) { + return false; + } + if (isInitialWirelessChargingNotification(lastNotificationTimeMillis)) { + updateWirelessChargingNotificationTimestamp(context, System.currentTimeMillis(), tag); + updateWirelessChargingWarningEnabled(context, /* enabled= */ true, tag); + return true; + } + final long durationMillis = System.currentTimeMillis() - lastNotificationTimeMillis; + final boolean show = durationMillis > WIRELESS_CHARGING_NOTIFICATION_THRESHOLD_MILLIS; + Log.d(tag, "shouldShowWirelessChargingNotification = " + show); + if (show) { + updateWirelessChargingNotificationTimestamp(context, System.currentTimeMillis(), tag); + updateWirelessChargingWarningEnabled(context, /* enabled= */ true, tag); + } + return show; + } + + private static boolean isWirelessChargingNotificationDisabled(long lastNotificationTimeMillis) { + return lastNotificationTimeMillis == Long.MIN_VALUE; + } + + private static boolean isInitialWirelessChargingNotification(long lastNotificationTimeMillis) { + return lastNotificationTimeMillis == WIRELESS_CHARGING_DEFAULT_TIMESTAMP; + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java index a88a9c72e4a9..2d07e5d471ed 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java @@ -16,6 +16,9 @@ package com.android.settingslib; import static com.android.settingslib.Utils.STORAGE_MANAGER_ENABLED_PROPERTY; +import static com.android.settingslib.Utils.WIRELESS_CHARGING_DEFAULT_TIMESTAMP; +import static com.android.settingslib.Utils.shouldShowWirelessChargingWarningTip; +import static com.android.settingslib.Utils.updateWirelessChargingNotificationTimestamp; import static com.google.common.truth.Truth.assertThat; @@ -28,10 +31,10 @@ import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; -import android.hardware.usb.flags.Flags; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; +import android.hardware.usb.flags.Flags; import android.location.LocationManager; import android.media.AudioManager; import android.os.BatteryManager; @@ -59,6 +62,7 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.shadows.ShadowSettings; +import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -72,21 +76,16 @@ public class UtilsTest { private static final String PERCENTAGE_49 = "49%"; private static final String PERCENTAGE_50 = "50%"; private static final String PERCENTAGE_100 = "100%"; + private static final long CURRENT_TIMESTAMP = System.currentTimeMillis(); private AudioManager mAudioManager; private Context mContext; - @Mock - private LocationManager mLocationManager; - @Mock - private ServiceState mServiceState; - @Mock - private NetworkRegistrationInfo mNetworkRegistrationInfo; - @Mock - private UsbPort mUsbPort; - @Mock - private UsbManager mUsbManager; - @Mock - private UsbPortStatus mUsbPortStatus; + @Mock private LocationManager mLocationManager; + @Mock private ServiceState mServiceState; + @Mock private NetworkRegistrationInfo mNetworkRegistrationInfo; + @Mock private UsbPort mUsbPort; + @Mock private UsbManager mUsbManager; + @Mock private UsbPortStatus mUsbPortStatus; @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -102,27 +101,37 @@ public class UtilsTest { @After public void reset() { - Settings.Secure.putInt(mContext.getContentResolver(), - Utils.INCOMPATIBLE_CHARGER_WARNING_DISABLED, 0); + Settings.Secure.putInt( + mContext.getContentResolver(), Utils.INCOMPATIBLE_CHARGER_WARNING_DISABLED, 0); } @Test public void testUpdateLocationEnabled() { int currentUserId = ActivityManager.getCurrentUser(); - Utils.updateLocationEnabled(mContext, true, currentUserId, - Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS); + Utils.updateLocationEnabled( + mContext, true, currentUserId, Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS); - assertThat(Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.LOCATION_CHANGER, - Settings.Secure.LOCATION_CHANGER_UNKNOWN)).isEqualTo( - Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS); + assertThat( + Settings.Secure.getInt( + mContext.getContentResolver(), + Settings.Secure.LOCATION_CHANGER, + Settings.Secure.LOCATION_CHANGER_UNKNOWN)) + .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS); } @Test public void testFormatPercentage_RoundTrue_RoundUpIfPossible() { - final String[] expectedPercentages = - {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1, PERCENTAGE_1, PERCENTAGE_49, - PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50, PERCENTAGE_100}; + final String[] expectedPercentages = { + PERCENTAGE_0, + PERCENTAGE_0, + PERCENTAGE_1, + PERCENTAGE_1, + PERCENTAGE_49, + PERCENTAGE_49, + PERCENTAGE_50, + PERCENTAGE_50, + PERCENTAGE_100 + }; for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) { final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], true); @@ -132,9 +141,17 @@ public class UtilsTest { @Test public void testFormatPercentage_RoundFalse_NoRound() { - final String[] expectedPercentages = - {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_49, - PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_100}; + final String[] expectedPercentages = { + PERCENTAGE_0, + PERCENTAGE_0, + PERCENTAGE_0, + PERCENTAGE_0, + PERCENTAGE_49, + PERCENTAGE_49, + PERCENTAGE_49, + PERCENTAGE_50, + PERCENTAGE_100 + }; for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) { final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], false); @@ -146,7 +163,9 @@ public class UtilsTest { public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() { Resources resources = mock(Resources.class); when(resources.getInteger( - eq(com.android.internal.R.integer.config_storageManagerDaystoRetainDefault))) + eq( + com.android.internal.R.integer + .config_storageManagerDaystoRetainDefault))) .thenReturn(60); assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60); } @@ -214,8 +233,10 @@ public class UtilsTest { public void isInService_voiceOutOfServiceDataInService_returnTrue() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); - when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(mNetworkRegistrationInfo); + when(mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) + .thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.isInService()).thenReturn(true); assertThat(Utils.isInService(mServiceState)).isTrue(); @@ -224,8 +245,10 @@ public class UtilsTest { @Test public void isInService_voiceOutOfServiceDataInServiceOnIwLan_returnFalse() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo); + when(mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN)) + .thenReturn(mNetworkRegistrationInfo); when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); when(mNetworkRegistrationInfo.isInService()).thenReturn(true); @@ -235,8 +258,10 @@ public class UtilsTest { @Test public void isInService_voiceOutOfServiceDataNull_returnFalse() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(null); + when(mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) + .thenReturn(null); assertThat(Utils.isInService(mServiceState)).isFalse(); } @@ -244,8 +269,10 @@ public class UtilsTest { @Test public void isInService_voiceOutOfServiceDataOutOfService_returnFalse() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(mNetworkRegistrationInfo); + when(mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) + .thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.isInService()).thenReturn(false); assertThat(Utils.isInService(mServiceState)).isFalse(); @@ -260,96 +287,106 @@ public class UtilsTest { @Test public void getCombinedServiceState_servicestateNull_returnOutOfService() { - assertThat(Utils.getCombinedServiceState(null)).isEqualTo( - ServiceState.STATE_OUT_OF_SERVICE); + assertThat(Utils.getCombinedServiceState(null)) + .isEqualTo(ServiceState.STATE_OUT_OF_SERVICE); } @Test public void getCombinedServiceState_ServiceStatePowerOff_returnPowerOff() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF); - assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo( - ServiceState.STATE_POWER_OFF); + assertThat(Utils.getCombinedServiceState(mServiceState)) + .isEqualTo(ServiceState.STATE_POWER_OFF); } @Test public void getCombinedServiceState_voiceInService_returnInService() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_IN_SERVICE); - assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo( - ServiceState.STATE_IN_SERVICE); + assertThat(Utils.getCombinedServiceState(mServiceState)) + .isEqualTo(ServiceState.STATE_IN_SERVICE); } @Test public void getCombinedServiceState_voiceOutOfServiceDataInService_returnInService() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(mNetworkRegistrationInfo); + when(mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) + .thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.isInService()).thenReturn(true); - assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo( - ServiceState.STATE_IN_SERVICE); + assertThat(Utils.getCombinedServiceState(mServiceState)) + .isEqualTo(ServiceState.STATE_IN_SERVICE); } @Test public void getCombinedServiceState_voiceOutOfServiceDataInServiceOnIwLan_returnOutOfService() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo); + when(mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN)) + .thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.isInService()).thenReturn(true); - assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo( - ServiceState.STATE_OUT_OF_SERVICE); + assertThat(Utils.getCombinedServiceState(mServiceState)) + .isEqualTo(ServiceState.STATE_OUT_OF_SERVICE); } @Test public void getCombinedServiceState_voiceOutOfServiceDataOutOfService_returnOutOfService() { when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegistrationState()).thenReturn( - ServiceState.STATE_OUT_OF_SERVICE); + when(mServiceState.getDataRegistrationState()) + .thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo( - ServiceState.STATE_OUT_OF_SERVICE); + assertThat(Utils.getCombinedServiceState(mServiceState)) + .isEqualTo(ServiceState.STATE_OUT_OF_SERVICE); } @Test public void getBatteryStatus_statusIsFull_returnFullString() { - final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra( - BatteryManager.EXTRA_SCALE, 100); + final Intent intent = + new Intent() + .putExtra(BatteryManager.EXTRA_LEVEL, 100) + .putExtra(BatteryManager.EXTRA_SCALE, 100); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo( - resources.getString(R.string.battery_info_status_full)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)) + .isEqualTo(resources.getString(R.string.battery_info_status_full)); } @Test public void getBatteryStatus_statusIsFullAndUseCompactStatus_returnFullyChargedString() { - final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra( - BatteryManager.EXTRA_SCALE, 100); + final Intent intent = + new Intent() + .putExtra(BatteryManager.EXTRA_LEVEL, 100) + .putExtra(BatteryManager.EXTRA_SCALE, 100); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo( - resources.getString(R.string.battery_info_status_full_charged)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)) + .isEqualTo(resources.getString(R.string.battery_info_status_full_charged)); } @Test public void getBatteryStatus_batteryLevelIs100_returnFullString() { - final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_STATUS, - BatteryManager.BATTERY_STATUS_FULL); + final Intent intent = + new Intent() + .putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_FULL); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo( - resources.getString(R.string.battery_info_status_full)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)) + .isEqualTo(resources.getString(R.string.battery_info_status_full)); } @Test public void getBatteryStatus_batteryLevelIs100AndUseCompactStatus_returnFullyString() { - final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_STATUS, - BatteryManager.BATTERY_STATUS_FULL); + final Intent intent = + new Intent() + .putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_FULL); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo( - resources.getString(R.string.battery_info_status_full_charged)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)) + .isEqualTo(resources.getString(R.string.battery_info_status_full_charged)); } @Test @@ -359,8 +396,8 @@ public class UtilsTest { intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo( - resources.getString(R.string.battery_info_status_charging)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)) + .isEqualTo(resources.getString(R.string.battery_info_status_charging)); } @Test @@ -370,8 +407,8 @@ public class UtilsTest { intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_DOCK); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo( - resources.getString(R.string.battery_info_status_charging_dock)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)) + .isEqualTo(resources.getString(R.string.battery_info_status_charging_dock)); } @Test @@ -381,8 +418,8 @@ public class UtilsTest { intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_WIRELESS); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo( - resources.getString(R.string.battery_info_status_charging_wireless)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)) + .isEqualTo(resources.getString(R.string.battery_info_status_charging_wireless)); } @Test @@ -392,8 +429,8 @@ public class UtilsTest { intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo( - resources.getString(R.string.battery_info_status_charging)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)) + .isEqualTo(resources.getString(R.string.battery_info_status_charging)); } @Test @@ -403,8 +440,8 @@ public class UtilsTest { intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_WIRELESS); final Resources resources = mContext.getResources(); - assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo( - resources.getString(R.string.battery_info_status_charging)); + assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)) + .isEqualTo(resources.getString(R.string.battery_info_status_charging)); } @Test @@ -503,12 +540,97 @@ public class UtilsTest { @Test public void containsIncompatibleChargers_disableWarning_returnFalse() { setupIncompatibleCharging(); - Settings.Secure.putInt(mContext.getContentResolver(), - Utils.INCOMPATIBLE_CHARGER_WARNING_DISABLED, 1); + Settings.Secure.putInt( + mContext.getContentResolver(), Utils.INCOMPATIBLE_CHARGER_WARNING_DISABLED, 1); assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse(); } + @Test + public void shouldShowWirelessChargingNotification_neverSendNotification_returnTrue() { + updateWirelessChargingNotificationTimestamp( + mContext, WIRELESS_CHARGING_DEFAULT_TIMESTAMP, TAG); + + assertThat(Utils.shouldShowWirelessChargingNotification(mContext, TAG)).isTrue(); + } + + @Test + public void shouldShowNotification_neverSendNotification_updateTimestampAndEnabledState() { + updateWirelessChargingNotificationTimestamp( + mContext, WIRELESS_CHARGING_DEFAULT_TIMESTAMP, TAG); + + Utils.shouldShowWirelessChargingNotification(mContext, TAG); + + assertThat(getWirelessChargingNotificationTimestamp()) + .isNotEqualTo(WIRELESS_CHARGING_DEFAULT_TIMESTAMP); + assertThat(shouldShowWirelessChargingWarningTip(mContext, TAG)).isTrue(); + } + + @Test + public void shouldShowWirelessChargingNotification_notificationDisabled_returnFalse() { + updateWirelessChargingNotificationTimestamp(mContext, CURRENT_TIMESTAMP, TAG); + + assertThat(Utils.shouldShowWirelessChargingNotification(mContext, TAG)).isFalse(); + } + + @Test + public void shouldShowWirelessChargingNotification_withinTimeThreshold_returnFalse() { + updateWirelessChargingNotificationTimestamp(mContext, CURRENT_TIMESTAMP, TAG); + + assertThat(Utils.shouldShowWirelessChargingNotification(mContext, TAG)).isFalse(); + } + + @Test + public void shouldShowWirelessChargingNotification_exceedTimeThreshold_returnTrue() { + final long monthAgo = Duration.ofDays(31).toMillis(); + final long timestamp = CURRENT_TIMESTAMP - monthAgo; + updateWirelessChargingNotificationTimestamp(mContext, timestamp, TAG); + + assertThat(Utils.shouldShowWirelessChargingNotification(mContext, TAG)).isTrue(); + } + + @Test + public void shouldShowNotification_exceedTimeThreshold_updateTimestampAndEnabledState() { + final long monthAgo = Duration.ofDays(31).toMillis(); + final long timestamp = CURRENT_TIMESTAMP - monthAgo; + updateWirelessChargingNotificationTimestamp(mContext, timestamp, TAG); + + Utils.shouldShowWirelessChargingNotification(mContext, TAG); + + assertThat(getWirelessChargingNotificationTimestamp()).isNotEqualTo(timestamp); + assertThat(shouldShowWirelessChargingWarningTip(mContext, TAG)).isTrue(); + } + + @Test + public void updateWirelessChargingNotificationTimestamp_dismissForever_setMinValue() { + updateWirelessChargingNotificationTimestamp(mContext, Long.MIN_VALUE, TAG); + + assertThat(getWirelessChargingNotificationTimestamp()).isEqualTo(Long.MIN_VALUE); + } + + @Test + public void updateWirelessChargingNotificationTimestamp_notDismissForever_setTimestamp() { + updateWirelessChargingNotificationTimestamp(mContext, CURRENT_TIMESTAMP, TAG); + + assertThat(getWirelessChargingNotificationTimestamp()) + .isNotEqualTo(WIRELESS_CHARGING_DEFAULT_TIMESTAMP); + assertThat(getWirelessChargingNotificationTimestamp()).isNotEqualTo(Long.MIN_VALUE); + } + + @Test + public void shouldShowWirelessChargingWarningTip_enabled_returnTrue() { + Utils.updateWirelessChargingWarningEnabled(mContext, true, TAG); + + assertThat(shouldShowWirelessChargingWarningTip(mContext, TAG)).isTrue(); + } + + @Test + public void shouldShowWirelessChargingWarningTip_disabled_returnFalse() { + Utils.updateWirelessChargingWarningEnabled(mContext, false, TAG); + + assertThat(shouldShowWirelessChargingWarningTip(mContext, TAG)).isFalse(); + } + private void setupIncompatibleCharging() { setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY); } @@ -520,6 +642,13 @@ public class UtilsTest { when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus); when(mUsbPort.supportsComplianceWarnings()).thenReturn(true); when(mUsbPortStatus.isConnected()).thenReturn(true); - when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[]{complianceWarningType}); + when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[] {complianceWarningType}); + } + + private long getWirelessChargingNotificationTimestamp() { + return Settings.Secure.getLong( + mContext.getContentResolver(), + Utils.WIRELESS_CHARGING_NOTIFICATION_TIMESTAMP, + WIRELESS_CHARGING_DEFAULT_TIMESTAMP); } } |