Merge "Add OnSharedPreferencesClearListener for Editor#clear."
This commit is contained in:
@@ -10834,7 +10834,9 @@ package android.content {
|
||||
method @Nullable public String getString(String, @Nullable String);
|
||||
method @Nullable public java.util.Set<java.lang.String> getStringSet(String, @Nullable java.util.Set<java.lang.String>);
|
||||
method public void registerOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
|
||||
method public default void registerOnSharedPreferencesClearListener(@NonNull android.content.SharedPreferences.OnSharedPreferencesClearListener);
|
||||
method public void unregisterOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
|
||||
method public default void unregisterOnSharedPreferencesClearListener(@NonNull android.content.SharedPreferences.OnSharedPreferencesClearListener);
|
||||
}
|
||||
|
||||
public static interface SharedPreferences.Editor {
|
||||
@@ -10854,6 +10856,10 @@ package android.content {
|
||||
method public void onSharedPreferenceChanged(android.content.SharedPreferences, String);
|
||||
}
|
||||
|
||||
public static interface SharedPreferences.OnSharedPreferencesClearListener {
|
||||
method public void onSharedPreferencesClear(@NonNull android.content.SharedPreferences, @NonNull java.util.Set<java.lang.String>);
|
||||
}
|
||||
|
||||
public class SyncAdapterType implements android.os.Parcelable {
|
||||
ctor public SyncAdapterType(String, String, boolean, boolean);
|
||||
ctor public SyncAdapterType(android.os.Parcel);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -25,6 +26,7 @@ import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.StructStat;
|
||||
import android.system.StructTimespec;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -92,6 +94,10 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
|
||||
new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final WeakHashMap<OnSharedPreferencesClearListener, Object> mClearListeners =
|
||||
new WeakHashMap<>();
|
||||
|
||||
/** Current memory state (always increasing) */
|
||||
@GuardedBy("this")
|
||||
private long mCurrentMemoryStateGeneration;
|
||||
@@ -252,6 +258,28 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOnSharedPreferencesClearListener(
|
||||
@NonNull OnSharedPreferencesClearListener listener) {
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener cannot be null.");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mClearListeners.put(listener, CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterOnSharedPreferencesClearListener(
|
||||
@NonNull OnSharedPreferencesClearListener listener) {
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener cannot be null.");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mClearListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void awaitLoadedLocked() {
|
||||
if (!mLoaded) {
|
||||
@@ -361,7 +389,9 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
private static class MemoryCommitResult {
|
||||
final long memoryStateGeneration;
|
||||
@Nullable final List<String> keysModified;
|
||||
@Nullable final Set<String> keysCleared;
|
||||
@Nullable final Set<OnSharedPreferenceChangeListener> listeners;
|
||||
@Nullable final Set<OnSharedPreferencesClearListener> clearListeners;
|
||||
final Map<String, Object> mapToWriteToDisk;
|
||||
final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
|
||||
|
||||
@@ -371,10 +401,14 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
|
||||
private MemoryCommitResult(long memoryStateGeneration, @Nullable List<String> keysModified,
|
||||
@Nullable Set<OnSharedPreferenceChangeListener> listeners,
|
||||
@Nullable Set<String> keysCleared,
|
||||
@Nullable Set<OnSharedPreferencesClearListener> clearListeners,
|
||||
Map<String, Object> mapToWriteToDisk) {
|
||||
this.memoryStateGeneration = memoryStateGeneration;
|
||||
this.keysModified = keysModified;
|
||||
this.listeners = listeners;
|
||||
this.keysCleared = keysCleared;
|
||||
this.clearListeners = clearListeners;
|
||||
this.mapToWriteToDisk = mapToWriteToDisk;
|
||||
}
|
||||
|
||||
@@ -492,13 +526,16 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
// SharedPreferences instance back, which has the
|
||||
// changes reflected in memory.
|
||||
notifyListeners(mcr);
|
||||
notifyClearListeners(mcr);
|
||||
}
|
||||
|
||||
// Returns true if any changes were made
|
||||
private MemoryCommitResult commitToMemory() {
|
||||
long memoryStateGeneration;
|
||||
List<String> keysModified = null;
|
||||
Set<String> keysCleared = null;
|
||||
Set<OnSharedPreferenceChangeListener> listeners = null;
|
||||
Set<OnSharedPreferencesClearListener> clearListeners = null;
|
||||
Map<String, Object> mapToWriteToDisk;
|
||||
|
||||
synchronized (SharedPreferencesImpl.this.mLock) {
|
||||
@@ -520,12 +557,20 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
keysModified = new ArrayList<String>();
|
||||
listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
|
||||
}
|
||||
boolean hasClearListeners = !mClearListeners.isEmpty();
|
||||
if (hasClearListeners) {
|
||||
keysCleared = new ArraySet<>();
|
||||
clearListeners = new HashSet<>(mClearListeners.keySet());
|
||||
}
|
||||
|
||||
synchronized (mEditorLock) {
|
||||
boolean changesMade = false;
|
||||
|
||||
if (mClear) {
|
||||
if (!mapToWriteToDisk.isEmpty()) {
|
||||
if (hasClearListeners) {
|
||||
keysCleared.addAll(mapToWriteToDisk.keySet());
|
||||
}
|
||||
changesMade = true;
|
||||
mapToWriteToDisk.clear();
|
||||
}
|
||||
@@ -569,7 +614,7 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
}
|
||||
}
|
||||
return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners,
|
||||
mapToWriteToDisk);
|
||||
keysCleared, clearListeners, mapToWriteToDisk);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -596,6 +641,7 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
}
|
||||
}
|
||||
notifyListeners(mcr);
|
||||
notifyClearListeners(mcr);
|
||||
return mcr.writeToDiskResult;
|
||||
}
|
||||
|
||||
@@ -618,6 +664,24 @@ final class SharedPreferencesImpl implements SharedPreferences {
|
||||
ActivityThread.sMainThreadHandler.post(() -> notifyListeners(mcr));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyClearListeners(final MemoryCommitResult mcr) {
|
||||
if (mcr.clearListeners == null || mcr.keysCleared == null
|
||||
|| mcr.keysCleared.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
for (OnSharedPreferencesClearListener listener : mcr.clearListeners) {
|
||||
if (listener != null) {
|
||||
listener.onSharedPreferencesClear(SharedPreferencesImpl.this,
|
||||
mcr.keysCleared);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Run this function on the main thread.
|
||||
ActivityThread.sMainThreadHandler.post(() -> notifyClearListeners(mcr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -58,7 +59,9 @@ public interface SharedPreferences {
|
||||
* <p>This callback will be run on your main thread.
|
||||
*
|
||||
* <p><em>Note: This callback will not be triggered when preferences are cleared via
|
||||
* {@link Editor#clear()}.</em>
|
||||
* {@link Editor#clear()}. However, from {@link android.os.Build.VERSION_CODES#R Android R}
|
||||
* onwards, you can use {@link OnSharedPreferencesClearListener} to register for
|
||||
* {@link Editor#clear()} callbacks.</em>
|
||||
*
|
||||
* @param sharedPreferences The {@link SharedPreferences} that received
|
||||
* the change.
|
||||
@@ -67,7 +70,23 @@ public interface SharedPreferences {
|
||||
*/
|
||||
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when shared preferences are cleared.
|
||||
*/
|
||||
public interface OnSharedPreferencesClearListener {
|
||||
/**
|
||||
* Called when shared preferences are cleared via {@link Editor#clear()}.
|
||||
*
|
||||
* <p>This callback will be run on your main thread.
|
||||
*
|
||||
* @param sharedPreferences The {@link SharedPreferences} that received the change.
|
||||
* @param keys The set of keys that were cleared.
|
||||
*/
|
||||
void onSharedPreferencesClear(@NonNull SharedPreferences sharedPreferences,
|
||||
@NonNull Set<String> keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used for modifying values in a {@link SharedPreferences}
|
||||
* object. All changes you make in an editor are batched, and not copied
|
||||
@@ -378,12 +397,43 @@ public interface SharedPreferences {
|
||||
* @see #unregisterOnSharedPreferenceChangeListener
|
||||
*/
|
||||
void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
|
||||
|
||||
|
||||
/**
|
||||
* Unregisters a previous callback.
|
||||
*
|
||||
*
|
||||
* @param listener The callback that should be unregistered.
|
||||
* @see #registerOnSharedPreferenceChangeListener
|
||||
*/
|
||||
void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
|
||||
|
||||
/**
|
||||
* Registers a callback to be invoked when preferences are cleared via {@link Editor#clear()}.
|
||||
*
|
||||
* <p class="caution"><strong>Caution:</strong> The preference manager does
|
||||
* not currently store a strong reference to the listener. You must store a
|
||||
* strong reference to the listener, or it will be susceptible to garbage
|
||||
* collection. We recommend you keep a reference to the listener in the
|
||||
* instance data of an object that will exist as long as you need the
|
||||
* listener.</p>
|
||||
*
|
||||
* @param listener The callback that will run.
|
||||
* @see #unregisterOnSharedPreferencesClearListener
|
||||
*/
|
||||
default void registerOnSharedPreferencesClearListener(
|
||||
@NonNull OnSharedPreferencesClearListener listener) {
|
||||
throw new UnsupportedOperationException(
|
||||
"registerOnSharedPreferencesClearListener not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a previous callback for {@link Editor#clear()}.
|
||||
*
|
||||
* @param listener The callback that should be unregistered.
|
||||
* @see #registerOnSharedPreferencesClearListener
|
||||
*/
|
||||
default void unregisterOnSharedPreferencesClearListener(
|
||||
@NonNull OnSharedPreferencesClearListener listener) {
|
||||
throw new UnsupportedOperationException(
|
||||
"unregisterOnSharedPreferencesClearListener not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user