Merge changes Ib975d5a7,Idcc93f9e,Ibc0f30d4,I5b09ec1d

* changes:
  Check whether a Wi-Fi network is trusted.
  Introduce communal trusted network condition.
  Introduce communal setting condition.
  Introduction to communal conditions monitor.
This commit is contained in:
Darrell Shi
2021-12-02 00:28:49 +00:00
committed by Android (Google) Code Review
12 changed files with 1256 additions and 70 deletions

View File

@@ -16,17 +16,11 @@
package com.android.systemui.communal;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import androidx.annotation.MainThread;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.communal.conditions.CommunalConditionsMonitor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.util.settings.SecureSettings;
import com.google.android.collect.Lists;
@@ -46,10 +40,15 @@ public class CommunalSourceMonitor {
// A list of {@link Callback} that have registered to receive updates.
private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
private final SecureSettings mSecureSettings;
private final CommunalConditionsMonitor mConditionsMonitor;
private CommunalSource mCurrentSource;
private boolean mCommunalEnabled;
// Whether all conditions for communal mode to show have been met.
private boolean mAllCommunalConditionsMet = false;
// Whether the class is currently listening for condition changes.
private boolean mListeningForConditions = false;
private CommunalSource.Callback mSourceCallback = new CommunalSource.Callback() {
@Override
@@ -59,24 +58,20 @@ public class CommunalSourceMonitor {
}
};
private final CommunalConditionsMonitor.Callback mConditionsCallback =
allConditionsMet -> {
if (mAllCommunalConditionsMet != allConditionsMet) {
if (DEBUG) Log.d(TAG, "communal conditions changed: " + allConditionsMet);
mAllCommunalConditionsMet = allConditionsMet;
executeOnSourceAvailableCallbacks();
}
};
@VisibleForTesting
@Inject
public CommunalSourceMonitor(
@MainThread Handler mainThreadHandler,
SecureSettings secureSettings) {
mSecureSettings = secureSettings;
ContentObserver settingsObserver = new ContentObserver(mainThreadHandler) {
@Override
public void onChange(boolean selfChange) {
reloadSettings();
}
};
mSecureSettings.registerContentObserverForUser(
Settings.Secure.COMMUNAL_MODE_ENABLED,
/* notifyForDescendants= */false,
settingsObserver, UserHandle.USER_SYSTEM);
reloadSettings();
public CommunalSourceMonitor(CommunalConditionsMonitor communalConditionsMonitor) {
mConditionsMonitor = communalConditionsMonitor;
}
/**
@@ -92,7 +87,7 @@ public class CommunalSourceMonitor {
mCurrentSource = source;
if (mCommunalEnabled) {
if (mAllCommunalConditionsMet) {
executeOnSourceAvailableCallbacks();
}
@@ -111,7 +106,7 @@ public class CommunalSourceMonitor {
itr.remove();
} else {
cb.onSourceAvailable(
(mCommunalEnabled && mCurrentSource != null) ? new WeakReference<>(
(mAllCommunalConditionsMet && mCurrentSource != null) ? new WeakReference<>(
mCurrentSource) : null);
}
}
@@ -126,9 +121,14 @@ public class CommunalSourceMonitor {
mCallbacks.add(new WeakReference<>(callback));
// Inform the callback of any already present CommunalSource.
if (mCommunalEnabled && mCurrentSource != null) {
if (mAllCommunalConditionsMet && mCurrentSource != null) {
callback.onSourceAvailable(new WeakReference<>(mCurrentSource));
}
if (!mListeningForConditions) {
mConditionsMonitor.addCallback(mConditionsCallback);
mListeningForConditions = true;
}
}
/**
@@ -138,21 +138,10 @@ public class CommunalSourceMonitor {
*/
public void removeCallback(Callback callback) {
mCallbacks.removeIf(el -> el.get() == callback);
}
private void reloadSettings() {
boolean newCommunalEnabled = mSecureSettings.getIntForUser(
Settings.Secure.COMMUNAL_MODE_ENABLED,
1,
UserHandle.USER_SYSTEM) == 1;
if (DEBUG) {
Log.d(TAG, "communal mode settings reloaded with value:" + newCommunalEnabled);
}
if (mCommunalEnabled != newCommunalEnabled) {
mCommunalEnabled = newCommunalEnabled;
executeOnSourceAvailableCallbacks();
if (mCallbacks.isEmpty() && mListeningForConditions) {
mConditionsMonitor.removeCallback(mConditionsCallback);
mListeningForConditions = false;
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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 com.android.systemui.communal.conditions;
import android.util.Log;
import com.android.systemui.statusbar.policy.CallbackController;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.WeakReference;
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.
*/
public abstract class CommunalCondition implements CallbackController<CommunalCondition.Callback> {
private final String mTag = getClass().getSimpleName();
private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
private boolean mIsConditionMet = false;
private boolean mStarted = false;
/**
* Starts monitoring the condition.
*/
protected abstract void start();
/**
* Stops monitoring the condition.
*/
protected abstract void stop();
/**
* Registers a callback to receive updates once started. This should be called before
* {@link #start()}. Also triggers the callback immediately if already started.
*/
@Override
public void addCallback(@NotNull Callback callback) {
if (shouldLog()) Log.d(mTag, "adding callback");
mCallbacks.add(new WeakReference<>(callback));
if (mStarted) {
callback.onConditionChanged(this, mIsConditionMet);
return;
}
start();
mStarted = true;
}
/**
* Removes the provided callback from further receiving updates.
*/
@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() || !mStarted) {
return;
}
stop();
mStarted = false;
}
/**
* Updates the value for whether the condition has been fulfilled, and sends an update if the
* value changes and any callback is registered.
*
* @param isConditionMet True if the condition has been fulfilled. False otherwise.
*/
protected void updateCondition(boolean isConditionMet) {
if (mIsConditionMet == isConditionMet) {
return;
}
if (shouldLog()) Log.d(mTag, "updating condition to " + isConditionMet);
mIsConditionMet = isConditionMet;
final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
while (iterator.hasNext()) {
final Callback cb = iterator.next().get();
if (cb == null) {
iterator.remove();
} else {
cb.onConditionChanged(this, mIsConditionMet);
}
}
}
private boolean shouldLog() {
return Log.isLoggable(mTag, Log.DEBUG);
}
/**
* Callback that receives updates about whether the condition has been fulfilled.
*/
public interface Callback {
/**
* Called when the fulfillment of the condition changes.
*
* @param condition The condition in question.
* @param isConditionMet True if the condition has been fulfilled. False otherwise.
*/
void onConditionChanged(CommunalCondition condition, boolean isConditionMet);
}
}

View File

@@ -0,0 +1,154 @@
/*
* 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 com.android.systemui.communal.conditions;
import static com.android.systemui.communal.dagger.CommunalModule.COMMUNAL_CONDITIONS;
import android.util.Log;
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 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.
*/
@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);
}
}
};
@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);
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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 com.android.systemui.communal.conditions;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.annotation.MainThread;
import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
/**
* Monitors the communal setting, and informs any listeners with updates.
*/
public class CommunalSettingCondition extends CommunalCondition {
private final SecureSettings mSecureSettings;
private final ContentObserver mCommunalSettingContentObserver;
@Inject
public CommunalSettingCondition(@MainThread Handler mainHandler,
SecureSettings secureSettings) {
mSecureSettings = secureSettings;
mCommunalSettingContentObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange) {
final boolean communalSettingEnabled = mSecureSettings.getIntForUser(
Settings.Secure.COMMUNAL_MODE_ENABLED, 0, UserHandle.USER_SYSTEM) == 1;
updateCondition(communalSettingEnabled);
}
};
}
@Override
protected void start() {
mSecureSettings.registerContentObserverForUser(Settings.Secure.COMMUNAL_MODE_ENABLED,
false /*notifyForDescendants*/, mCommunalSettingContentObserver,
UserHandle.USER_SYSTEM);
// Fetches setting immediately.
mCommunalSettingContentObserver.onChange(false);
}
@Override
protected void stop() {
mSecureSettings.unregisterContentObserver(mCommunalSettingContentObserver);
}
}

