From 8dcffb88cf71b9d5a59af0d4fce2d43a7ab26679 Mon Sep 17 00:00:00 2001 From: Santos Cordon Date: Sat, 3 Apr 2021 01:53:50 +0100 Subject: [PATCH 1/3] Use new getBrighntessInfo() API for brightness The slider and settings need to use the new brightness api so that: 1) It can work for mutiple-displays that support brightness 2) Can work with high-brightness mode which can dynamically adjust the brightness min and max. Bug: 168210311 Test: Verify that slider can go to 100% with HBM on or off. Test: atest com.android.settings.display Change-Id: I01029e211f64f0a8598b1388dd3bb535eb0beb69 --- .../BrightnessLevelPreferenceController.java | 51 ++++++++++++------- ...ightnessLevelPreferenceControllerTest.java | 45 ++++------------ 2 files changed, 44 insertions(+), 52 deletions(-) diff --git a/src/com/android/settings/display/BrightnessLevelPreferenceController.java b/src/com/android/settings/display/BrightnessLevelPreferenceController.java index 2e545721f68..7e0ce66c33e 100644 --- a/src/com/android/settings/display/BrightnessLevelPreferenceController.java +++ b/src/com/android/settings/display/BrightnessLevelPreferenceController.java @@ -20,13 +20,15 @@ import static com.android.settingslib.display.BrightnessUtils.convertLinearToGam import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; +import android.hardware.display.BrightnessInfo; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; -import android.provider.Settings; import android.provider.Settings.System; import android.service.vr.IVrManager; import android.util.Log; @@ -49,42 +51,53 @@ public class BrightnessLevelPreferenceController extends AbstractPreferenceContr private static final String TAG = "BrightnessPrefCtrl"; private static final String KEY_BRIGHTNESS = "brightness"; - private static final Uri BRIGHTNESS_URI; private static final Uri BRIGHTNESS_FOR_VR_URI; private static final Uri BRIGHTNESS_ADJ_URI; - private final float mMinBrightness; - private final float mMaxBrightness; private final float mMinVrBrightness; private final float mMaxVrBrightness; private final ContentResolver mContentResolver; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final DisplayManager mDisplayManager; private Preference mPreference; static { - BRIGHTNESS_URI = System.getUriFor(System.SCREEN_BRIGHTNESS_FLOAT); BRIGHTNESS_FOR_VR_URI = System.getUriFor(System.SCREEN_BRIGHTNESS_FOR_VR); BRIGHTNESS_ADJ_URI = System.getUriFor(System.SCREEN_AUTO_BRIGHTNESS_ADJ); } private ContentObserver mBrightnessObserver = - new ContentObserver(new Handler(Looper.getMainLooper())) { + new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { updatedSummary(mPreference); } }; + private final DisplayListener mDisplayListener = new DisplayListener() { + @Override + public void onDisplayAdded(int displayId) {} + + @Override + public void onDisplayRemoved(int displayId) {} + + @Override + public void onDisplayChanged(int displayId) { + updatedSummary(mPreference); + } + }; + + public BrightnessLevelPreferenceController(Context context, Lifecycle lifecycle) { super(context); + mDisplayManager = context.getSystemService(DisplayManager.class); + if (lifecycle != null) { lifecycle.addObserver(this); } - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mMinBrightness = powerManager.getBrightnessConstraint( - PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM); - mMaxBrightness = powerManager.getBrightnessConstraint( - PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM); + final PowerManager powerManager = context.getSystemService(PowerManager.class); + mMinVrBrightness = powerManager.getBrightnessConstraint( PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR); mMaxVrBrightness = powerManager.getBrightnessConstraint( @@ -115,14 +128,16 @@ public class BrightnessLevelPreferenceController extends AbstractPreferenceContr @Override public void onStart() { - mContentResolver.registerContentObserver(BRIGHTNESS_URI, false, mBrightnessObserver); mContentResolver.registerContentObserver(BRIGHTNESS_FOR_VR_URI, false, mBrightnessObserver); mContentResolver.registerContentObserver(BRIGHTNESS_ADJ_URI, false, mBrightnessObserver); + mDisplayManager.registerDisplayListener(mDisplayListener, mHandler, + DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); } @Override public void onStop() { mContentResolver.unregisterContentObserver(mBrightnessObserver); + mDisplayManager.unregisterDisplayListener(mDisplayListener); } private void updatedSummary(Preference preference) { @@ -132,15 +147,17 @@ public class BrightnessLevelPreferenceController extends AbstractPreferenceContr } private double getCurrentBrightness() { - final int value; + int value = 0; if (isInVrMode()) { value = convertLinearToGammaFloat(System.getFloat(mContentResolver, - System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT, mMaxBrightness), + System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT, mMaxVrBrightness), mMinVrBrightness, mMaxVrBrightness); } else { - value = convertLinearToGammaFloat(Settings.System.getFloat(mContentResolver, - System.SCREEN_BRIGHTNESS_FLOAT, mMinBrightness), - mMinBrightness, mMaxBrightness); + final BrightnessInfo info = mContext.getDisplay().getBrightnessInfo(); + if (info != null) { + value = convertLinearToGammaFloat(info.brightness, info.brightnessMinimum, + info.brightnessMaximum); + } } return getPercentage(value, GAMMA_SPACE_MIN, GAMMA_SPACE_MAX); } diff --git a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java index 15d4c973baf..8fd847a8073 100644 --- a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java @@ -22,15 +22,16 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; +import android.hardware.display.BrightnessInfo; import android.os.PowerManager; import android.provider.Settings.System; +import android.view.Display; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -52,6 +53,8 @@ public class BrightnessLevelPreferenceControllerTest { @Mock private PowerManager mPowerManager; @Mock + private Display mDisplay; + @Mock private PreferenceScreen mScreen; @Mock private Preference mPreference; @@ -65,7 +68,7 @@ public class BrightnessLevelPreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); mContentResolver = mContext.getContentResolver(); when(mPowerManager.getBrightnessConstraint( PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM)).thenReturn(0.0f); @@ -78,6 +81,7 @@ public class BrightnessLevelPreferenceControllerTest { ShadowApplication.getInstance().setSystemService(POWER_SERVICE, mPowerManager); when(mScreen.findPreference(anyString())).thenReturn(mPreference); + when(mContext.getDisplay()).thenReturn(mDisplay); mController = spy(new BrightnessLevelPreferenceController(mContext, null)); doReturn(false).when(mController).isInVrMode(); } @@ -101,8 +105,6 @@ public class BrightnessLevelPreferenceControllerTest { controller.onStart(); - assertThat(shadowContentResolver.getContentObservers( - System.getUriFor(System.SCREEN_BRIGHTNESS_FLOAT))).isNotEmpty(); assertThat(shadowContentResolver.getContentObservers( System.getUriFor(System.SCREEN_BRIGHTNESS_FOR_VR))).isNotEmpty(); assertThat(shadowContentResolver.getContentObservers( @@ -119,8 +121,6 @@ public class BrightnessLevelPreferenceControllerTest { controller.onStart(); controller.onStop(); - assertThat(shadowContentResolver.getContentObservers( - System.getUriFor(System.SCREEN_BRIGHTNESS_FLOAT))).isEmpty(); assertThat(shadowContentResolver.getContentObservers( System.getUriFor(System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT))).isEmpty(); assertThat(shadowContentResolver.getContentObservers( @@ -143,7 +143,8 @@ public class BrightnessLevelPreferenceControllerTest { System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS_MODE, System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - System.putFloat(mContentResolver, System.SCREEN_BRIGHTNESS_FLOAT, 0.1f); + when(mDisplay.getBrightnessInfo()).thenReturn( + new BrightnessInfo(0.1f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); mController.updateState(mPreference); @@ -156,7 +157,8 @@ public class BrightnessLevelPreferenceControllerTest { System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS_MODE, System.SCREEN_BRIGHTNESS_MODE_MANUAL); - System.putFloat(mContentResolver, System.SCREEN_BRIGHTNESS_FLOAT, 0.5f); + when(mDisplay.getBrightnessInfo()).thenReturn( + new BrightnessInfo(0.5f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); mController.updateState(mPreference); @@ -175,32 +177,5 @@ public class BrightnessLevelPreferenceControllerTest { System.putFloat(mContentResolver, System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT, -20f); mController.updateState(mPreference); verify(mPreference).setSummary("0%"); - - // Auto mode - doReturn(false).when(mController).isInVrMode(); - System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS_MODE, - System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - - reset(mPreference); - System.putFloat(mContentResolver, System.SCREEN_BRIGHTNESS_FLOAT, 1.15f); - mController.updateState(mPreference); - verify(mPreference).setSummary("100%"); - - System.putFloat(mContentResolver, System.SCREEN_BRIGHTNESS_FLOAT, -10f); - mController.updateState(mPreference); - verify(mPreference).setSummary("0%"); - - // Manual mode - System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS_MODE, - System.SCREEN_BRIGHTNESS_MODE_MANUAL); - - reset(mPreference); - System.putFloat(mContentResolver, System.SCREEN_BRIGHTNESS_FLOAT, 1.15f); - mController.updateState(mPreference); - verify(mPreference).setSummary("100%"); - - System.putFloat(mContentResolver, System.SCREEN_BRIGHTNESS_FLOAT, -10f); - mController.updateState(mPreference); - verify(mPreference).setSummary("0%"); } } From aee53bc98dd7f94522e65df1180a8f52ad016976 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Fri, 23 Apr 2021 15:43:26 -0400 Subject: [PATCH 2/3] Move preference loading to a background thread To improve the loading time of the Notifications screen. Also introduce placeholder preferences to minimize jank when the data becomes available Test: Robotests, adb shell am start -W -a android.settings.NOTIFICATION_SETTINGS Fixes: 185877371 Change-Id: Id63469fdb42e1a66468f2c5f1da8c366686f06e4 --- .../configure_notification_settings_v2.xml | 9 +++ ...centNotifyingAppsPreferenceController.java | 57 +++++++------------ ...NotifyingAppsPreferenceControllerTest.java | 57 ++++++++++++------- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/res/xml/configure_notification_settings_v2.xml b/res/xml/configure_notification_settings_v2.xml index 6b1e69190e5..a0d2dabdc84 100644 --- a/res/xml/configure_notification_settings_v2.xml +++ b/res/xml/configure_notification_settings_v2.xml @@ -42,6 +42,15 @@ android:key="recent_notifications_category" android:title="@string/recent_notifications"> + + + SKIP_SYSTEM_PACKAGES = new ArraySet<>(); private final Fragment mHost; private final PackageManager mPm; @@ -148,13 +149,17 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC @VisibleForTesting void refreshUi(Context prefContext) { - reloadData(); - final List recentApps = getDisplayableRecentAppList(); - if (recentApps != null && !recentApps.isEmpty()) { - displayRecentApps(prefContext, recentApps); - } else { - displayOnlyAllAppsLink(); - } + ThreadUtils.postOnBackgroundThread(() -> { + reloadData(); + final List recentApps = getDisplayableRecentAppList(); + ThreadUtils.postOnMainThread(() -> { + if (recentApps != null && !recentApps.isEmpty()) { + displayRecentApps(prefContext, recentApps); + } else { + displayOnlyAllAppsLink(); + } + }); + }); } @VisibleForTesting @@ -198,8 +203,7 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC } } - @VisibleForTesting - static String getKey(int userId, String pkg) { + private static String getKey(int userId, String pkg) { return userId + "|" + pkg; } @@ -221,19 +225,9 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC mSeeAllPref.setSummary(null); mSeeAllPref.setIcon(R.drawable.ic_chevron_right_24dp); - // Rebind prefs/avoid adding new prefs if possible. Adding/removing prefs causes jank. - // Build a cached preference pool - final Map appPreferences = new ArrayMap<>(); - int prefCount = mCategory.getPreferenceCount(); - for (int i = 0; i < prefCount; i++) { - final Preference pref = mCategory.getPreference(i); - final String key = pref.getKey(); - if (!TextUtils.equals(key, KEY_SEE_ALL)) { - appPreferences.put(key, (PrimarySwitchPreference) pref); - } - } + int keyIndex = 1; final int recentAppsCount = recentApps.size(); - for (int i = 0; i < recentAppsCount; i++) { + for (int i = 0; i < recentAppsCount; i++, keyIndex++) { final NotifyingApp app = recentApps.get(i); // Bind recent apps to existing prefs if possible, or create a new pref. final String pkgName = app.getPackage(); @@ -243,20 +237,12 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC continue; } - boolean rebindPref = true; - PrimarySwitchPreference pref = appPreferences.remove(getKey(app.getUserId(), - pkgName)); - if (pref == null) { - pref = new PrimarySwitchPreference(prefContext); - rebindPref = false; - } - pref.setKey(getKey(app.getUserId(), pkgName)); + PrimarySwitchPreference pref = mCategory.findPreference(KEY_PLACEHOLDER + keyIndex); pref.setTitle(appEntry.label); pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info)); pref.setIconSize(TwoTargetPreference.ICON_SIZE_SMALL); pref.setSummary(StringUtil.formatRelativeTime(mContext, System.currentTimeMillis() - app.getLastNotified(), true)); - pref.setOrder(i); Bundle args = new Bundle(); args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkgName); args.putInt(AppInfoBase.ARG_PACKAGE_UID, appEntry.info.uid); @@ -280,13 +266,10 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC pref.setChecked( !mNotificationBackend.getNotificationsBanned(pkgName, appEntry.info.uid)); - if (!rebindPref) { - mCategory.addPreference(pref); - } } - // Remove unused prefs from pref cache pool - for (Preference unusedPrefs : appPreferences.values()) { - mCategory.removePreference(unusedPrefs); + // If there are less than SHOW_RECENT_APP_COUNT recent apps, remove placeholders + for (int i = keyIndex; i <= SHOW_RECENT_APP_COUNT; i++) { + mCategory.removePreferenceRecursively(KEY_PLACEHOLDER + i); } } diff --git a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java index 6226b9a318b..983bf535bdd 100644 --- a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java @@ -48,6 +48,7 @@ import android.service.notification.NotifyingApp; import android.text.TextUtils; import com.android.settings.R; +import com.android.settings.widget.PrimarySwitchPreference; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.instantapps.InstantAppDataProvider; @@ -80,6 +81,9 @@ public class RecentNotifyingAppsPreferenceControllerTest { private PreferenceScreen mScreen; @Mock private PreferenceCategory mCategory; + private PrimarySwitchPreference mApp1; + private PrimarySwitchPreference mApp2; + private PrimarySwitchPreference mApp3; @Mock private Preference mSeeAllPref; @Mock @@ -115,6 +119,15 @@ public class RecentNotifyingAppsPreferenceControllerTest { mController = new RecentNotifyingAppsPreferenceController( mContext, mBackend, mIUsageStatsManager, mUserManager, mAppState, mHost); when(mScreen.findPreference(anyString())).thenReturn(mCategory); + mApp1 = new PrimarySwitchPreference(mContext); + mApp1.setKey("app1"); + mApp2 = new PrimarySwitchPreference(mContext); + mApp2.setKey("app2"); + mApp3 = new PrimarySwitchPreference(mContext); + mApp3.setKey("app3"); + when(mCategory.findPreference("app1")).thenReturn(mApp1); + when(mCategory.findPreference("app2")).thenReturn(mApp2); + when(mCategory.findPreference("app3")).thenReturn(mApp3); when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_SEE_ALL)) .thenReturn(mSeeAllPref); @@ -169,12 +182,18 @@ public class RecentNotifyingAppsPreferenceControllerTest { app2.mPackage = "pkg.class2"; app2.mTimeStamp = System.currentTimeMillis() - 1000; events.add(app2); + ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); + ApplicationsState.AppEntry app2Entry = mock(ApplicationsState.AppEntry.class); + app1Entry.info = mApplicationInfo; + app1Entry.label = "app 1"; + app2Entry.info = mApplicationInfo; + app2Entry.label = "app 2"; // app1, app2 are valid apps. app3 is invalid. when(mAppState.getEntry(app.getPackageName(), UserHandle.myUserId())) - .thenReturn(mAppEntry); + .thenReturn(app1Entry); when(mAppState.getEntry(app1.getPackageName(), UserHandle.myUserId())) - .thenReturn(mAppEntry); + .thenReturn(app2Entry); when(mAppState.getEntry(app2.getPackageName(), UserHandle.myUserId())) .thenReturn(null); when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn( @@ -192,7 +211,10 @@ public class RecentNotifyingAppsPreferenceControllerTest { verify(mCategory).setTitle(R.string.recent_notifications); // Only add app1 & app2. app3 skipped because it's invalid app. - verify(mCategory, times(2)).addPreference(any(Preference.class)); + assertThat(mApp1.getTitle()).isEqualTo(app1Entry.label); + assertThat(mApp2.getTitle()).isEqualTo(app2Entry.label); + + verify(mCategory).removePreferenceRecursively(mApp3.getKey()); verify(mSeeAllPref).setSummary(null); verify(mSeeAllPref).setIcon(R.drawable.ic_chevron_right_24dp); @@ -209,22 +231,24 @@ public class RecentNotifyingAppsPreferenceControllerTest { Event app1 = new Event(); app1.mEventType = Event.NOTIFICATION_INTERRUPTION; app1.mPackage = "com.foo.barinstant"; - app1.mTimeStamp = System.currentTimeMillis() + 200; + app1.mTimeStamp = System.currentTimeMillis() - 200; events.add(app1); UsageEvents usageEvents = getUsageEvents( new String[] {"com.foo.bar", "com.foo.barinstant"}, events); when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) .thenReturn(usageEvents); + ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); - ApplicationsState.AppEntry app2Entry = mock(ApplicationsState.AppEntry.class); + appEntry.info = mApplicationInfo; + appEntry.label = "app 1"; app1Entry.info = mApplicationInfo; - app2Entry.info = mApplicationInfo; + app1Entry.label = "app 2"; when(mAppState.getEntry( - app.getPackageName(), UserHandle.myUserId())).thenReturn(app1Entry); + app.getPackageName(), UserHandle.myUserId())).thenReturn(appEntry); when(mAppState.getEntry( - app1.getPackageName(), UserHandle.myUserId())).thenReturn(app2Entry); + app1.getPackageName(), UserHandle.myUserId())).thenReturn(app1Entry); // Only the regular app app1 should have its intent resolve. when(mPackageManager.resolveActivity(argThat(intentMatcher(app.getPackageName())), @@ -233,7 +257,7 @@ public class RecentNotifyingAppsPreferenceControllerTest { // Make sure app2 is considered an instant app. ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", (InstantAppDataProvider) (ApplicationInfo info) -> { - if (info == app2Entry.info) { + if (info == app1Entry.info) { return true; } else { return false; @@ -242,15 +266,10 @@ public class RecentNotifyingAppsPreferenceControllerTest { mController.displayPreference(mScreen); - ArgumentCaptor prefCaptor = ArgumentCaptor.forClass(Preference.class); - verify(mCategory, times(2)).addPreference(prefCaptor.capture()); - List prefs = prefCaptor.getAllValues(); - assertThat(prefs.get(1).getKey()).isEqualTo( - RecentNotifyingAppsPreferenceController.getKey(UserHandle.myUserId(), - app.getPackageName())); - assertThat(prefs.get(0).getKey()).isEqualTo( - RecentNotifyingAppsPreferenceController.getKey(UserHandle.myUserId(), - app1.getPackageName())); + assertThat(mApp1.getTitle()).isEqualTo(appEntry.label); + assertThat(mApp2.getTitle()).isEqualTo(app1Entry.label); + + verify(mCategory).removePreferenceRecursively(mApp3.getKey()); } @Test @@ -274,7 +293,7 @@ public class RecentNotifyingAppsPreferenceControllerTest { mController.displayPreference(mScreen); - verify(mCategory).addPreference(argThat(summaryMatches("Just now"))); + assertThat(mApp1.getSummary()).isEqualTo("Just now"); } @Test From ef6cea8c84c9412fc51dd77a2cf5ab0757645fd4 Mon Sep 17 00:00:00 2001 From: ykhung Date: Sat, 24 Apr 2021 01:04:30 +0800 Subject: [PATCH 3/3] Add test cases for utcToLocalTime in the ConvertUtils Bug: 177406865 Bug: 185187729 Test: make SettingsRoboTests Test: make SettingsGoogleRoboTests Change-Id: I22bda2db821e69c40202db692ada52e96af25e16 --- .../settings/fuelgauge/BatteryChartView.java | 9 ++++-- .../settings/fuelgauge/ConvertUtils.java | 26 ++++++++--------- .../settings/fuelgauge/ConvertUtilsTest.java | 28 +++++++++++++++++++ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryChartView.java b/src/com/android/settings/fuelgauge/BatteryChartView.java index f970072cb94..366946e12e2 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartView.java +++ b/src/com/android/settings/fuelgauge/BatteryChartView.java @@ -103,8 +103,8 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick return; } // Sets the chart is clickable if there is at least one valid item in it. - for (int index = 0; index < mLevels.length; index++) { - if (mLevels[index] != 0) { + for (int index = 0; index < mLevels.length - 1; index++) { + if (mLevels[index] != 0 && mLevels[index + 1] != 0) { setClickable(true); break; } @@ -155,6 +155,11 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick return; } final int trapezoidIndex = getTrapezoidIndex(mTouchUpEvent.getX()); + // Ignores the click event if the level is zero. + if (trapezoidIndex == SELECTED_INDEX_INVALID + || (trapezoidIndex >= 0 && mLevels[trapezoidIndex] == 0)) { + return; + } // Selects all if users click the same trapezoid item two times. if (trapezoidIndex == mSelectedIndex) { setSelectedIndex(SELECTED_INDEX_ALL); diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/ConvertUtils.java index 2e8726e38ab..00dcb6be62b 100644 --- a/src/com/android/settings/fuelgauge/ConvertUtils.java +++ b/src/com/android/settings/fuelgauge/ConvertUtils.java @@ -70,8 +70,12 @@ public final class ConvertUtils { public static final int CONSUMER_TYPE_SYSTEM_BATTERY = 3; private static String sZoneId; - private static SimpleDateFormat sSimpleDateFormat; - private static SimpleDateFormat sSimpleDateFormatForHour; + private static String sZoneIdForHour; + + @VisibleForTesting + static SimpleDateFormat sSimpleDateFormat; + @VisibleForTesting + static SimpleDateFormat sSimpleDateFormatForHour; private ConvertUtils() {} @@ -140,25 +144,19 @@ public final class ConvertUtils { sZoneId = currentZoneId; sSimpleDateFormat = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss", Locale.ENGLISH); - sSimpleDateFormatForHour = null; } return sSimpleDateFormat.format(new Date(timestamp)); } /** Converts UTC timestamp to local time hour data. */ - public static int utcToLocalTimeHour(long timestamp) { + public static String utcToLocalTimeHour(long timestamp) { final String currentZoneId = TimeZone.getDefault().getID(); - if (!currentZoneId.equals(sZoneId) || sSimpleDateFormatForHour == null) { - sZoneId = currentZoneId; - sSimpleDateFormat = null; - sSimpleDateFormatForHour = new SimpleDateFormat("HH", Locale.ENGLISH); - } - try { - return Integer.parseInt( - sSimpleDateFormatForHour.format(new Date(timestamp))); - } catch (NumberFormatException e) { - return Integer.MIN_VALUE; + if (!currentZoneId.equals(sZoneIdForHour) || sSimpleDateFormatForHour == null) { + sZoneIdForHour = currentZoneId; + sSimpleDateFormatForHour = new SimpleDateFormat("h aa", Locale.ENGLISH); } + return sSimpleDateFormatForHour.format(new Date(timestamp)) + .toLowerCase(Locale.getDefault()); } /** Gets indexed battery usage data for each corresponding time slot. */ diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java index e95b158391b..12913a29dc8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java @@ -39,10 +39,12 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.TimeZone; @@ -254,6 +256,32 @@ public final class ConvertUtilsTest { assertBatteryDiffEntry(entryList.get(0), 68, 40L, 50L); } + @Test + public void testUtcToLocalTime_returnExpectedResult() { + final long timestamp = 1619196786769L; + ConvertUtils.sSimpleDateFormat = null; + // Invokes the method first to create the SimpleDateFormat. + ConvertUtils.utcToLocalTime(/*timestamp=*/ 0); + ConvertUtils.sSimpleDateFormat + .setTimeZone(TimeZone.getTimeZone("GMT")); + + assertThat(ConvertUtils.utcToLocalTime(timestamp)) + .isEqualTo("Apr 23,2021 16:53:06"); + } + + @Test + public void testUtcToLocalTmeHour_returnExpectedResult() { + final long timestamp = 1619196786769L; + ConvertUtils.sSimpleDateFormatForHour = null; + // Invokes the method first to create the SimpleDateFormat. + ConvertUtils.utcToLocalTimeHour(/*timestamp=*/ 0); + ConvertUtils.sSimpleDateFormatForHour + .setTimeZone(TimeZone.getTimeZone("GMT")); + + assertThat(ConvertUtils.utcToLocalTimeHour(timestamp)) + .isEqualTo("4 pm"); + } + private static BatteryHistEntry createBatteryHistEntry( String packageName, String appLabel, double consumePower, long uid, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {