From 385a63d56a1f5afdf064539d033da999b748289a Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Wed, 30 Oct 2013 19:40:48 -0400 Subject: [PATCH] Move coalescing to callback, optimize KeyguardStatusView. Move the recent keyguard hidden coalescing down to the callback level. The lifetime of each callback can be short, make sure they see visibility changes at least once for each change local to their lifetime. KeyguardStatusView.refresh() is called multiple times, and instances are recreated often. This results in expensive computations filling the sysui/keyguard ui queue, adding to overall sluggishness. Traceview points to DateFormat.getBestDateTimePattern as the main culprit. As of this change, refresh() will only call the expensive date pattern computations when absolutely necessary, resulting in better performance turning the screen off/on. Bug:11221659 Bug:11447043 Change-Id: I3d4105af7db608803b82d8ef0ff141e42c154257 --- .../com/android/keyguard/KeyguardService.java | 5 -- .../android/keyguard/KeyguardStatusView.java | 54 ++++++++++++------- .../keyguard/KeyguardUpdateMonitor.java | 2 +- .../KeyguardUpdateMonitorCallback.java | 15 ++++++ 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java index 8ccd6fe1915b6..36b2446c6b68a 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java @@ -68,8 +68,6 @@ public class KeyguardService extends Service { } private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() { - private boolean mSetHiddenCalled; - private boolean mIsHidden; public boolean isShowing() { return mKeyguardViewMediator.isShowing(); } @@ -91,10 +89,7 @@ public class KeyguardService extends Service { } public void setHidden(boolean isHidden) { checkPermission(); - if (mSetHiddenCalled && mIsHidden == isHidden) return; mKeyguardViewMediator.setHidden(isHidden); - mSetHiddenCalled = true; - mIsHidden = isHidden; } public void dismiss() { mKeyguardViewMediator.dismiss(); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java index d93327526f656..0bfee38cc84c2 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java @@ -98,26 +98,13 @@ public class KeyguardStatusView extends GridLayout { } protected void refresh() { - Resources res = mContext.getResources(); - Locale locale = Locale.getDefault(); - final String dateFormat = DateFormat.getBestDateTimePattern(locale, - res.getString(R.string.abbrev_wday_month_day_no_year)); + Patterns.update(mContext); - mDateView.setFormat24Hour(dateFormat); - mDateView.setFormat12Hour(dateFormat); + mDateView.setFormat24Hour(Patterns.dateView); + mDateView.setFormat12Hour(Patterns.dateView); - // 12-hour clock. - // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton - // format. The following code removes the AM/PM indicator if we didn't want it. - final String clock12skel = res.getString(R.string.clock_12hr_format); - String clock12hr = DateFormat.getBestDateTimePattern(locale, clock12skel); - clock12hr = clock12skel.contains("a") ? clock12hr : clock12hr.replaceAll("a", "").trim(); - mClockView.setFormat12Hour(clock12hr); - - // 24-hour clock - final String clock24skel = res.getString(R.string.clock_24hr_format); - final String clock24hr = DateFormat.getBestDateTimePattern(locale, clock24skel); - mClockView.setFormat24Hour(clock24hr); + mClockView.setFormat12Hour(Patterns.clockView12); + mClockView.setFormat24Hour(Patterns.clockView24); refreshAlarmStatus(); } @@ -149,4 +136,35 @@ public class KeyguardStatusView extends GridLayout { return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET; } + // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. + // This is an optimization to ensure we only recompute the patterns when the inputs change. + private static final class Patterns { + static String dateView; + static String clockView12; + static String clockView24; + static String cacheKey; + + static void update(Context context) { + final Locale locale = Locale.getDefault(); + final Resources res = context.getResources(); + final String dateViewSkel = res.getString(R.string.abbrev_wday_month_day_no_year); + final String clockView12Skel = res.getString(R.string.clock_12hr_format); + final String clockView24Skel = res.getString(R.string.clock_24hr_format); + final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel; + if (key.equals(cacheKey)) return; + + dateView = DateFormat.getBestDateTimePattern(locale, dateViewSkel); + + clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel); + // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton + // format. The following code removes the AM/PM indicator if we didn't want it. + if (!clockView12Skel.contains("a")) { + clockView12 = clockView12.replaceAll("a", "").trim(); + } + + clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); + + cacheKey = key; + } + } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index 520cea32b0135..a8493166ac847 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -815,7 +815,7 @@ public class KeyguardUpdateMonitor { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onKeyguardVisibilityChanged(isShowing); + cb.onKeyguardVisibilityChangedRaw(isShowing); } } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 76f963733c98d..c08880dfc8723 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -19,6 +19,7 @@ import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.graphics.Bitmap; import android.media.AudioManager; +import android.os.SystemClock; import android.view.WindowManagerPolicy; import com.android.internal.telephony.IccCardConstants; @@ -27,6 +28,11 @@ import com.android.internal.telephony.IccCardConstants; * Callback for general information relevant to lock screen. */ class KeyguardUpdateMonitorCallback { + + private static final long VISIBILITY_CHANGED_COLLAPSE_MS = 1000; + private long mVisibilityChangedCalled; + private boolean mShowing; + /** * Called when the battery status changes, e.g. when plugged in or unplugged, charge * level, etc. changes. @@ -70,6 +76,15 @@ class KeyguardUpdateMonitorCallback { */ void onKeyguardVisibilityChanged(boolean showing) { } + void onKeyguardVisibilityChangedRaw(boolean showing) { + final long now = SystemClock.elapsedRealtime(); + if (showing == mShowing + && (now - mVisibilityChangedCalled) < VISIBILITY_CHANGED_COLLAPSE_MS) return; + onKeyguardVisibilityChanged(showing); + mVisibilityChangedCalled = now; + mShowing = showing; + } + /** * Called when visibility of lockscreen clock changes, such as when * obscured by a widget.