View File

@@ -0,0 +1,189 @@
/*
* 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 com.android.systemui.communal.conditions;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.WifiInfo;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.settings.SecureSettings;
import java.util.Arrays;
import java.util.HashSet;
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 {
private final String mTag = getClass().getSimpleName();
private final ConnectivityManager mConnectivityManager;
private final ContentObserver mTrustedNetworksObserver;
private final SecureSettings mSecureSettings;
// The SSID of the connected Wi-Fi network. Null if not connected to Wi-Fi.
private String mWifiSSID;
// Set of SSIDs of trusted networks.
private final HashSet<String> mTrustedNetworks = new HashSet<>();
/**
* The deliminator used to separate trusted network keys saved as a string in secure settings.
*/
public static final String SETTINGS_STRING_DELIMINATOR = ",/";
@Inject
public CommunalTrustedNetworkCondition(@Main Handler handler,
ConnectivityManager connectivityManager, SecureSettings secureSettings) {
mConnectivityManager = connectivityManager;
mSecureSettings = secureSettings;
mTrustedNetworksObserver = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange) {
fetchTrustedNetworks();
}
};
}
/**
* Starts monitoring for trusted network connection. Ignores if already started.
*/
@Override
protected void start() {
if (shouldLog()) Log.d(mTag, "start listening for wifi connections");
fetchTrustedNetworks();
final NetworkRequest wifiNetworkRequest = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
mConnectivityManager.registerNetworkCallback(wifiNetworkRequest, mNetworkCallback);
mSecureSettings.registerContentObserverForUser(
Settings.Secure.COMMUNAL_MODE_TRUSTED_NETWORKS, false, mTrustedNetworksObserver,
UserHandle.USER_SYSTEM);
}
/**
* Stops monitoring for trusted network connection.
*/
@Override
protected void stop() {
if (shouldLog()) Log.d(mTag, "stop listening for wifi connections");
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mSecureSettings.unregisterContentObserver(mTrustedNetworksObserver);
}
private void updateWifiInfo(WifiInfo wifiInfo) {
if (wifiInfo == null) {
mWifiSSID = null;
} else {
// Remove the wrapping quotes around the SSID.
mWifiSSID = wifiInfo.getSSID().replace("\"", "");
}
checkIfConnectedToTrustedNetwork();
}
private void fetchTrustedNetworks() {
final String trustedNetworksString = mSecureSettings.getStringForUser(
Settings.Secure.COMMUNAL_MODE_TRUSTED_NETWORKS, UserHandle.USER_SYSTEM);
mTrustedNetworks.clear();
if (shouldLog()) Log.d(mTag, "fetched trusted networks: " + trustedNetworksString);
if (TextUtils.isEmpty(trustedNetworksString)) {
return;
}
mTrustedNetworks.addAll(
Arrays.asList(trustedNetworksString.split(SETTINGS_STRING_DELIMINATOR)));
checkIfConnectedToTrustedNetwork();
}
private void checkIfConnectedToTrustedNetwork() {
final boolean connectedToTrustedNetwork = mWifiSSID != null && mTrustedNetworks.contains(
mWifiSSID);
if (shouldLog()) {
Log.d(mTag, (connectedToTrustedNetwork ? "connected to" : "disconnected from")
+ " a trusted network");
}
updateCondition(connectedToTrustedNetwork);
}
private final ConnectivityManager.NetworkCallback mNetworkCallback =
new ConnectivityManager.NetworkCallback(
ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) {
private boolean mIsConnected = false;
private WifiInfo mWifiInfo;
@Override
public void onAvailable(@NonNull Network network) {
super.onAvailable(network);
if (shouldLog()) Log.d(mTag, "connected to wifi");
mIsConnected = true;
if (mWifiInfo != null) {
updateWifiInfo(mWifiInfo);
}
}
@Override
public void onLost(@NonNull Network network) {
super.onLost(network);
if (shouldLog()) Log.d(mTag, "disconnected from wifi");
mIsConnected = false;
mWifiInfo = null;
updateWifiInfo(null);
}
@Override
public void onCapabilitiesChanged(@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
mWifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
if (mIsConnected) {
updateWifiInfo(mWifiInfo);
}
}
};
private boolean shouldLog() {
return Log.isLoggable(mTag, Log.DEBUG);
}
}

