summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJim Miller <jaggies@google.com>2011-01-13 17:56:35 -0800
committerJim Miller <jaggies@google.com>2011-01-14 18:01:12 -0800
commit8b886fab5496b0b1f5193f21855220176deddc37 (patch)
tree38cad39f24e37fa645e148422d3242afefc3a0e2 /core
parent5a40b8ef81034e00f886010c71dccd62b919028b (diff)
downloadframeworks_base-8b886fab5496b0b1f5193f21855220176deddc37.zip
frameworks_base-8b886fab5496b0b1f5193f21855220176deddc37.tar.gz
frameworks_base-8b886fab5496b0b1f5193f21855220176deddc37.tar.bz2
Fix 3106227: use WeakReferences for receivers in DigitalClock class
This works around a bug in the framework where LockScreen wouldn't get GC'd under certain circumstances which would lead to an OOM crash. It now uses WeakReferences for observers inside the DigitalClock container class and unregisters them if the containing DigitalClock goes away. Also removed mLive variable which was unused and could potentially leak the receivers. Left mAttached for debugging so we can use it to determine if the calls to onAttachToWindow() and onDetachFromWindow() are grossly unbalanced which may be the root cause of the original problem. Have cleanUp() explicitly clear unused references to make tracing through hprof references easier. Change-Id: I99a7e0c356001b05eab5aa729564553666febfea
Diffstat (limited to 'core')
-rw-r--r--core/java/com/android/internal/widget/DigitalClock.java103
1 files changed, 63 insertions, 40 deletions
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.BroadcastReceiver;
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.view.View;
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 @@ public class DigitalClock extends LinearLayout {
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 @@ public class DigitalClock extends LinearLayout {
}
}
- 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 @@ public class DigitalClock extends LinearLayout {
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 @@ public class DigitalClock extends LinearLayout {
}
/* 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 @@ public class DigitalClock extends LinearLayout {
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 @@ public class DigitalClock extends LinearLayout {
}
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 @@ public class DigitalClock extends LinearLayout {
}
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;
- }
}