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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user