View File

@@ -20,15 +20,23 @@ import android.content.Context;
import android.view.View;
import android.widget.FrameLayout;
import com.android.systemui.communal.conditions.CommunalCondition;
import com.android.systemui.communal.conditions.CommunalSettingCondition;
import com.android.systemui.communal.conditions.CommunalTrustedNetworkCondition;
import com.android.systemui.idle.AmbientLightModeMonitor;
import com.android.systemui.idle.LightSensorEventsDebounceAlgorithm;
import com.android.systemui.idle.dagger.IdleViewComponent;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Named;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.ElementsIntoSet;
/**
* Dagger Module providing Communal-related functionality.
@@ -39,6 +47,7 @@ import dagger.Provides;
})
public interface CommunalModule {
String IDLE_VIEW = "idle_view";
String COMMUNAL_CONDITIONS = "communal_conditions";
/** */
@Provides
@@ -56,4 +65,17 @@ public interface CommunalModule {
@Binds
AmbientLightModeMonitor.DebounceAlgorithm ambientLightDebounceAlgorithm(
LightSensorEventsDebounceAlgorithm algorithm);
/**
* Provides a set of conditions that need to be fulfilled in order for Communal Mode to display.
*/
@Provides
@ElementsIntoSet
@Named(COMMUNAL_CONDITIONS)
static Set<CommunalCondition> provideCommunalConditions(
CommunalSettingCondition communalSettingCondition,
CommunalTrustedNetworkCondition communalTrustedNetworkCondition) {
return new HashSet<>(
Arrays.asList(communalSettingCondition, communalTrustedNetworkCondition));
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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 com.android.systemui.communal;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.conditions.CommunalCondition;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalConditionTest extends SysuiTestCase {
private FakeCommunalCondition mCondition;
@Before
public void setup() {
mCondition = spy(new FakeCommunalCondition());
}
@Test
public void addCallback_addFirstCallback_triggerStart() {
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
verify(mCondition).start();
}
@Test
public void addCallback_addMultipleCallbacks_triggerStartOnlyOnce() {
final CommunalCondition.Callback callback1 = mock(CommunalCondition.Callback.class);
final CommunalCondition.Callback callback2 = mock(CommunalCondition.Callback.class);
final CommunalCondition.Callback callback3 = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback1);
mCondition.addCallback(callback2);
mCondition.addCallback(callback3);
verify(mCondition, times(1)).start();
}
@Test
public void addCallback_alreadyStarted_triggerUpdate() {
final CommunalCondition.Callback callback1 = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback1);
mCondition.fakeUpdateCondition(true);
final CommunalCondition.Callback callback2 = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback2);
verify(callback2).onConditionChanged(mCondition, true);
}
@Test
public void removeCallback_removeLastCallback_triggerStop() {
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
verify(mCondition, never()).stop();
mCondition.removeCallback(callback);
verify(mCondition).stop();
}
@Test
public void updateCondition_falseToTrue_reportTrue() {
mCondition.fakeUpdateCondition(false);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(true);
verify(callback).onConditionChanged(eq(mCondition), eq(true));
}
@Test
public void updateCondition_trueToFalse_reportFalse() {
mCondition.fakeUpdateCondition(true);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(false);
verify(callback).onConditionChanged(eq(mCondition), eq(false));
}
@Test
public void updateCondition_trueToTrue_reportNothing() {
mCondition.fakeUpdateCondition(true);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(true);
verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
}
@Test
public void updateCondition_falseToFalse_reportNothing() {
mCondition.fakeUpdateCondition(false);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(false);
verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
}
}

