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
This commit is contained in:
Danny Baumann
2017-02-08 10:28:24 +01:00
parent 77b94bc5a1
commit 6669674eb6
2 changed files with 30 additions and 14 deletions

View File

@@ -124,7 +124,7 @@ public class RemotePreference extends SelfRemovingPreference
@Override
public void onDetached() {
super.onDetached();
RemotePreferenceManager.get(mContext).detach(getKey());
RemotePreferenceManager.get(mContext).detach(getKey(), this);
}
protected String getRemoteKey(Bundle metaData) {

View File

@@ -28,8 +28,10 @@ import android.os.UserHandle;
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<String, Intent> mCache = new ArrayMap<>();
private final Map<String, OnRemoteUpdateListener> mCallbacks = new ArrayMap<>();
private final Map<String, Set<OnRemoteUpdateListener>> mCallbacks = new ArrayMap<>();
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
@@ -73,7 +75,7 @@ public class RemotePreferenceManager {
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 class RemotePreferenceManager {
}
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<OnRemoteUpdateListener> 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<OnRemoteUpdateListener> 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 class RemotePreferenceManager {
public void run() {
synchronized (mCallbacks) {
if (mCallbacks.containsKey(key)) {
mCallbacks.get(key).onRemoteUpdated(bundle);
Set<OnRemoteUpdateListener> cbs = mCallbacks.get(key);
if (cbs != null) {
for (OnRemoteUpdateListener cb : cbs) {
cb.onRemoteUpdated(bundle);
}
}
}
}
}