diff --git a/res/values/config.xml b/res/values/config.xml
index c7ef595e3ae..fb1859c85b1 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -617,4 +617,7 @@
false
+
+
+ false
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b7007c4b69c..fde4f262b59 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6646,6 +6646,8 @@
No usage for past 24 hr
+
+ Other users
Battery left estimate is based on your device usage
diff --git a/res/xml/vpn_settings2.xml b/res/xml/vpn_settings2.xml
index 08075a6c8b1..0d374c75518 100644
--- a/res/xml/vpn_settings2.xml
+++ b/res/xml/vpn_settings2.xml
@@ -16,4 +16,9 @@
+
+
+
diff --git a/src/com/android/settings/display/ScreenResolutionFragment.java b/src/com/android/settings/display/ScreenResolutionFragment.java
index bc825149c9c..914d4be568a 100644
--- a/src/com/android/settings/display/ScreenResolutionFragment.java
+++ b/src/com/android/settings/display/ScreenResolutionFragment.java
@@ -26,6 +26,7 @@ import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
+import android.provider.Settings;
import android.text.TextUtils;
import android.view.Display;
@@ -56,6 +57,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
private Resources mResources;
private static final int FHD_INDEX = 0;
private static final int QHD_INDEX = 1;
+ private static final String RESOLUTION_METRIC_SETTING_KEY = "user_selected_resolution";
private Display mDefaultDisplay;
private String[] mScreenResolutionOptions;
private Set mResolutions;
@@ -157,6 +159,17 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
@VisibleForTesting
public void setDisplayMode(final int width) {
mDisplayObserver.startObserve();
+
+ /** For store settings globally. */
+ /** TODO(b/238061217): Moving to an atom with the same string */
+ Settings.System.putString(
+ getContext().getContentResolver(),
+ RESOLUTION_METRIC_SETTING_KEY,
+ getPreferMode(width).getPhysicalWidth()
+ + "x"
+ + getPreferMode(width).getPhysicalHeight());
+
+ /** Apply the resolution change. */
mDefaultDisplay.setUserPreferredDisplayMode(getPreferMode(width));
}
@@ -186,7 +199,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
protected boolean setDefaultKey(final String key) {
int width = getWidthForResoluitonKey(key);
if (width < 0) {
- return false;
+ return false;
}
setDisplayMode(width);
@@ -200,9 +213,8 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
String selectedKey = selected.getKey();
int selectedWidth = getWidthForResoluitonKey(selectedKey);
if (!mDisplayObserver.setPendingResolutionChange(selectedWidth)) {
- return;
+ return;
}
-
super.onRadioButtonClicked(selected);
}
@@ -318,7 +330,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
}
if (!isDensityChanged() || !isResolutionChangeApplied()) {
- return;
+ return;
}
restoreDensity();
@@ -353,10 +365,10 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
int currentWidth = getCurrentWidth();
if (selectedWidth == currentWidth) {
- return false;
+ return false;
}
if (mPreviousWidth.get() != -1 && !isResolutionChangeApplied()) {
- return false;
+ return false;
}
mPreviousWidth.set(currentWidth);
@@ -366,7 +378,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
private boolean isResolutionChangeApplied() {
if (mPreviousWidth.get() == getCurrentWidth()) {
- return false;
+ return false;
}
return true;
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 3f6c1657165..a6c48a48d6b 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -69,6 +69,8 @@ public class BatteryUtils {
public static final int UID_REMOVED_APPS = -4;
/** Special UID value for data usage by tethering. */
public static final int UID_TETHERING = -5;
+ /** Special UID for aggregated other users. */
+ public static final long UID_OTHER_USERS = Long.MIN_VALUE;
@Retention(RetentionPolicy.SOURCE)
@IntDef({StatusType.SCREEN_USAGE,
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index ee53d7f6b6e..83d7a33287a 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -149,6 +149,11 @@ public interface PowerUsageFeatureProvider {
*/
Map> getBatteryHistory(Context context);
+ /**
+ * Returns battery history data since last full charge with corresponding timestamp key.
+ */
+ Map> getBatteryHistorySinceLastFullCharge(Context context);
+
/**
* Returns {@link Uri} to monitor battery history data is update.
*/
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 8c8fd96965d..12626414e44 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -165,6 +165,12 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
return null;
}
+ @Override
+ public Map> getBatteryHistorySinceLastFullCharge(
+ Context context) {
+ return null;
+ }
+
@Override
public Uri getBatteryHistoryUri() {
return null;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index 8b995c859f9..d4d7a00fdc2 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -113,6 +113,9 @@ public class BatteryDiffEntry {
/** Gets the app label name for this entry. */
public String getAppLabel() {
+ if (isOtherUsers()) {
+ return mContext.getString(R.string.battery_usage_other_users);
+ }
loadLabelAndIcon();
// Returns default applicationn label if we cannot find it.
return mAppLabel == null || mAppLabel.length() == 0
@@ -122,6 +125,9 @@ public class BatteryDiffEntry {
/** Gets the app icon {@link Drawable} for this entry. */
public Drawable getAppIcon() {
+ if (isOtherUsers()) {
+ return mContext.getDrawable(R.drawable.ic_power_system);
+ }
loadLabelAndIcon();
return mAppIcon != null && mAppIcon.getConstantState() != null
? mAppIcon.getConstantState().newDrawable()
@@ -156,6 +162,9 @@ public class BatteryDiffEntry {
/** Whether the current BatteryDiffEntry is system component or not. */
public boolean isSystemEntry() {
+ if (isOtherUsers()) {
+ return true;
+ }
switch (mBatteryHistEntry.mConsumerType) {
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
@@ -175,6 +184,11 @@ public class BatteryDiffEntry {
return false;
}
+ private boolean isOtherUsers() {
+ return mBatteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
+ && mBatteryHistEntry.mUid == BatteryUtils.UID_OTHER_USERS;
+ }
+
void loadLabelAndIcon() {
if (mIsLoaded) {
return;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index 76f9419ac41..168fe0f5383 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.os.BatteryUsageStats;
import android.os.LocaleList;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.ArraySet;
@@ -28,6 +29,8 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import com.android.settings.Utils;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.overlay.FeatureFactory;
import java.lang.annotation.Retention;
@@ -265,17 +268,55 @@ public final class ConvertUtils {
}
}
insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap);
+ resolveMultiUsersData(context, resultMap);
if (purgeLowPercentageAndFakeData) {
purgeLowPercentageAndFakeData(context, resultMap);
}
return resultMap;
}
+ @VisibleForTesting
+ static void resolveMultiUsersData(
+ final Context context,
+ final Map> indexedUsageMap) {
+ final int currentUserId = context.getUserId();
+ final UserHandle userHandle =
+ Utils.getManagedProfile(context.getSystemService(UserManager.class));
+ final int workProfileUserId =
+ userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
+ // Loops for all BatteryDiffEntry in the different slots.
+ for (List entryList : indexedUsageMap.values()) {
+ double consumePowerFromOtherUsers = 0f;
+ double consumePercentageFromOtherUsers = 0f;
+ final Iterator iterator = entryList.iterator();
+ while (iterator.hasNext()) {
+ final BatteryDiffEntry entry = iterator.next();
+ final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
+ if (batteryHistEntry.mConsumerType != CONSUMER_TYPE_UID_BATTERY) {
+ continue;
+ }
+ // Whether the BatteryHistEntry represents the current user data?
+ if (batteryHistEntry.mUserId == currentUserId
+ || batteryHistEntry.mUserId == workProfileUserId) {
+ continue;
+ }
+ // Removes and aggregates non-current users data from the list.
+ iterator.remove();
+ consumePowerFromOtherUsers += entry.mConsumePower;
+ consumePercentageFromOtherUsers += entry.getPercentOfTotal();
+ }
+ if (consumePercentageFromOtherUsers != 0) {
+ entryList.add(createOtherUsersEntry(context, consumePowerFromOtherUsers,
+ consumePercentageFromOtherUsers));
+ }
+ }
+ }
+
private static void insert24HoursData(
final int desiredIndex,
final Map> indexedUsageMap) {
final Map resultMap = new HashMap<>();
- double totalConsumePower = 0.0;
+ double totalConsumePower = 0f;
// Loops for all BatteryDiffEntry and aggregate them together.
for (List entryList : indexedUsageMap.values()) {
for (BatteryDiffEntry entry : entryList) {
@@ -361,4 +402,22 @@ public final class ConvertUtils {
return locales != null && !locales.isEmpty() ? locales.get(0)
: Locale.getDefault();
}
+
+ private static BatteryDiffEntry createOtherUsersEntry(
+ Context context, double consumePower, double consumePercentage) {
+ final ContentValues values = new ContentValues();
+ values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS);
+ values.put(BatteryHistEntry.KEY_USER_ID, BatteryUtils.UID_OTHER_USERS);
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, CONSUMER_TYPE_UID_BATTERY);
+ // We will show the percentage for the "other users" item only, the aggregated
+ // running time information is useless for users to identify individual apps.
+ final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
+ context,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ consumePower,
+ new BatteryHistEntry(values));
+ batteryDiffEntry.setTotalConsumePower(100 * consumePower / consumePercentage);
+ return batteryDiffEntry;
+ }
}
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index aff7197e274..c59b3854599 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -45,6 +45,7 @@ import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -177,6 +178,11 @@ public abstract class FeatureFactory {
*/
public abstract AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider();
+ /**
+ * Retrieves implementation for advanced vpn feature.
+ */
+ public abstract AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider();
+
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index 89f74de8233..593b8666c02 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -71,6 +71,8 @@ import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.slices.SlicesFeatureProviderImpl;
import com.android.settings.users.UserFeatureProvider;
import com.android.settings.users.UserFeatureProviderImpl;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProviderImpl;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settings.wifi.WifiTrackerLibProviderImpl;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -106,6 +108,7 @@ public class FeatureFactoryImpl extends FeatureFactory {
private SecuritySettingsFeatureProvider mSecuritySettingsFeatureProvider;
private AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider;
private AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
+ private AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -334,4 +337,12 @@ public class FeatureFactoryImpl extends FeatureFactory {
}
return mAccessibilityMetricsFeatureProvider;
}
+
+ @Override
+ public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() {
+ if (mAdvancedVpnFeatureProvider == null) {
+ mAdvancedVpnFeatureProvider = new AdvancedVpnFeatureProviderImpl();
+ }
+ return mAdvancedVpnFeatureProvider;
+ }
}
diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java
new file mode 100644
index 00000000000..cb56c351448
--- /dev/null
+++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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.settings.vpn2;
+
+import android.content.Context;
+
+/**
+ * Feature Provider used in vpn usage
+ */
+public interface AdvancedVpnFeatureProvider {
+
+ /**
+ * Returns package name of advanced vpn.
+ */
+ String getAdvancedVpnPackageName();
+
+ /**
+ * Returns {@code true} advanced vpn is supported.
+ */
+ boolean isAdvancedVpnSupported(Context context);
+
+ /**
+ * Returns the title of advanced vpn preference group.
+ */
+ String getAdvancedVpnPreferenceGroupTitle(Context context);
+
+ /**
+ * Returns the title of vpn preference group.
+ */
+ String getVpnPreferenceGroupTitle(Context context);
+
+ /**
+ * Returns {@code true} advanced vpn is removable.
+ */
+ boolean isAdvancedVpnRemovable();
+}
diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java
new file mode 100644
index 00000000000..c5bc69c042d
--- /dev/null
+++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.settings.vpn2;
+
+import android.content.Context;
+
+/**
+ * Feature provider implementation for advanced vpn.
+ */
+public class AdvancedVpnFeatureProviderImpl implements AdvancedVpnFeatureProvider {
+ @Override
+ public String getAdvancedVpnPackageName() {
+ return null;
+ }
+
+ @Override
+ public boolean isAdvancedVpnSupported(Context context) {
+ return false;
+ }
+
+ @Override
+ public String getAdvancedVpnPreferenceGroupTitle(Context context) {
+ return null;
+ }
+
+ @Override
+ public String getVpnPreferenceGroupTitle(Context context) {
+ return null;
+ }
+
+ @Override
+ public boolean isAdvancedVpnRemovable() {
+ return true;
+ }
+}
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java
index d4ee5b9c476..d2fa5fccbfc 100644
--- a/src/com/android/settings/vpn2/AppManagementFragment.java
+++ b/src/com/android/settings/vpn2/AppManagementFragment.java
@@ -48,6 +48,7 @@ import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedPreference;
@@ -71,6 +72,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment
private PackageManager mPackageManager;
private DevicePolicyManager mDevicePolicyManager;
private VpnManager mVpnManager;
+ private AdvancedVpnFeatureProvider mFeatureProvider;
// VPN app info
private final int mUserId = UserHandle.myUserId();
@@ -122,6 +124,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment
mPackageManager = getContext().getPackageManager();
mDevicePolicyManager = getContext().getSystemService(DevicePolicyManager.class);
mVpnManager = getContext().getSystemService(VpnManager.class);
+ mFeatureProvider = FeatureFactory.getFactory(getContext()).getAdvancedVpnFeatureProvider();
mPreferenceAlwaysOn = (RestrictedSwitchPreference) findPreference(KEY_ALWAYS_ON_VPN);
mPreferenceLockdown = (RestrictedSwitchPreference) findPreference(KEY_LOCKDOWN_VPN);
@@ -283,7 +286,16 @@ public class AppManagementFragment extends SettingsPreferenceFragment
}
}
- private void updateRestrictedViews() {
+ @VisibleForTesting
+ void updateRestrictedViews() {
+ if (mFeatureProvider.isAdvancedVpnSupported(getContext())
+ && !mFeatureProvider.isAdvancedVpnRemovable()
+ && TextUtils.equals(mPackageName, mFeatureProvider.getAdvancedVpnPackageName())) {
+ mPreferenceForget.setVisible(false);
+ } else {
+ mPreferenceForget.setVisible(true);
+ }
+
if (isAdded()) {
mPreferenceAlwaysOn.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN,
mUserId);
@@ -314,6 +326,14 @@ public class AppManagementFragment extends SettingsPreferenceFragment
}
}
+ @VisibleForTesting
+ void init(String packageName, AdvancedVpnFeatureProvider featureProvider,
+ RestrictedPreference preference) {
+ mPackageName = packageName;
+ mFeatureProvider = featureProvider;
+ mPreferenceForget = preference;
+ }
+
private String getAlwaysOnVpnPackage() {
return mVpnManager.getAlwaysOnVpnPackageForUser(mUserId);
}
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
index e89785fe535..43805956b6e 100644
--- a/src/com/android/settings/vpn2/VpnSettings.java
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -42,6 +42,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.security.Credentials;
import android.security.LegacyVpnProfileStore;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -52,6 +53,7 @@ import android.view.MenuItem;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.LegacyVpnInfo;
@@ -59,6 +61,7 @@ import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.settings.R;
import com.android.settings.RestrictedSettingsFragment;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.GearPreference;
import com.android.settings.widget.GearPreference.OnGearClickListener;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -79,9 +82,12 @@ import java.util.Set;
public class VpnSettings extends RestrictedSettingsFragment implements
Handler.Callback, Preference.OnPreferenceClickListener {
private static final String LOG_TAG = "VpnSettings";
+ private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
private static final int RESCAN_MESSAGE = 0;
private static final int RESCAN_INTERVAL_MS = 1000;
+ private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group";
+ private static final String VPN_GROUP_KEY = "vpn_group";
private static final NetworkRequest VPN_REQUEST = new NetworkRequest.Builder()
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
@@ -102,6 +108,9 @@ public class VpnSettings extends RestrictedSettingsFragment implements
private LegacyVpnInfo mConnectedLegacyVpn;
private boolean mUnavailable;
+ private AdvancedVpnFeatureProvider mFeatureProvider;
+ private PreferenceScreen mPreferenceScreen;
+ private boolean mIsAdvancedVpnSupported;
public VpnSettings() {
super(UserManager.DISALLOW_CONFIG_VPN);
@@ -119,11 +128,14 @@ public class VpnSettings extends RestrictedSettingsFragment implements
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
mVpnManager = (VpnManager) getSystemService(Context.VPN_MANAGEMENT_SERVICE);
+ mFeatureProvider = FeatureFactory.getFactory(getContext()).getAdvancedVpnFeatureProvider();
+ mIsAdvancedVpnSupported = mFeatureProvider.isAdvancedVpnSupported(getContext());
mUnavailable = isUiRestricted();
setHasOptionsMenu(!mUnavailable);
addPreferencesFromResource(R.xml.vpn_settings2);
+ mPreferenceScreen = getPreferenceScreen();
}
@Override
@@ -229,7 +241,8 @@ public class VpnSettings extends RestrictedSettingsFragment implements
// Run heavy RPCs before switching to UI thread
final List vpnProfiles = loadVpnProfiles();
- final List vpnApps = getVpnApps(context, /* includeProfiles */ true);
+ final List vpnApps = getVpnApps(context, /* includeProfiles */ true,
+ mFeatureProvider);
final Map connectedLegacyVpns = getConnectedLegacyVpns();
final Set connectedAppVpns = getConnectedAppVpns();
@@ -265,7 +278,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements
private final VpnSettings mSettings;
- public UpdatePreferences(VpnSettings settings) {
+ UpdatePreferences(VpnSettings settings) {
mSettings = settings;
}
@@ -332,7 +345,14 @@ public class VpnSettings extends RestrictedSettingsFragment implements
}
// Trim out deleted VPN preferences
- mSettings.setShownPreferences(updates);
+ if (DEBUG) {
+ Log.d(LOG_TAG, "isAdvancedVpnSupported() : " + mSettings.mIsAdvancedVpnSupported);
+ }
+ if (mSettings.mIsAdvancedVpnSupported) {
+ mSettings.setShownAdvancedPreferences(updates);
+ } else {
+ mSettings.setShownPreferences(updates);
+ }
}
}
@@ -343,12 +363,61 @@ public class VpnSettings extends RestrictedSettingsFragment implements
@VisibleForTesting @UiThread
public void setShownPreferences(final Collection updates) {
+ retainAllPreference(updates);
+
+ final PreferenceGroup vpnGroup = getPreferenceScreen();
+ updatePreferenceGroup(vpnGroup, updates);
+
+ // Show all new preferences on the screen
+ for (Preference pref : updates) {
+ vpnGroup.addPreference(pref);
+ }
+ }
+
+ @VisibleForTesting @UiThread
+ void setShownAdvancedPreferences(final Collection updates) {
+ retainAllPreference(updates);
+
+ PreferenceGroup advancedVpnGroup = mPreferenceScreen.findPreference(ADVANCED_VPN_GROUP_KEY);
+ PreferenceGroup vpnGroup = mPreferenceScreen.findPreference(VPN_GROUP_KEY);
+ advancedVpnGroup.setTitle(
+ mFeatureProvider.getAdvancedVpnPreferenceGroupTitle(getContext()));
+ vpnGroup.setTitle(mFeatureProvider.getVpnPreferenceGroupTitle(getContext()));
+ updatePreferenceGroup(advancedVpnGroup, updates);
+ updatePreferenceGroup(vpnGroup, updates);
+
+ // Show all new preferences on the screen
+ for (Preference pref : updates) {
+ String packageName = "";
+ if (pref instanceof LegacyVpnPreference) {
+ LegacyVpnPreference legacyPref = (LegacyVpnPreference) pref;
+ packageName = legacyPref.getPackageName();
+ } else if (pref instanceof AppPreference) {
+ AppPreference appPref = (AppPreference) pref;
+ packageName = appPref.getPackageName();
+ }
+ if (DEBUG) {
+ Log.d(LOG_TAG, "setShownAdvancedPreferences() package name : " + packageName);
+ }
+ if (TextUtils.equals(packageName, mFeatureProvider.getAdvancedVpnPackageName())) {
+ advancedVpnGroup.addPreference(pref);
+ } else {
+ vpnGroup.addPreference(pref);
+ }
+ }
+
+ advancedVpnGroup.setVisible(advancedVpnGroup.getPreferenceCount() > 0);
+ vpnGroup.setVisible(vpnGroup.getPreferenceCount() > 0);
+ }
+
+ private void retainAllPreference(Collection updates) {
mLegacyVpnPreferences.values().retainAll(updates);
mAppPreferences.values().retainAll(updates);
+ }
+ private void updatePreferenceGroup(PreferenceGroup vpnGroup, Collection updates) {
// Change {@param updates} in-place to only contain new preferences that were not already
// added to the preference screen.
- final PreferenceGroup vpnGroup = getPreferenceScreen();
for (int i = vpnGroup.getPreferenceCount() - 1; i >= 0; i--) {
Preference p = vpnGroup.getPreference(i);
if (updates.contains(p)) {
@@ -357,11 +426,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
vpnGroup.removePreference(p);
}
}
-
- // Show any new preferences on the screen
- for (Preference pref : updates) {
- vpnGroup.addPreference(pref);
- }
}
@Override
@@ -508,7 +572,15 @@ public class VpnSettings extends RestrictedSettingsFragment implements
return result;
}
- static List getVpnApps(Context context, boolean includeProfiles) {
+ static List getVpnApps(Context context, boolean includeProfiles,
+ AdvancedVpnFeatureProvider featureProvider) {
+ return getVpnApps(context, includeProfiles, featureProvider,
+ context.getSystemService(AppOpsManager.class));
+ }
+
+ @VisibleForTesting
+ static List getVpnApps(Context context, boolean includeProfiles,
+ AdvancedVpnFeatureProvider featureProvider, AppOpsManager aom) {
List result = Lists.newArrayList();
final Set profileIds;
@@ -521,8 +593,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
profileIds = Collections.singleton(UserHandle.myUserId());
}
- // Fetch VPN-enabled apps from AppOps.
- AppOpsManager aom = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
List apps =
aom.getPackagesForOps(new int[] {OP_ACTIVATE_VPN, OP_ACTIVATE_PLATFORM_VPN});
if (apps != null) {
@@ -540,7 +610,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements
allowed = true;
}
}
- if (allowed) {
+ if (allowed || isAdvancedVpn(featureProvider, pkg.getPackageName(), context)) {
result.add(new AppVpnInfo(userId, pkg.getPackageName()));
}
}
@@ -550,6 +620,12 @@ public class VpnSettings extends RestrictedSettingsFragment implements
return result;
}
+ private static boolean isAdvancedVpn(AdvancedVpnFeatureProvider featureProvider,
+ String packageName, Context context) {
+ return featureProvider.isAdvancedVpnSupported(context)
+ && TextUtils.equals(packageName, featureProvider.getAdvancedVpnPackageName());
+ }
+
private static List loadVpnProfiles() {
final ArrayList result = Lists.newArrayList();
@@ -562,4 +638,10 @@ public class VpnSettings extends RestrictedSettingsFragment implements
}
return result;
}
+
+ @VisibleForTesting
+ void init(PreferenceScreen preferenceScreen, AdvancedVpnFeatureProvider featureProvider) {
+ mPreferenceScreen = preferenceScreen;
+ mFeatureProvider = featureProvider;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index 14bbeea7187..283df7bcc43 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -70,6 +70,7 @@ import org.robolectric.annotation.Resetter;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class)
@@ -343,9 +344,17 @@ public final class BatteryBackupHelperTest {
private void verifyBackupData(String expectedResult) throws Exception {
final byte[] expectedBytes = expectedResult.getBytes();
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(byte[].class);
+ final Set expectedResultSet =
+ Set.of(expectedResult.split(BatteryBackupHelper.DELIMITER));
+
verify(mBackupDataOutput).writeEntityHeader(
BatteryBackupHelper.KEY_OPTIMIZATION_LIST, expectedBytes.length);
- verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
+ verify(mBackupDataOutput).writeEntityData(captor.capture(), eq(expectedBytes.length));
+ final String actualResult = new String(captor.getValue());
+ final Set actualResultSet =
+ Set.of(actualResult.split(BatteryBackupHelper.DELIMITER));
+ assertThat(actualResultSet).isEqualTo(expectedResultSet);
}
private void createTestingData(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index bb19b5a53dc..683f0fd2df4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -138,7 +138,7 @@ public final class BatteryDiffEntryTest {
// Generates fake testing data.
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
- values.put("drainType",
+ values.put(BatteryHistEntry.KEY_DRAIN_TYPE,
Integer.valueOf(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY));
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
@@ -164,7 +164,7 @@ public final class BatteryDiffEntryTest {
// Generates fake testing data.
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_USER_BATTERY);
- values.put("userId", Integer.valueOf(1001));
+ values.put(BatteryHistEntry.KEY_USER_ID, Integer.valueOf(1001));
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
@@ -189,8 +189,8 @@ public final class BatteryDiffEntryTest {
final String fakePackageName = "com.fake.google.com";
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("uid", /*invalid uid*/ 10001);
- values.put("packageName", fakePackageName);
+ values.put(BatteryHistEntry.KEY_UID, /*invalid uid*/ 10001);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, fakePackageName);
doReturn(mMockAppInfo).when(mMockPackageManager)
.getApplicationInfo(fakePackageName, 0);
doReturn(expectedAppLabel).when(mMockPackageManager)
@@ -233,7 +233,7 @@ public final class BatteryDiffEntryTest {
final String expectedAppLabel = "fake app label";
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("appLabel", expectedAppLabel);
+ values.put(BatteryHistEntry.KEY_APP_LABEL, expectedAppLabel);
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry);
@@ -391,8 +391,8 @@ public final class BatteryDiffEntryTest {
final String fakePackageName = "com.fake.google.com";
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("uid", /*invalid uid*/ 10001);
- values.put("packageName", fakePackageName);
+ values.put(BatteryHistEntry.KEY_UID, /*invalid uid*/ 10001);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, fakePackageName);
final BatteryDiffEntry entry =
createBatteryDiffEntry(10, new BatteryHistEntry(values));
@@ -424,7 +424,7 @@ public final class BatteryDiffEntryTest {
final String expectedPackageName = "com.fake.google.com";
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("packageName", expectedPackageName);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, expectedPackageName);
final BatteryDiffEntry entry =
createBatteryDiffEntry(10, new BatteryHistEntry(values));
@@ -437,7 +437,7 @@ public final class BatteryDiffEntryTest {
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
values.put(
- "packageName",
+ BatteryHistEntry.KEY_PACKAGE_NAME,
expectedPackageName + ":privileged_process0");
final BatteryDiffEntry entry =
createBatteryDiffEntry(10, new BatteryHistEntry(values));
@@ -445,11 +445,24 @@ public final class BatteryDiffEntryTest {
assertThat(entry.getPackageName()).isEqualTo(expectedPackageName);
}
+ @Test
+ public void getAppLabel_withOtherUsersUid_returnExpectedLabel() {
+ final ContentValues values = getContentValuesWithType(
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
+ values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS);
+
+ final BatteryDiffEntry batteryDiffEntry = createBatteryDiffEntry(
+ /*consumePower=*/ 0, new BatteryHistEntry(values));
+
+ assertThat(batteryDiffEntry.getAppLabel())
+ .isEqualTo(mContext.getString(R.string.battery_usage_other_users));
+ }
+
private BatteryDiffEntry createBatteryDiffEntry(
int consumerType, long uid, boolean isHidden) {
final ContentValues values = getContentValuesWithType(consumerType);
- values.put("isHidden", isHidden);
- values.put("uid", uid);
+ values.put(BatteryHistEntry.KEY_IS_HIDDEN, isHidden);
+ values.put(BatteryHistEntry.KEY_UID, uid);
return new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 0,
@@ -472,15 +485,15 @@ public final class BatteryDiffEntryTest {
private static ContentValues getContentValuesWithType(int consumerType) {
final ContentValues values = new ContentValues();
- values.put("consumerType", Integer.valueOf(consumerType));
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, Integer.valueOf(consumerType));
return values;
}
private BatteryDiffEntry createBatteryDiffEntry(Drawable drawable) throws Exception {
final ContentValues values = getContentValuesWithType(
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
- values.put("uid", 1001);
- values.put("packageName", "com.a.b.c");
+ values.put(BatteryHistEntry.KEY_UID, 1001);
+ values.put(BatteryHistEntry.KEY_PACKAGE_NAME, "com.a.b.c");
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values);
doReturn(drawable).when(mMockPackageManager).getDefaultActivityIcon();
doReturn(null).when(mMockPackageManager).getApplicationInfo("com.a.b.c", 0);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index 0b8a98a742d..c1f981539c1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -27,6 +27,7 @@ import android.os.BatteryUsageStats;
import android.os.LocaleList;
import android.os.UserHandle;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -39,6 +40,7 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -371,6 +373,71 @@ public final class ConvertUtilsTest {
assertThat(ConvertUtils.getLocale(mContext)).isEqualTo(Locale.getDefault());
}
+ @Test
+ public void resolveMultiUsersData_replaceOtherUsersItemWithExpectedEntry() {
+ final int currentUserId = mContext.getUserId();
+ final Map> entryMap = new HashMap<>();
+ // Without other users time slot.
+ entryMap.put(0, Arrays.asList(
+ createBatteryDiffEntry(
+ currentUserId,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 50)));
+ // With other users time slot.
+ final List withOtherUsersList = new ArrayList<>();
+ entryMap.put(1, withOtherUsersList);
+ withOtherUsersList.add(
+ createBatteryDiffEntry(
+ currentUserId + 1,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
+ /*consumePercentage=*/ 20));
+ withOtherUsersList.add(
+ createBatteryDiffEntry(
+ currentUserId + 2,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 30));
+ withOtherUsersList.add(
+ createBatteryDiffEntry(
+ currentUserId + 3,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 40));
+
+ ConvertUtils.resolveMultiUsersData(mContext, entryMap);
+
+ assertThat(entryMap.get(0).get(0).getPercentOfTotal()).isEqualTo(50);
+ // Asserts with other users items.
+ final List entryList = entryMap.get(1);
+ assertThat(entryList).hasSize(2);
+ assertBatteryDiffEntry(
+ entryList.get(0),
+ currentUserId + 1,
+ /*uid=*/ 0,
+ ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
+ /*consumePercentage=*/ 20);
+ assertBatteryDiffEntry(
+ entryList.get(1),
+ BatteryUtils.UID_OTHER_USERS,
+ BatteryUtils.UID_OTHER_USERS,
+ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*consumePercentage=*/ 70);
+ }
+
+ private BatteryDiffEntry createBatteryDiffEntry(
+ long userId, int counsumerType, double consumePercentage) {
+ final ContentValues values = new ContentValues();
+ values.put(BatteryHistEntry.KEY_USER_ID, userId);
+ values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, counsumerType);
+ final BatteryDiffEntry batteryDiffEntry =
+ new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*consumePower=*/ consumePercentage,
+ new BatteryHistEntry(values));
+ batteryDiffEntry.setTotalConsumePower(100f);
+ return batteryDiffEntry;
+ }
+
private static BatteryHistEntry createBatteryHistEntry(
String packageName, String appLabel, double consumePower,
long uid, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
@@ -389,6 +456,15 @@ public final class ConvertUtilsTest {
return new BatteryHistEntry(values);
}
+ private static void assertBatteryDiffEntry(
+ BatteryDiffEntry entry, long userId, long uid, int counsumerType,
+ double consumePercentage) {
+ assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
+ assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
+ assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(counsumerType);
+ assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
+ }
+
private static void assertBatteryDiffEntry(
BatteryDiffEntry entry, int percentOfTotal,
long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 518aee9d23a..2f248320ae5 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -47,6 +47,7 @@ import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -87,6 +88,7 @@ public class FakeFeatureFactory extends FeatureFactory {
public SecuritySettingsFeatureProvider securitySettingsFeatureProvider;
public AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider;
public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
+ public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -136,6 +138,7 @@ public class FakeFeatureFactory extends FeatureFactory {
securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class);
mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class);
+ mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class);
}
@Override
@@ -272,4 +275,9 @@ public class FakeFeatureFactory extends FeatureFactory {
public AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider() {
return mAccessibilityMetricsFeatureProvider;
}
+
+ @Override
+ public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() {
+ return mAdvancedVpnFeatureProvider;
+ }
}
diff --git a/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java b/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java
index b7d37df0d19..4e674d271cb 100644
--- a/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java
+++ b/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java
@@ -27,15 +27,12 @@ import android.view.Display;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-@RunWith(AndroidJUnit4.class)
public class ScreenResolutionFragmentTest {
private Context mContext;
@@ -56,6 +53,7 @@ public class ScreenResolutionFragmentTest {
public void getDefaultKey_FHD() {
Display.Mode mode = new Display.Mode(0, FHD_WIDTH, 0, 0);
doReturn(mode).when(mFragment).getDisplayMode();
+ doReturn(mContext).when(mFragment).getContext();
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey()).isEqualTo(mFragment.getKeyForResolution(FHD_WIDTH));
@@ -66,6 +64,7 @@ public class ScreenResolutionFragmentTest {
public void getDefaultKey_QHD() {
Display.Mode mode = new Display.Mode(0, QHD_WIDTH, 0, 0);
doReturn(mode).when(mFragment).getDisplayMode();
+ doReturn(mContext).when(mFragment).getContext();
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey()).isEqualTo(mFragment.getKeyForResolution(QHD_WIDTH));
@@ -74,6 +73,7 @@ public class ScreenResolutionFragmentTest {
@Test
@UiThreadTest
public void setDefaultKey_FHD() {
+ doReturn(mContext).when(mFragment).getContext();
mFragment.onAttach(mContext);
mFragment.setDefaultKey(mFragment.getKeyForResolution(FHD_WIDTH));
@@ -84,6 +84,7 @@ public class ScreenResolutionFragmentTest {
@Test
@UiThreadTest
public void setDefaultKey_QHD() {
+ doReturn(mContext).when(mFragment).getContext();
mFragment.onAttach(mContext);
mFragment.setDefaultKey(mFragment.getKeyForResolution(QHD_WIDTH));
@@ -94,6 +95,7 @@ public class ScreenResolutionFragmentTest {
@Test
@UiThreadTest
public void bindPreferenceExtra_setSummary() {
+ doReturn(mContext).when(mFragment).getContext();
mFragment.onAttach(mContext);
SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(mContext);
ScreenResolutionFragment.ScreenResolutionCandidateInfo candidates =
diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
index 717de791c55..f565075736d 100644
--- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -45,6 +45,7 @@ import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
+import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -82,6 +83,7 @@ public class FakeFeatureFactory extends FeatureFactory {
public SecuritySettingsFeatureProvider securitySettingsFeatureProvider;
public AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider;
public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
+ public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -122,6 +124,7 @@ public class FakeFeatureFactory extends FeatureFactory {
securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class);
mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class);
+ mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class);
}
@Override
@@ -258,4 +261,9 @@ public class FakeFeatureFactory extends FeatureFactory {
public AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider() {
return mAccessibilityMetricsFeatureProvider;
}
+
+ @Override
+ public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() {
+ return mAdvancedVpnFeatureProvider;
+ }
}
diff --git a/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java b/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java
new file mode 100644
index 00000000000..80bb39372c0
--- /dev/null
+++ b/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 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.settings.vpn2;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.RestrictedPreference;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class AppManagementFragmentTest {
+ private static final String FAKE_PACKAGE_NAME = "com.fake.package.name";
+ private static final String ADVANCED_VPN_GROUP_PACKAGE_NAME = "com.advanced.package.name";
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ private AppManagementFragment mFragment;
+ private Context mContext;
+ private FakeFeatureFactory mFakeFeatureFactory;
+ private RestrictedPreference mPreferenceForget;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mFragment = spy(new AppManagementFragment());
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mPreferenceForget = new RestrictedPreference(mContext);
+
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ mFragment.init(ADVANCED_VPN_GROUP_PACKAGE_NAME,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName())
+ .thenReturn(ADVANCED_VPN_GROUP_PACKAGE_NAME);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any()))
+ .thenReturn(true);
+ }
+
+ @Test
+ public void updateRestrictedViews_isAdvancedVpn_hidesForgetPreference() {
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable())
+ .thenReturn(false);
+ mFragment.updateRestrictedViews();
+ assertThat(mPreferenceForget.isVisible()).isFalse();
+ }
+
+ @Test
+ public void updateRestrictedViews_isNotAdvancedVpn_showsForgetPreference() {
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable())
+ .thenReturn(false);
+ mFragment.init(FAKE_PACKAGE_NAME,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget);
+ mFragment.updateRestrictedViews();
+ assertThat(mPreferenceForget.isVisible()).isTrue();
+ }
+
+ @Test
+ public void updateRestrictedViews_isAdvancedVpnRemovable_showsForgetPreference() {
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable())
+ .thenReturn(true);
+ mFragment.init(FAKE_PACKAGE_NAME,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget);
+ mFragment.updateRestrictedViews();
+ assertThat(mPreferenceForget.isVisible()).isTrue();
+ }
+}
diff --git a/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java
new file mode 100644
index 00000000000..86bd1e741a2
--- /dev/null
+++ b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 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.settings.vpn2;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.util.ArraySet;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class VpnSettingsTest {
+ private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group";
+ private static final String VPN_GROUP_KEY = "vpn_group";
+ private static final String ADVANCED_VPN_GROUP_TITLE = "advanced_vpn_group_title";
+ private static final String VPN_GROUP_TITLE = "vpn_group_title";
+ private static final String FAKE_PACKAGE_NAME = "com.fake.package.name";
+ private static final String ADVANCED_VPN_GROUP_PACKAGE_NAME = "com.advanced.package.name";
+ private static final int USER_ID_1 = UserHandle.USER_NULL;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock
+ private AppOpsManager mAppOpsManager;
+
+ private VpnSettings mVpnSettings;
+ private Context mContext;
+ private PreferenceManager mPreferenceManager;
+ private PreferenceScreen mPreferenceScreen;
+ private PreferenceGroup mAdvancedVpnGroup;
+ private PreferenceGroup mVpnGroup;
+ private FakeFeatureFactory mFakeFeatureFactory;
+
+ @Before
+ @UiThreadTest
+ public void setUp() throws PackageManager.NameNotFoundException {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mVpnSettings = spy(new VpnSettings());
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mAdvancedVpnGroup = spy(new PreferenceCategory(mContext));
+ mVpnGroup = spy(new PreferenceCategory(mContext));
+ mAdvancedVpnGroup.setKey(ADVANCED_VPN_GROUP_KEY);
+ mVpnGroup.setKey(VPN_GROUP_KEY);
+ mPreferenceManager = new PreferenceManager(mContext);
+ mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
+ mPreferenceScreen.addPreference(mAdvancedVpnGroup);
+ mPreferenceScreen.addPreference(mVpnGroup);
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ mVpnSettings.init(mPreferenceScreen, mFakeFeatureFactory.getAdvancedVpnFeatureProvider());
+
+ when(mVpnSettings.getContext()).thenReturn(mContext);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider
+ .getAdvancedVpnPreferenceGroupTitle(mContext)).thenReturn(ADVANCED_VPN_GROUP_TITLE);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getVpnPreferenceGroupTitle(mContext))
+ .thenReturn(VPN_GROUP_TITLE);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName())
+ .thenReturn(ADVANCED_VPN_GROUP_PACKAGE_NAME);
+ when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any()))
+ .thenReturn(true);
+ doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+ doReturn(mContext).when(mContext).createPackageContextAsUser(any(), anyInt(), any());
+ doReturn(mPreferenceManager).when(mVpnGroup).getPreferenceManager();
+ doReturn(mPreferenceManager).when(mAdvancedVpnGroup).getPreferenceManager();
+ }
+
+ @Test
+ public void setShownAdvancedPreferences_hasGeneralVpn_returnsVpnCountAs1() {
+ Set updates = new ArraySet<>();
+ AppPreference pref =
+ spy(new AppPreference(mContext, USER_ID_1, FAKE_PACKAGE_NAME));
+ updates.add(pref);
+
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ assertThat(mVpnGroup.getPreferenceCount()).isEqualTo(1);
+ assertThat(mVpnGroup.isVisible()).isTrue();
+ assertThat(mAdvancedVpnGroup.isVisible()).isFalse();
+ }
+
+ @Test
+ public void setShownAdvancedPreferences_hasAdvancedVpn_returnsAdvancedVpnCountAs1() {
+ Set updates = new ArraySet<>();
+ AppPreference pref =
+ spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_GROUP_PACKAGE_NAME));
+ updates.add(pref);
+
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ assertThat(mAdvancedVpnGroup.getPreferenceCount()).isEqualTo(1);
+ assertThat(mAdvancedVpnGroup.isVisible()).isTrue();
+ assertThat(mVpnGroup.isVisible()).isFalse();
+ }
+
+ @Test
+ public void setShownAdvancedPreferences_noVpn_returnsEmpty() {
+ Set updates = new ArraySet<>();
+
+ mVpnSettings.setShownAdvancedPreferences(updates);
+
+ assertThat(mAdvancedVpnGroup.getPreferenceCount()).isEqualTo(0);
+ assertThat(mVpnGroup.getPreferenceCount()).isEqualTo(0);
+ assertThat(mAdvancedVpnGroup.isVisible()).isFalse();
+ assertThat(mVpnGroup.isVisible()).isFalse();
+ }
+
+ @Test
+ public void getVpnApps_isAdvancedVpn_returnsOne() {
+ int uid = 1111;
+ List opEntries = new ArrayList<>();
+ List apps = new ArrayList<>();
+ AppOpsManager.PackageOps packageOps =
+ new AppOpsManager.PackageOps(ADVANCED_VPN_GROUP_PACKAGE_NAME, uid, opEntries);
+ apps.add(packageOps);
+ when(mAppOpsManager.getPackagesForOps((int[]) any())).thenReturn(apps);
+
+ assertThat(VpnSettings.getVpnApps(mContext, /* includeProfiles= */ false,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(),
+ mAppOpsManager).size()).isEqualTo(1);
+ }
+
+ @Test
+ public void getVpnApps_isNotAdvancedVpn_returnsEmpty() {
+ int uid = 1111;
+ List opEntries = new ArrayList<>();
+ List apps = new ArrayList<>();
+ AppOpsManager.PackageOps packageOps =
+ new AppOpsManager.PackageOps(FAKE_PACKAGE_NAME, uid, opEntries);
+ apps.add(packageOps);
+ when(mAppOpsManager.getPackagesForOps((int[]) any())).thenReturn(apps);
+
+ assertThat(VpnSettings.getVpnApps(mContext, /* includeProfiles= */ false,
+ mFakeFeatureFactory.getAdvancedVpnFeatureProvider(),
+ mAppOpsManager)).isEmpty();
+ }
+}