/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content; import android.annotation.NonNull; import android.content.res.Configuration; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * A helper class to manage {@link ComponentCallbacks} and {@link ComponentCallbacks2}, such as * registering ,unregistering {@link ComponentCallbacks} and sending callbacks to all registered * {@link ComponentCallbacks}. * * @see Context#registerComponentCallbacks(ComponentCallbacks) * @see Context#unregisterComponentCallbacks(ComponentCallbacks) * @see ComponentCallbacks * @see ComponentCallbacks2 * * @hide */ public class ComponentCallbacksController { @GuardedBy("mLock") private List mComponentCallbacks; private final Object mLock = new Object(); /** * Register the {@link ComponentCallbacks}. * * @see Context#registerComponentCallbacks(ComponentCallbacks) */ public void registerCallbacks(@NonNull ComponentCallbacks callbacks) { synchronized (mLock) { if (mComponentCallbacks == null) { mComponentCallbacks = new ArrayList<>(); } mComponentCallbacks.add(callbacks); } } /** * Unregister the {@link ComponentCallbacks}. * * @see Context#unregisterComponentCallbacks(ComponentCallbacks) */ public void unregisterCallbacks(@NonNull ComponentCallbacks callbacks) { synchronized (mLock) { if (mComponentCallbacks == null || mComponentCallbacks.isEmpty()) { return; } mComponentCallbacks.remove(callbacks); } } /** * Clear all registered {@link ComponentCallbacks}. * It is useful when the associated {@link Context} is going to be released. */ public void clearCallbacks() { synchronized (mLock) { if (mComponentCallbacks != null) { mComponentCallbacks.clear(); } } } /** * Sending {@link ComponentCallbacks#onConfigurationChanged(Configuration)} to all registered * {@link ComponentCallbacks}. */ public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { forAllComponentCallbacks(callbacks -> callbacks.onConfigurationChanged(newConfig)); } /** * Sending {@link ComponentCallbacks#onLowMemory()} to all registered * {@link ComponentCallbacks}. */ public void dispatchLowMemory() { forAllComponentCallbacks(ComponentCallbacks::onLowMemory); } /** * Sending {@link ComponentCallbacks2#onTrimMemory(int)} to all registered * {@link ComponentCallbacks2}. */ public void dispatchTrimMemory(int level) { forAllComponentCallbacks(callbacks -> { if (callbacks instanceof ComponentCallbacks2) { ((ComponentCallbacks2) callbacks).onTrimMemory(level); } }); } private void forAllComponentCallbacks(Consumer callbacksConsumer) { final ComponentCallbacks[] callbacksArray; synchronized (mLock) { if (mComponentCallbacks == null || mComponentCallbacks.isEmpty()) { return; } callbacksArray = new ComponentCallbacks[mComponentCallbacks.size()]; mComponentCallbacks.toArray(callbacksArray); } for (ComponentCallbacks callbacks : callbacksArray) { callbacksConsumer.accept(callbacks); } } }