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

Commit 40093359 authored by Bryce Lee's avatar Bryce Lee
Browse files

Generalize Communal Conditions.

This changelist refactors the communal conditions logic
into a general utility class that can be used in other
contexts.

Test: atest ConditionTest
Test: atest ConditionMonitorTest
Bug: 209197297
Change-Id: I265c4b275d259299982381267a028db8091089b1
parent 2aae2899
Loading
Loading
Loading
Loading
+8 −120
Original line number Diff line number Diff line
@@ -16,139 +16,27 @@

package com.android.systemui.communal.conditions;

import static com.android.systemui.communal.dagger.CommunalModule.COMMUNAL_CONDITIONS;

import android.util.Log;
import static com.android.systemui.communal.dagger.CommunalModule.COMMUNAL_CONDITIONS;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.CallbackController;

import org.jetbrains.annotations.NotNull;
import com.android.systemui.util.condition.Condition;
import com.android.systemui.util.condition.Monitor;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Named;

/**
 * {@link CommunalConditionsMonitor} takes in a set of conditions, monitors whether all of them have
 * been fulfilled, and informs any registered listeners.
 * A concrete implementation of {@Monitor} with conditions for monitoring when communal mode should
 * be enabled.
 */
@SysUISingleton
public class CommunalConditionsMonitor implements
        CallbackController<CommunalConditionsMonitor.Callback> {
    private final String mTag = getClass().getSimpleName();

    private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();

    // Set of all conditions that need to be monitored.
    private final Set<CommunalCondition> mConditions;

    // Map of values of each condition.
    private final HashMap<CommunalCondition, Boolean> mConditionsMap = new HashMap<>();

    // Whether all conditions have been met.
    private boolean mAllConditionsMet = false;

    // Whether the monitor has started listening for all the conditions.
    private boolean mHaveConditionsStarted = false;

    // Callback for when each condition has been updated.
    private final CommunalCondition.Callback mConditionCallback = (condition, isConditionMet) -> {
        mConditionsMap.put(condition, isConditionMet);

        final boolean newAllConditionsMet = !mConditionsMap.containsValue(false);

        if (newAllConditionsMet == mAllConditionsMet) {
            return;
        }

        if (shouldLog()) Log.d(mTag, "all conditions met: " + newAllConditionsMet);
        mAllConditionsMet = newAllConditionsMet;

        // Updates all callbacks.
        final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
        while (iterator.hasNext()) {
            final Callback callback = iterator.next().get();
            if (callback == null) {
                iterator.remove();
            } else {
                callback.onConditionsChanged(mAllConditionsMet);
            }
        }
    };

public class CommunalConditionsMonitor extends Monitor {
    @Inject
    public CommunalConditionsMonitor(
            @Named(COMMUNAL_CONDITIONS) Set<CommunalCondition> communalConditions) {
        mConditions = communalConditions;

        // Initializes the conditions map and registers a callback for each condition.
        mConditions.forEach((condition -> mConditionsMap.put(condition, false)));
    }

    @Override
    public void addCallback(@NotNull Callback callback) {
        if (shouldLog()) Log.d(mTag, "adding callback");
        mCallbacks.add(new WeakReference<>(callback));

        // Updates the callback immediately.
        callback.onConditionsChanged(mAllConditionsMet);

        if (!mHaveConditionsStarted) {
            if (shouldLog()) Log.d(mTag, "starting all conditions");
            mConditions.forEach(condition -> condition.addCallback(mConditionCallback));
            mHaveConditionsStarted = true;
        }
    }

    @Override
    public void removeCallback(@NotNull Callback callback) {
        if (shouldLog()) Log.d(mTag, "removing callback");
        final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
        while (iterator.hasNext()) {
            final Callback cb = iterator.next().get();
            if (cb == null || cb == callback) {
                iterator.remove();
            }
        }

        if (mCallbacks.isEmpty() && mHaveConditionsStarted) {
            if (shouldLog()) Log.d(mTag, "stopping all conditions");
            mConditions.forEach(condition -> condition.removeCallback(mConditionCallback));

            mAllConditionsMet = false;
            mHaveConditionsStarted = false;
        }
    }

    /**
     * Force updates each condition to the value provided.
     */
    @VisibleForTesting
    public void overrideAllConditionsMet(boolean value) {
        mConditions.forEach(condition -> condition.updateCondition(value));
    }

    private boolean shouldLog() {
        return Log.isLoggable(mTag, Log.DEBUG);
    }

    /**
     * Callback that receives updates of whether all conditions have been fulfilled.
     */
    public interface Callback {
        /**
         * Triggered when the fulfillment of all conditions have been met.
         *
         * @param allConditionsMet True if all conditions have been fulfilled. False if none or
         *                         only partial conditions have been fulfilled.
         */
        void onConditionsChanged(boolean allConditionsMet);
            @Named(COMMUNAL_CONDITIONS) Set<Condition> communalConditions) {
        super(communalConditions);
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.provider.Settings;

import androidx.annotation.MainThread;

import com.android.systemui.util.condition.Condition;
import com.android.systemui.util.settings.SecureSettings;

import javax.inject.Inject;
@@ -30,7 +31,7 @@ import javax.inject.Inject;
/**
 * Monitors the communal setting, and informs any listeners with updates.
 */
public class CommunalSettingCondition extends CommunalCondition {
public class CommunalSettingCondition extends Condition {
    private final SecureSettings mSecureSettings;
    private final ContentObserver mCommunalSettingContentObserver;

+2 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.util.Log;
import androidx.annotation.NonNull;

import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.condition.Condition;
import com.android.systemui.util.settings.SecureSettings;

import java.util.Arrays;
@@ -42,7 +43,7 @@ import javax.inject.Inject;
 * Monitors Wi-Fi connections and triggers callback, if any, when the device is connected to and
 * disconnected from a trusted network.
 */
public class CommunalTrustedNetworkCondition extends CommunalCondition {
public class CommunalTrustedNetworkCondition extends Condition {
    private final String mTag = getClass().getSimpleName();
    private final ConnectivityManager mConnectivityManager;
    private final ContentObserver mTrustedNetworksObserver;
+2 −2
Original line number Diff line number Diff line
@@ -28,12 +28,12 @@ import androidx.annotation.Nullable;
import com.android.systemui.R;
import com.android.systemui.communal.CommunalSource;
import com.android.systemui.communal.PackageObserver;
import com.android.systemui.communal.conditions.CommunalCondition;
import com.android.systemui.communal.conditions.CommunalSettingCondition;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.idle.AmbientLightModeMonitor;
import com.android.systemui.idle.LightSensorEventsDebounceAlgorithm;
import com.android.systemui.idle.dagger.IdleViewComponent;
import com.android.systemui.util.condition.Condition;

import java.util.Collections;
import java.util.HashSet;
@@ -99,7 +99,7 @@ public interface CommunalModule {
    @Provides
    @ElementsIntoSet
    @Named(COMMUNAL_CONDITIONS)
    static Set<CommunalCondition> provideCommunalConditions(
    static Set<Condition> provideCommunalConditions(
            CommunalSettingCondition communalSettingCondition) {
        return new HashSet<>(Collections.singletonList(communalSettingCondition));
    }
+5 −4
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

package com.android.systemui.communal.conditions;
package com.android.systemui.util.condition;

import android.util.Log;

@@ -27,9 +27,10 @@ import java.util.ArrayList;
import java.util.Iterator;

/**
 * Base class for a condition that needs to be fulfilled in order for Communal Mode to display.
 * Base class for a condition that needs to be fulfilled in order for {@link Monitor} to inform
 * its callbacks.
 */
public abstract class CommunalCondition implements CallbackController<CommunalCondition.Callback> {
public abstract class Condition implements CallbackController<Condition.Callback> {
    private final String mTag = getClass().getSimpleName();

    private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
@@ -125,6 +126,6 @@ public abstract class CommunalCondition implements CallbackController<CommunalCo
         * @param condition The condition in question.
         * @param isConditionMet True if the condition has been fulfilled. False otherwise.
         */
        void onConditionChanged(CommunalCondition condition, boolean isConditionMet);
        void onConditionChanged(Condition condition, boolean isConditionMet);
    }
}
Loading