Defensively copy callback collections before invoking
This is done in order to prevent ConcurrentModificationExceptions, caused by the callback unregistering itself when invoked. The pattern used by this CL is also used by StatusBarStateControllerImpl. Fixes: 192192372 Test: manual Change-Id: Ibac2282d5c9242ae063adb2247d4297291fa3abf Merged-In: Ibac2282d5c9242ae063adb2247d4297291fa3abf
This commit is contained in:
@@ -87,7 +87,7 @@ public class KeyguardBouncer {
|
||||
private final Runnable mResetRunnable = ()-> {
|
||||
if (mKeyguardViewController != null) {
|
||||
mKeyguardViewController.resetSecurityContainer();
|
||||
for (KeyguardResetCallback callback : mResetCallbacks) {
|
||||
for (KeyguardResetCallback callback : new ArrayList<>(mResetCallbacks)) {
|
||||
callback.onKeyguardReset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,16 +55,18 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -100,7 +102,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
|
||||
private ForcePluginOpenListener mForcePluginOpenListener;
|
||||
private Consumer<Integer> mScrimsVisibilityListener;
|
||||
private final ArrayList<WeakReference<StatusBarWindowCallback>>
|
||||
mCallbacks = Lists.newArrayList();
|
||||
mCallbacks = new ArrayList<>();
|
||||
|
||||
private final SysuiColorExtractor mColorExtractor;
|
||||
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
|
||||
@@ -464,13 +466,15 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
|
||||
|
||||
@Override
|
||||
public void notifyStateChangedCallbacks() {
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
StatusBarWindowCallback cb = mCallbacks.get(i).get();
|
||||
if (cb != null) {
|
||||
cb.onStateChanged(mCurrentState.mKeyguardShowing,
|
||||
mCurrentState.mKeyguardOccluded,
|
||||
mCurrentState.mBouncerShowing);
|
||||
}
|
||||
// Copy callbacks to separate ArrayList to avoid concurrent modification
|
||||
List<StatusBarWindowCallback> activeCallbacks = mCallbacks.stream()
|
||||
.map(Reference::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
for (StatusBarWindowCallback cb : activeCallbacks) {
|
||||
cb.onStateChanged(mCurrentState.mKeyguardShowing,
|
||||
mCurrentState.mKeyguardOccluded,
|
||||
mCurrentState.mBouncerShowing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
@@ -157,7 +158,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
|
||||
NotificationPeekEvent.NOTIFICATION_PEEK, entry.getSbn().getUid(),
|
||||
entry.getSbn().getPackageName(), entry.getSbn().getInstanceId());
|
||||
}
|
||||
for (OnHeadsUpChangedListener listener : mListeners) {
|
||||
for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
|
||||
if (isPinned) {
|
||||
listener.onHeadsUpPinned(entry);
|
||||
} else {
|
||||
@@ -177,7 +178,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
|
||||
entry.setHeadsUp(true);
|
||||
setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
|
||||
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 1 /* visible */);
|
||||
for (OnHeadsUpChangedListener listener : mListeners) {
|
||||
for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
|
||||
listener.onHeadsUpStateChanged(entry, true);
|
||||
}
|
||||
}
|
||||
@@ -188,7 +189,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
|
||||
entry.setHeadsUp(false);
|
||||
setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */);
|
||||
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 0 /* visible */);
|
||||
for (OnHeadsUpChangedListener listener : mListeners) {
|
||||
for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
|
||||
listener.onHeadsUpStateChanged(entry, false);
|
||||
}
|
||||
}
|
||||
@@ -206,7 +207,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
|
||||
if (mHasPinnedNotification) {
|
||||
MetricsLogger.count(mContext, "note_peek", 1);
|
||||
}
|
||||
for (OnHeadsUpChangedListener listener : mListeners) {
|
||||
for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
|
||||
listener.onHeadsUpPinnedModeChanged(hasPinnedNotification);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,7 +807,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
||||
}
|
||||
|
||||
private void onEditTextFocusChanged(RemoteEditText remoteEditText, boolean focused) {
|
||||
for (View.OnFocusChangeListener listener : mEditTextFocusChangeListeners) {
|
||||
for (View.OnFocusChangeListener listener : new ArrayList<>(mEditTextFocusChangeListeners)) {
|
||||
listener.onFocusChange(remoteEditText, focused);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user