Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41220928 authored by Clark Scheff's avatar Clark Scheff Committed by Gerrit Code Review
Browse files

ThemeManager: Synchronize access to listeners

If the Set of listeners is modified while iterating we will get
a ConcurentModificationException so we need to synchronize access
to avoid this.

Change-Id: Ib521ad86a665316d707463200c16c1bcdcfac362
parent a7f86420
Loading
Loading
Loading
Loading
+84 −51
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -56,13 +57,21 @@ public class ThemeManager {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    Iterator<ThemeChangeListener> iterator = mChangeListeners.iterator();
                    while(iterator.hasNext()) {
                    synchronized (mChangeListeners) {
                        List<ThemeChangeListener> listenersToRemove = new ArrayList
                                <ThemeChangeListener>();
                        for (ThemeChangeListener listener : mChangeListeners) {
                            try {
                            iterator.next().onProgress(progress);
                                listener.onProgress(progress);
                            } catch (Throwable e) {
                                Log.w(TAG, "Unable to update theme change progress", e);
                            iterator.remove();
                                listenersToRemove.add(listener);
                            }
                        }
                        if (listenersToRemove.size() > 0) {
                            for (ThemeChangeListener listener : listenersToRemove) {
                                mChangeListeners.remove(listener);
                            }
                        }
                    }
                }
@@ -74,13 +83,21 @@ public class ThemeManager {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    Iterator<ThemeChangeListener> iterator = mChangeListeners.iterator();
                    while(iterator.hasNext()) {
                    synchronized (mChangeListeners) {
                        List<ThemeChangeListener> listenersToRemove = new ArrayList
                                <ThemeChangeListener>();
                        for (ThemeChangeListener listener : mChangeListeners) {
                            try {
                            iterator.next().onFinish(isSuccess);
                                listener.onFinish(isSuccess);
                            } catch (Throwable e) {
                                Log.w(TAG, "Unable to update theme change listener", e);
                            iterator.remove();
                                listenersToRemove.add(listener);
                            }
                        }
                        if (listenersToRemove.size() > 0) {
                            for (ThemeChangeListener listener : listenersToRemove) {
                                mChangeListeners.remove(listener);
                            }
                        }
                    }
                }
@@ -95,13 +112,21 @@ public class ThemeManager {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    Iterator<ThemeProcessingListener> iterator = mProcessingListeners.iterator();
                    while(iterator.hasNext()) {
                    synchronized (mProcessingListeners) {
                        List<ThemeProcessingListener> listenersToRemove = new ArrayList
                                <ThemeProcessingListener>();
                        for (ThemeProcessingListener listener : mProcessingListeners) {
                            try {
                            iterator.next().onFinishedProcessing(pkgName);
                                listener.onFinishedProcessing(pkgName);
                            } catch (Throwable e) {
                                Log.w(TAG, "Unable to update theme change progress", e);
                            iterator.remove();
                                listenersToRemove.add(listener);
                            }
                        }
                        if (listenersToRemove.size() > 0) {
                            for (ThemeProcessingListener listener : listenersToRemove) {
                                mProcessingListeners.remove(listener);
                            }
                        }
                    }
                }
@@ -111,6 +136,7 @@ public class ThemeManager {


    public void addClient(ThemeChangeListener listener) {
        synchronized (mChangeListeners) {
            if (mChangeListeners.contains(listener)) {
                throw new IllegalArgumentException("Client was already added ");
            }
@@ -123,8 +149,10 @@ public class ThemeManager {
            }
            mChangeListeners.add(listener);
        }
    }

    public void removeClient(ThemeChangeListener listener) {
        synchronized (mChangeListeners) {
            mChangeListeners.remove(listener);
            if (mChangeListeners.size() == 0) {
                try {
@@ -134,6 +162,7 @@ public class ThemeManager {
                }
            }
        }
    }

    public void onClientPaused(ThemeChangeListener listener) {
        removeClient(listener);
@@ -152,6 +181,7 @@ public class ThemeManager {
     * @param listener ThemeChangeListener to register
     */
    public void registerProcessingListener(ThemeProcessingListener listener) {
        synchronized (mProcessingListeners) {
            if (mProcessingListeners.contains(listener)) {
                throw new IllegalArgumentException("Listener was already added ");
            }
@@ -164,12 +194,14 @@ public class ThemeManager {
            }
            mProcessingListeners.add(listener);
        }
    }

    /**
     * Unregister a ThemeChangeListener.
     * @param listener ThemeChangeListener to unregister
     */
    public void unregisterProcessingListener(ThemeChangeListener listener) {
        synchronized (mProcessingListeners) {
            mProcessingListeners.remove(listener);
            if (mProcessingListeners.size() == 0) {
                try {
@@ -179,6 +211,7 @@ public class ThemeManager {
                }
            }
        }
    }

    /**
     * Convenience method. Applies the entire theme.