// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.download;
import androidx.annotation.Nullable;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import java.util.HashSet;
import java.util.Set;
/**
* A class that handles logic related to observers that are waiting to see when the
* DownloadsForegroundService is shutting down or starting back up.
*/
public final class DownloadForegroundServiceObservers {
private static final String TAG = "DownloadFgServiceObs";
/**
* An Observer interfaces that allows other classes to know when this service is shutting down.
* Implementing classes must be marked as @UsedByReflection in order to prevent the class name
* from being obfuscated.
* Implementing classes must also have a public parameterless constructor that is marked as
* @UsedByReflection.
* Implementing classes may never be renamed, as class names are persisted between app updates.
*/
public interface Observer {
/** Called when any task (service or activity) is removed from the service's application. */
void onForegroundServiceTaskRemoved();
/**
* Called when the foreground service is destroyed.
*
*/
void onForegroundServiceDestroyed();
}
/**
* Adds an observer, which will be notified when this service attempts to start stopping itself.
* @param observerClass to be added to the list of observers in SharedPrefs.
*/
public static void addObserver(Class<? extends Observer> observerClass) {
ThreadUtils.assertOnUiThread();
Set<String> observers = getAllObservers();
String observerClassName = observerClass.getName();
if (observers.contains(observerClassName)) return;
// Set returned from getStringSet() should not be modified.
observers = new HashSet<>(observers);
observers.add(observerClassName);
ChromeSharedPreferences.getInstance()
.writeStringSet(
ChromePreferenceKeys.DOWNLOAD_FOREGROUND_SERVICE_OBSERVERS, observers);
}
/**
* Removes observer, which will no longer be notified when this class starts stopping itself.
* @param observerClass to be removed from the list of observers in SharedPrefs.
*/
public static void removeObserver(Class<? extends Observer> observerClass) {
ThreadUtils.assertOnUiThread();
Set<String> observers = getAllObservers();
String observerClassName = observerClass.getName();
if (!observers.contains(observerClassName)) return;
// Set returned from getStringSet() should not be modified.
observers = new HashSet<>(observers);
observers.remove(observerClassName);
// Clear observer list if there are none.
if (observers.size() == 0) {
removeAllObservers();
return;
}
ChromeSharedPreferences.getInstance()
.writeStringSet(
ChromePreferenceKeys.DOWNLOAD_FOREGROUND_SERVICE_OBSERVERS, observers);
}
static void alertObserversServiceDestroyed() {
Set<String> observers = getAllObservers();
for (String observerClassName : observers) {
DownloadForegroundServiceObservers.Observer observer =
DownloadForegroundServiceObservers.getObserverFromClassName(observerClassName);
if (observer != null) observer.onForegroundServiceDestroyed();
}
}
static void alertObserversTaskRemoved() {
Set<String> observers = getAllObservers();
for (String observerClassName : observers) {
Observer observer = getObserverFromClassName(observerClassName);
if (observer != null) observer.onForegroundServiceTaskRemoved();
}
}
private static Set<String> getAllObservers() {
return ChromeSharedPreferences.getInstance()
.readStringSet(ChromePreferenceKeys.DOWNLOAD_FOREGROUND_SERVICE_OBSERVERS);
}
private static void removeAllObservers() {
ChromeSharedPreferences.getInstance()
.removeKey(ChromePreferenceKeys.DOWNLOAD_FOREGROUND_SERVICE_OBSERVERS);
}
private static @Nullable Observer getObserverFromClassName(String observerClassName) {
try {
Class<?> observerClass = Class.forName(observerClassName);
return (Observer) observerClass.newInstance();
} catch (Throwable e) {
Log.w(TAG, "getObserverFromClassName(): %s", observerClassName, e);
return null;
}
}
}