From 6669674eb67449d6ff4eb6ac2f5601f0a355d75c Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Wed, 8 Feb 2017 10:28:24 +0100 Subject: [PATCH] RemotePreferenceManager: Fix receiver registration issues. - We might get see attach() calls from multiple prefs, so stop assuming there's only one per key. Namely, a new activity might be created and attached before the previous one is destroyed - The passed-in context is likely to be an activity one. As the manager instance is static, this can cause leaks and the receiver might be attached to a destroyed activity. Just hold onto the application context instead, which is a singleton anyway. Change-Id: Ica17c19ab6e1cdfd402968ce2594d3ed362e23ee JIRA:LINN-3 --- .../preference/RemotePreference.java | 2 +- .../preference/RemotePreferenceManager.java | 42 +++++++++++++------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/sdk/src/java/cyanogenmod/preference/RemotePreference.java b/sdk/src/java/cyanogenmod/preference/RemotePreference.java index 42c50c8..0b5bebd 100644 --- a/sdk/src/java/cyanogenmod/preference/RemotePreference.java +++ b/sdk/src/java/cyanogenmod/preference/RemotePreference.java @@ -124,7 +124,7 @@ public void onAttached() { @Override public void onDetached() { super.onDetached(); - RemotePreferenceManager.get(mContext).detach(getKey()); + RemotePreferenceManager.get(mContext).detach(getKey(), this); } protected String getRemoteKey(Bundle metaData) { diff --git a/sdk/src/java/cyanogenmod/preference/RemotePreferenceManager.java b/sdk/src/java/cyanogenmod/preference/RemotePreferenceManager.java index 8313360..9ced81e 100644 --- a/sdk/src/java/cyanogenmod/preference/RemotePreferenceManager.java +++ b/sdk/src/java/cyanogenmod/preference/RemotePreferenceManager.java @@ -28,8 +28,10 @@ import android.util.ArrayMap; import android.util.Log; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; import cyanogenmod.platform.Manifest; @@ -54,7 +56,7 @@ public class RemotePreferenceManager { private final Context mContext; private final Map mCache = new ArrayMap<>(); - private final Map mCallbacks = new ArrayMap<>(); + private final Map> mCallbacks = new ArrayMap<>(); private final Handler mMainHandler = new Handler(Looper.getMainLooper()); @@ -73,7 +75,7 @@ private RemotePreferenceManager(Context context) { public synchronized static RemotePreferenceManager get(Context context) { if (sInstance == null) { - sInstance = new RemotePreferenceManager(context); + sInstance = new RemotePreferenceManager(context.getApplicationContext()); } return sInstance; } @@ -89,27 +91,36 @@ public void attach(String key, OnRemoteUpdateListener pref) { } synchronized (mCallbacks) { if (i != null) { - mCallbacks.put(key, pref); - if (mCallbacks.size() == 1) { - mThread = new HandlerThread("RemotePreference"); - mThread.start(); - mHandler = new Handler(mThread.getLooper()); - mContext.registerReceiver(mListener, - new IntentFilter(ACTION_REFRESH_PREFERENCE), - Manifest.permission.MANAGE_REMOTE_PREFERENCES, mHandler); + Set cbs = mCallbacks.get(key); + if (cbs == null) { + cbs = new HashSet<>(); + mCallbacks.put(key, cbs); + if (mCallbacks.size() == 1) { + mThread = new HandlerThread("RemotePreference"); + mThread.start(); + mHandler = new Handler(mThread.getLooper()); + mContext.registerReceiver(mListener, + new IntentFilter(ACTION_REFRESH_PREFERENCE), + Manifest.permission.MANAGE_REMOTE_PREFERENCES, mHandler); + } } + cbs.add(pref); requestUpdate(key); } } } - public void detach(String key) { + public void detach(String key, OnRemoteUpdateListener pref) { synchronized (mCallbacks) { - if (mCallbacks.remove(key) != null && mCallbacks.size() == 0) { + Set cbs = mCallbacks.get(key); + if (cbs != null && cbs.remove(pref) && cbs.isEmpty() + && mCallbacks.remove(key) != null && mCallbacks.isEmpty()) { mContext.unregisterReceiver(mListener); if (mThread != null) { mThread.quit(); + mThread = null; } + mHandler = null; } } } @@ -152,7 +163,12 @@ public void onReceive(Context context, Intent intent) { public void run() { synchronized (mCallbacks) { if (mCallbacks.containsKey(key)) { - mCallbacks.get(key).onRemoteUpdated(bundle); + Set cbs = mCallbacks.get(key); + if (cbs != null) { + for (OnRemoteUpdateListener cb : cbs) { + cb.onRemoteUpdated(bundle); + } + } } } }