Merge "Fix 3106227: use WeakReferences for receivers in DigitalClock class" into gingerbread
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index fa47ff6..303a1bf 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Typeface;
import android.os.Handler;
@@ -33,6 +32,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import java.lang.ref.WeakReference;
import java.text.DateFormatSymbols;
import java.util.Calendar;
@@ -49,26 +49,41 @@
private TextView mTimeDisplay;
private AmPm mAmPm;
private ContentObserver mFormatChangeObserver;
- private boolean mLive = true;
- private boolean mAttached;
+ private int mAttached = 0; // for debugging - tells us whether attach/detach is unbalanced
/* called by system on minute ticks */
private final Handler mHandler = new Handler();
- private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mLive && intent.getAction().equals(
- Intent.ACTION_TIMEZONE_CHANGED)) {
- mCalendar = Calendar.getInstance();
- }
- // Post a runnable to avoid blocking the broadcast.
- mHandler.post(new Runnable() {
- public void run() {
- updateTime();
+ private BroadcastReceiver mIntentReceiver;
+
+ private static class TimeChangedReceiver extends BroadcastReceiver {
+ private WeakReference<DigitalClock> mClock;
+ private Context mContext;
+
+ public TimeChangedReceiver(DigitalClock clock) {
+ mClock = new WeakReference<DigitalClock>(clock);
+ mContext = clock.getContext();
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Post a runnable to avoid blocking the broadcast.
+ final boolean timezoneChanged =
+ intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);
+ final DigitalClock clock = mClock.get();
+ if (clock != null) {
+ clock.mHandler.post(new Runnable() {
+ public void run() {
+ if (timezoneChanged) {
+ clock.mCalendar = Calendar.getInstance();
}
+ clock.updateTime();
+ }
});
+ } else {
+ mContext.unregisterReceiver(this);
}
- };
+ }
+ };
static class AmPm {
private TextView mAmPm;
@@ -94,14 +109,23 @@
}
}
- private class FormatChangeObserver extends ContentObserver {
- public FormatChangeObserver() {
+ private static class FormatChangeObserver extends ContentObserver {
+ private WeakReference<DigitalClock> mClock;
+ private Context mContext;
+ public FormatChangeObserver(DigitalClock clock) {
super(new Handler());
+ mClock = new WeakReference<DigitalClock>(clock);
+ mContext = clock.getContext();
}
@Override
public void onChange(boolean selfChange) {
- setDateFormat();
- updateTime();
+ DigitalClock digitalClock = mClock.get();
+ if (digitalClock != null) {
+ digitalClock.setDateFormat();
+ digitalClock.updateTime();
+ } else {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
}
}
@@ -129,11 +153,11 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mAttached) return;
- mAttached = true;
+ mAttached++;
- if (mLive) {
- /* monitor time ticks, time changed, timezone */
+ /* monitor time ticks, time changed, timezone */
+ if (mIntentReceiver == null) {
+ mIntentReceiver = new TimeChangedReceiver(this);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
@@ -142,9 +166,11 @@
}
/* monitor 12/24-hour display preference */
- mFormatChangeObserver = new FormatChangeObserver();
- mContext.getContentResolver().registerContentObserver(
- Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ if (mFormatChangeObserver == null) {
+ mFormatChangeObserver = new FormatChangeObserver(this);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ }
updateTime();
}
@@ -153,16 +179,19 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (!mAttached) return;
- mAttached = false;
+ mAttached--;
- if (mLive) {
+ if (mIntentReceiver != null) {
mContext.unregisterReceiver(mIntentReceiver);
}
- mContext.getContentResolver().unregisterContentObserver(
- mFormatChangeObserver);
- }
+ if (mFormatChangeObserver != null) {
+ mContext.getContentResolver().unregisterContentObserver(
+ mFormatChangeObserver);
+ }
+ mFormatChangeObserver = null;
+ mIntentReceiver = null;
+ }
void updateTime(Calendar c) {
mCalendar = c;
@@ -170,9 +199,7 @@
}
private void updateTime() {
- if (mLive) {
- mCalendar.setTimeInMillis(System.currentTimeMillis());
- }
+ mCalendar.setTimeInMillis(System.currentTimeMillis());
CharSequence newTime = DateFormat.format(mFormat, mCalendar);
mTimeDisplay.setText(newTime);
@@ -180,12 +207,8 @@
}
private void setDateFormat() {
- mFormat = android.text.format.DateFormat.is24HourFormat(getContext())
+ mFormat = android.text.format.DateFormat.is24HourFormat(getContext())
? M24 : M12;
mAmPm.setShowAmPm(mFormat.equals(M12));
}
-
- void setLive(boolean live) {
- mLive = live;
- }
}
diff --git a/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
index 840c5e1..c4feefd 100644
--- a/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
@@ -62,8 +62,8 @@
*/
private static final int AWAKE_POKE_MILLIS = 30000;
- private final KeyguardScreenCallback mCallback;
- private final LockPatternUtils mLockPatternUtils;
+ private KeyguardScreenCallback mCallback;
+ private LockPatternUtils mLockPatternUtils;
private KeyguardUpdateMonitor mUpdateMonitor;
private TextView mTopHeader;
@@ -159,7 +159,10 @@
if (mCheckingDialog != null) {
mCheckingDialog.hide();
}
- mUpdateMonitor.removeCallback(this);
+ mUpdateMonitor.removeCallback(this); // this must be first
+ mCallback = null;
+ mLockPatternUtils = null;
+ mUpdateMonitor = null;
}
/** {@inheritDoc} */
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index ba1d7f5..708e89d 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -223,8 +223,8 @@
mKeyguardHost.postDelayed(new Runnable() {
public void run() {
synchronized (KeyguardViewManager.this) {
- mKeyguardHost.removeView(lastView);
lastView.cleanUp();
+ mKeyguardHost.removeView(lastView);
}
}
}, 500);
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 27706ef..f3d07ab 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -495,8 +495,10 @@
public void cleanUp() {
((KeyguardScreen) mLockScreen).onPause();
((KeyguardScreen) mLockScreen).cleanUp();
+ this.removeView(mLockScreen);
((KeyguardScreen) mUnlockScreen).onPause();
((KeyguardScreen) mUnlockScreen).cleanUp();
+ this.removeView(mUnlockScreen);
}
private boolean isSecure() {
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 635b7d3..5a20b93 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -55,9 +55,9 @@
private Status mStatus = Status.Normal;
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardScreenCallback mCallback;
+ private LockPatternUtils mLockPatternUtils;
+ private KeyguardUpdateMonitor mUpdateMonitor;
+ private KeyguardScreenCallback mCallback;
private TextView mCarrier;
private SlidingTab mSelector;
@@ -225,8 +225,8 @@
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- updateMonitor.registerInfoCallback(this);
- updateMonitor.registerSimStateCallback(this);
+ mUpdateMonitor.registerInfoCallback(this);
+ mUpdateMonitor.registerSimStateCallback(this);
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSilentMode = isSilentMode();
@@ -668,7 +668,10 @@
/** {@inheritDoc} */
public void cleanUp() {
- mUpdateMonitor.removeCallback(this);
+ mUpdateMonitor.removeCallback(this); // this must be first
+ mLockPatternUtils = null;
+ mUpdateMonitor = null;
+ mCallback = null;
}
/** {@inheritDoc} */
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index 418e243..ffd0a47 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -66,9 +66,9 @@
private int mTotalFailedPatternAttempts = 0;
private CountDownTimer mCountdownTimer = null;
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardScreenCallback mCallback;
+ private LockPatternUtils mLockPatternUtils;
+ private KeyguardUpdateMonitor mUpdateMonitor;
+ private KeyguardScreenCallback mCallback;
/**
* whether there is a fallback option available when the pattern is forgotten.
@@ -478,6 +478,9 @@
/** {@inheritDoc} */
public void cleanUp() {
mUpdateMonitor.removeCallback(this);
+ mLockPatternUtils = null;
+ mUpdateMonitor = null;
+ mCallback = null;
}
@Override