View File

@@ -0,0 +1,178 @@
/*
* 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 com.android.systemui.communal;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.conditions.CommunalCondition;
import com.android.systemui.communal.conditions.CommunalConditionsMonitor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.HashSet;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalConditionsMonitorTest extends SysuiTestCase {
private FakeCommunalCondition mCondition1;
private FakeCommunalCondition mCondition2;
private FakeCommunalCondition mCondition3;
private HashSet<CommunalCondition> mConditions;
private CommunalConditionsMonitor mCommunalConditionsMonitor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mCondition1 = spy(new FakeCommunalCondition());
mCondition2 = spy(new FakeCommunalCondition());
mCondition3 = spy(new FakeCommunalCondition());
mConditions = new HashSet<>(Arrays.asList(mCondition1, mCondition2, mCondition3));
mCommunalConditionsMonitor = new CommunalConditionsMonitor(mConditions);
}
@Test
public void addCallback_addFirstCallback_addCallbackToAllConditions() {
final CommunalConditionsMonitor.Callback callback1 =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback1);
mConditions.forEach(condition -> verify(condition).addCallback(any()));
final CommunalConditionsMonitor.Callback callback2 =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback2);
mConditions.forEach(condition -> verify(condition, times(1)).addCallback(any()));
}
@Test
public void addCallback_addFirstCallback_reportWithDefaultValue() {
final CommunalConditionsMonitor.Callback callback =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback);
verify(callback).onConditionsChanged(false);
}
@Test
public void addCallback_addSecondCallback_reportWithExistingValue() {
final CommunalConditionsMonitor.Callback callback1 =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback1);
mCommunalConditionsMonitor.overrideAllConditionsMet(true);
final CommunalConditionsMonitor.Callback callback2 =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback2);
verify(callback2).onConditionsChanged(true);
}
@Test
public void removeCallback_shouldNoLongerReceiveUpdate() {
final CommunalConditionsMonitor.Callback callback =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback);
clearInvocations(callback);
mCommunalConditionsMonitor.removeCallback(callback);
mCommunalConditionsMonitor.overrideAllConditionsMet(true);
verify(callback, never()).onConditionsChanged(true);
mCommunalConditionsMonitor.overrideAllConditionsMet(false);
verify(callback, never()).onConditionsChanged(false);
}
@Test
public void removeCallback_removeLastCallback_removeCallbackFromAllConditions() {
final CommunalConditionsMonitor.Callback callback1 =
mock(CommunalConditionsMonitor.Callback.class);
final CommunalConditionsMonitor.Callback callback2 =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback1);
mCommunalConditionsMonitor.addCallback(callback2);
mCommunalConditionsMonitor.removeCallback(callback1);
mConditions.forEach(condition -> verify(condition, never()).removeCallback(any()));
mCommunalConditionsMonitor.removeCallback(callback2);
mConditions.forEach(condition -> verify(condition).removeCallback(any()));
}
@Test
public void updateCallbacks_allConditionsMet_reportTrue() {
final CommunalConditionsMonitor.Callback callback =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback);
clearInvocations(callback);
mCondition1.fakeUpdateCondition(true);
mCondition2.fakeUpdateCondition(true);
mCondition3.fakeUpdateCondition(true);
verify(callback).onConditionsChanged(true);
}
@Test
public void updateCallbacks_oneConditionStoppedMeeting_reportFalse() {
final CommunalConditionsMonitor.Callback callback =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback);
mCondition1.fakeUpdateCondition(true);
mCondition2.fakeUpdateCondition(true);
mCondition3.fakeUpdateCondition(true);
clearInvocations(callback);
mCondition1.fakeUpdateCondition(false);
verify(callback).onConditionsChanged(false);
}
@Test
public void updateCallbacks_shouldOnlyUpdateWhenValueChanges() {
final CommunalConditionsMonitor.Callback callback =
mock(CommunalConditionsMonitor.Callback.class);
mCommunalConditionsMonitor.addCallback(callback);
verify(callback).onConditionsChanged(false);
clearInvocations(callback);
mCondition1.fakeUpdateCondition(true);
verify(callback, never()).onConditionsChanged(anyBoolean());
mCondition2.fakeUpdateCondition(true);
verify(callback, never()).onConditionsChanged(anyBoolean());
mCondition3.fakeUpdateCondition(true);
verify(callback).onConditionsChanged(true);
}
}

View File

@@ -0,0 +1,114 @@
/*
* 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 com.android.systemui.communal;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.conditions.CommunalCondition;
import com.android.systemui.communal.conditions.CommunalSettingCondition;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.utils.os.FakeHandler;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalSettingConditionTest extends SysuiTestCase {
private FakeSettings mSecureSettings;
private CommunalSettingCondition mCondition;
@Before
public void setup() {
final FakeHandler handler = new FakeHandler(Looper.getMainLooper());
mSecureSettings = new FakeSettings();
mCondition = new CommunalSettingCondition(handler, mSecureSettings);
}
@Test
public void addCallback_communalSettingEnabled_immediatelyReportsTrue() {
updateCommunalSetting(true);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
verify(callback).onConditionChanged(mCondition, true);
}
@Test
public void addCallback_communalSettingDisabled_noReport() {
updateCommunalSetting(false);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
}
@Test
public void updateCallback_communalSettingEnabled_reportsTrue() {
updateCommunalSetting(false);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
clearInvocations(callback);
updateCommunalSetting(true);
verify(callback).onConditionChanged(mCondition, true);
}
@Test
public void updateCallback_communalSettingDisabled_reportsFalse() {
updateCommunalSetting(true);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
clearInvocations(callback);
updateCommunalSetting(false);
verify(callback).onConditionChanged(mCondition, false);
}
@Test
public void updateCallback_communalSettingDidNotChange_neverReportDup() {
updateCommunalSetting(true);
final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class);
mCondition.addCallback(callback);
clearInvocations(callback);
updateCommunalSetting(true);
verify(callback, never()).onConditionChanged(mCondition, true);
}
private void updateCommunalSetting(boolean value) {
mSecureSettings.putIntForUser(Settings.Secure.COMMUNAL_MODE_ENABLED, value ? 1 : 0,
UserHandle.USER_SYSTEM);
}
}

View File

@@ -20,25 +20,25 @@ package com.android.systemui.communal;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.communal.conditions.CommunalConditionsMonitor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.lang.ref.WeakReference;
@@ -47,15 +47,16 @@ import java.lang.ref.WeakReference;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class CommunalSourceMonitorTest extends SysuiTestCase {
@Mock private CommunalConditionsMonitor mCommunalConditionsMonitor;
@Captor private ArgumentCaptor<CommunalConditionsMonitor.Callback> mConditionsCallbackCaptor;
private CommunalSourceMonitor mCommunalSourceMonitor;
private FakeSettings mSecureSettings;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mSecureSettings = new FakeSettings();
mCommunalSourceMonitor = new CommunalSourceMonitor(
Handler.createAsync(TestableLooper.get(this).getLooper()), mSecureSettings);
mCommunalSourceMonitor = new CommunalSourceMonitor(mCommunalConditionsMonitor);
}
@Test
@@ -65,6 +66,7 @@ public class CommunalSourceMonitorTest extends SysuiTestCase {
mCommunalSourceMonitor.setSource(source);
mCommunalSourceMonitor.addCallback(callback);
setConditionsMet(true);
verifyOnSourceAvailableCalledWith(callback, source);
}
@@ -82,33 +84,32 @@ public class CommunalSourceMonitorTest extends SysuiTestCase {
}
@Test
public void testAddCallbackWithDefaultSetting() {
public void testAddCallbackWithConditionsMet() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
setConditionsMet(true);
clearInvocations(callback);
mCommunalSourceMonitor.setSource(source);
verifyOnSourceAvailableCalledWith(callback, source);
}
@Test
public void testAddCallbackWithSettingDisabled() {
setCommunalEnabled(false);
public void testAddCallbackWithConditionsNotMet() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
setConditionsMet(false);
mCommunalSourceMonitor.setSource(source);
verify(callback, never()).onSourceAvailable(any());
}
@Test
public void testSettingEnabledAfterCallbackAdded() {
setCommunalEnabled(false);
public void testConditionsAreMetAfterCallbackAdded() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
@@ -118,33 +119,27 @@ public class CommunalSourceMonitorTest extends SysuiTestCase {
// The callback should not have executed since communal is disabled.
verify(callback, never()).onSourceAvailable(any());
// The callback should execute when the user changes the setting to enabled.
setCommunalEnabled(true);
// The callback should execute when all conditions are met.
setConditionsMet(true);
verifyOnSourceAvailableCalledWith(callback, source);
}
@Test
public void testSettingDisabledAfterCallbackAdded() {
public void testConditionsNoLongerMetAfterCallbackAdded() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
mCommunalSourceMonitor.setSource(source);
setConditionsMet(true);
verifyOnSourceAvailableCalledWith(callback, source);
// The callback should execute again when the setting is disabled, with a value of null.
setCommunalEnabled(false);
// The callback should execute again when conditions are no longer met, with a value of
// null.
setConditionsMet(false);
verify(callback).onSourceAvailable(null);
}
private void setCommunalEnabled(boolean enabled) {
mSecureSettings.putIntForUser(
Settings.Secure.COMMUNAL_MODE_ENABLED,
enabled ? 1 : 0,
UserHandle.USER_SYSTEM);
TestableLooper.get(this).processAllMessages();
}
private void verifyOnSourceAvailableCalledWith(CommunalSourceMonitor.Callback callback,
CommunalSource source) {
final ArgumentCaptor<WeakReference<CommunalSource>> sourceCapture =
@@ -152,4 +147,13 @@ public class CommunalSourceMonitorTest extends SysuiTestCase {
verify(callback).onSourceAvailable(sourceCapture.capture());
assertThat(sourceCapture.getValue().get()).isEqualTo(source);
}
// Pushes an update on whether the communal conditions are met, assuming that a callback has
// been registered with the communal conditions monitor.
private void setConditionsMet(boolean value) {
verify(mCommunalConditionsMonitor).addCallback(mConditionsCallbackCaptor.capture());
final CommunalConditionsMonitor.Callback conditionsCallback =
mConditionsCallbackCaptor.getValue();
conditionsCallback.onConditionsChanged(value);
}
}

View File

@@ -0,0 +1,172 @@
/*
* 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 com.android.systemui.communal;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.WifiInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.conditions.CommunalTrustedNetworkCondition;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.utils.os.FakeHandler;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalTrustedNetworkConditionTest extends SysuiTestCase {
@Mock private ConnectivityManager mConnectivityManager;
@Captor private ArgumentCaptor<ConnectivityManager.NetworkCallback> mNetworkCallbackCaptor;
private final Handler mHandler = new FakeHandler(Looper.getMainLooper());
private CommunalTrustedNetworkCondition mCondition;
private final String mTrustedWifi1 = "wifi-1";
private final String mTrustedWifi2 = "wifi-2";
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
final FakeSettings secureSettings = new FakeSettings();
secureSettings.putStringForUser(Settings.Secure.COMMUNAL_MODE_TRUSTED_NETWORKS,
mTrustedWifi1 + CommunalTrustedNetworkCondition.SETTINGS_STRING_DELIMINATOR
+ mTrustedWifi2, UserHandle.USER_SYSTEM);
mCondition = new CommunalTrustedNetworkCondition(mHandler, mConnectivityManager,
secureSettings);
}
@Test
public void updateCallback_connectedToTrustedNetwork_reportsTrue() {
final CommunalTrustedNetworkCondition.Callback callback =
mock(CommunalTrustedNetworkCondition.Callback.class);
mCondition.addCallback(callback);
final ConnectivityManager.NetworkCallback networkCallback = captureNetworkCallback();
// Connected to trusted Wi-Fi network.
final Network network = mock(Network.class);
networkCallback.onAvailable(network);
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi1));
// Verifies that the callback is triggered.
verify(callback).onConditionChanged(mCondition, true);
}
@Test
public void updateCallback_switchedToAnotherTrustedNetwork_reportsNothing() {
final CommunalTrustedNetworkCondition.Callback callback =
mock(CommunalTrustedNetworkCondition.Callback.class);
mCondition.addCallback(callback);
final ConnectivityManager.NetworkCallback networkCallback = captureNetworkCallback();
// Connected to a trusted Wi-Fi network.
final Network network = mock(Network.class);
networkCallback.onAvailable(network);
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi1));
clearInvocations(callback);
// Connected to another trusted Wi-Fi network.
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi2));
// Verifies that the callback is not triggered.
verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
}
@Test
public void updateCallback_connectedToNonTrustedNetwork_reportsFalse() {
final CommunalTrustedNetworkCondition.Callback callback =
mock(CommunalTrustedNetworkCondition.Callback.class);
mCondition.addCallback(callback);
final ConnectivityManager.NetworkCallback networkCallback = captureNetworkCallback();
// Connected to trusted Wi-Fi network.
final Network network = mock(Network.class);
networkCallback.onAvailable(network);
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi1));
// Connected to non-trusted Wi-Fi network.
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities("random-wifi"));
// Verifies that the callback is triggered.
verify(callback).onConditionChanged(mCondition, false);
}
@Test
public void updateCallback_disconnectedFromNetwork_reportsFalse() {
final CommunalTrustedNetworkCondition.Callback callback =
mock(CommunalTrustedNetworkCondition.Callback.class);
mCondition.addCallback(callback);
final ConnectivityManager.NetworkCallback networkCallback = captureNetworkCallback();
// Connected to Wi-Fi.
final Network network = mock(Network.class);
networkCallback.onAvailable(network);
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi1));
clearInvocations(callback);
// Disconnected from Wi-Fi.
networkCallback.onLost(network);
// Verifies that the callback is triggered.
verify(callback).onConditionChanged(mCondition, false);
}
// Captures and returns the network callback, assuming it is registered with the connectivity
// manager.
private ConnectivityManager.NetworkCallback captureNetworkCallback() {
verify(mConnectivityManager).registerNetworkCallback(any(NetworkRequest.class),
mNetworkCallbackCaptor.capture());
return mNetworkCallbackCaptor.getValue();
}
private NetworkCapabilities fakeNetworkCapabilities(String ssid) {
final NetworkCapabilities networkCapabilities = mock(NetworkCapabilities.class);
final WifiInfo wifiInfo = mock(WifiInfo.class);
when(wifiInfo.getSSID()).thenReturn(ssid);
when(networkCapabilities.getTransportInfo()).thenReturn(wifiInfo);
return networkCapabilities;
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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 com.android.systemui.communal;
import com.android.systemui.communal.conditions.CommunalCondition;
/**
* Fake implementation of {@link CommunalCondition}, and provides a way for tests to update
* condition fulfillment.
*/
public class FakeCommunalCondition extends CommunalCondition {
@Override
public void start() {}
@Override
public void stop() {}
public void fakeUpdateCondition(boolean isConditionMet) {
updateCondition(isConditionMet);
}
}