mListener.onSubmit(this);
break;
case BUTTON_FORGET:
- if (WifiSettings.isEditabilityLockedDown(
- getContext(), mAccessPoint.getConfig())) {
+ if (WifiUtils.isNetworkLockedDown(getContext(), mAccessPoint.getConfig())) {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
RestrictedLockUtils.getDeviceOwner(getContext()));
return;
import android.annotation.NonNull;
import android.app.Activity;
import android.app.Dialog;
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
WifiConfiguration config = mSelectedAccessPoint.getConfig();
// Some configs are ineditable
- if (isEditabilityLockedDown(getActivity(), config)) {
+ if (WifiUtils.isNetworkLockedDown(getActivity(), config)) {
return;
}
private void showDialog(AccessPoint accessPoint, int dialogMode) {
if (accessPoint != null) {
WifiConfiguration config = accessPoint.getConfig();
- if (isEditabilityLockedDown(getActivity(), config) && accessPoint.isActive()) {
+ if (WifiUtils.isNetworkLockedDown(getActivity(), config) && accessPoint.isActive()) {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
RestrictedLockUtils.getDeviceOwner(getActivity()));
return;
}
};
- /**
- * Returns true if the config is not editable through Settings.
- * @param context Context of caller
- * @param config The WiFi config.
- * @return true if the config is not editable through Settings.
- */
- public static boolean isEditabilityLockedDown(Context context, WifiConfiguration config) {
- return !canModifyNetwork(context, config);
- }
-
- /**
- * This method is a stripped version of WifiConfigStore.canModifyNetwork.
- * TODO: refactor to have only one method.
- * @param context Context of caller
- * @param config The WiFi config.
- * @return true if Settings can modify the config.
- */
- static boolean canModifyNetwork(Context context, WifiConfiguration config) {
- if (config == null) {
- return true;
- }
-
- final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
-
- // Check if device has DPM capability. If it has and dpm is still null, then we
- // treat this case with suspicion and bail out.
- final PackageManager pm = context.getPackageManager();
- if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) && dpm == null) {
- return false;
- }
-
- boolean isConfigEligibleForLockdown = false;
- if (dpm != null) {
- final ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
- if (deviceOwner != null) {
- final int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
- try {
- final int deviceOwnerUid = pm.getPackageUidAsUser(deviceOwner.getPackageName(),
- deviceOwnerUserId);
- isConfigEligibleForLockdown = deviceOwnerUid == config.creatorUid;
- } catch (NameNotFoundException e) {
- // don't care
- }
- }
- }
- if (!isConfigEligibleForLockdown) {
- return true;
- }
-
- final ContentResolver resolver = context.getContentResolver();
- final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
- Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
- return !isLockdownFeatureEnabled;
- }
-
private static class SummaryProvider
implements SummaryLoader.SummaryProvider, OnSummaryChangeListener {
package com.android.settings.wifi;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.wifi.WifiConfiguration;
+import android.provider.Settings;
import android.text.TextUtils;
+import com.android.settings.wrapper.DevicePolicyManagerWrapper;
+import com.android.settingslib.wrapper.PackageManagerWrapper;
+
public class WifiUtils {
private static final int SSID_ASCII_MIN_LENGTH = 1;
final int length = password.length();
return length >= PASSWORD_MIN_LENGTH && length <= PASSWORD_MAX_LENGTH;
}
+
+ /**
+ * This method is a stripped and negated version of WifiConfigStore.canModifyNetwork.
+ * @param context Context of caller
+ * @param config The WiFi config.
+ * @return true if Settings cannot modify the config due to lockDown.
+ */
+ public static boolean isNetworkLockedDown(Context context, WifiConfiguration config) {
+ if (config == null) {
+ return false;
+ }
+
+ final DevicePolicyManagerWrapper dpm = DevicePolicyManagerWrapper.from(context);
+ final PackageManagerWrapper pm = new PackageManagerWrapper(context.getPackageManager());
+
+ // Check if device has DPM capability. If it has and dpm is still null, then we
+ // treat this case with suspicion and bail out.
+ if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) && dpm == null) {
+ return true;
+ }
+
+ boolean isConfigEligibleForLockdown = false;
+ if (dpm != null) {
+ final ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
+ if (deviceOwner != null) {
+ final int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
+ try {
+ final int deviceOwnerUid = pm.getPackageUidAsUser(deviceOwner.getPackageName(),
+ deviceOwnerUserId);
+ isConfigEligibleForLockdown = deviceOwnerUid == config.creatorUid;
+ } catch (PackageManager.NameNotFoundException e) {
+ // don't care
+ }
+ }
+ }
+ if (!isConfigEligibleForLockdown) {
+ return false;
+ }
+
+ final ContentResolver resolver = context.getContentResolver();
+ final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
+ Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
+ return isLockdownFeatureEnabled;
+ }
}
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static com.android.settings.wifi.WifiSettings.isEditabilityLockedDown;
-
import android.app.Activity;
import android.app.Fragment;
import android.content.BroadcastReceiver;
import com.android.settings.wifi.WifiDetailPreference;
import com.android.settings.wifi.WifiDialog;
import com.android.settings.wifi.WifiDialog.WifiDialogListener;
+import com.android.settings.wifi.WifiUtils;
import com.android.settings.wrapper.ConnectivityManagerWrapper;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
mButtonsPref = ((ActionButtonPreference) screen.findPreference(KEY_BUTTONS_PREF))
.setButton1Text(R.string.forget)
.setButton1Positive(false)
- .setButton2Text(R.string.support_sign_in_button_text)
.setButton1OnClickListener(view -> forgetNetwork())
+ .setButton2Text(R.string.support_sign_in_button_text)
.setButton2Positive(true)
.setButton2OnClickListener(view -> signIntoNetwork());
* Returns whether the network represented by this preference can be forgotten.
*/
private boolean canForgetNetwork() {
- // TODO(65396674): create test for the locked down scenario
- return (mWifiInfo != null && mWifiInfo.isEphemeral())
- || (mWifiConfig != null && !isEditabilityLockedDown(mContext, mWifiConfig));
+ return (mWifiInfo != null && mWifiInfo.isEphemeral()) || canModifyNetwork();
+ }
+
+ /**
+ * Returns whether the network represented by this preference can be modified.
+ */
+ public boolean canModifyNetwork() {
+ return mWifiConfig != null && !WifiUtils.isNetworkLockedDown(mContext, mWifiConfig);
}
/**
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.wifi.WifiConfigUiBase;
import com.android.settings.wifi.WifiDialog;
import com.android.settings.wrapper.ConnectivityManagerWrapper;
+import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.wifi.AccessPoint;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case Menu.FIRST:
- showDialog(WIFI_DIALOG_ID);
+ if (!mWifiDetailPreferenceController.canModifyNetwork()) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
+ RestrictedLockUtils.getDeviceOwner(getContext()));
+ } else {
+ showDialog(WIFI_DIALOG_ID);
+ }
return true;
default:
return super.onOptionsItemSelected(menuItem);
package com.android.settings.wrapper;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import java.util.List;
mDpm = dpm;
}
+ public static @Nullable DevicePolicyManagerWrapper from(Context context) {
+ DevicePolicyManager dpm =
+ (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ return dpm == null ? null : new DevicePolicyManagerWrapper(dpm);
+ }
+
/**
* Calls {@code DevicePolicyManager.getActiveAdminsAsUser()}.
*
- * @see android.app.admin.DevicePolicyManager#getActiveAdminsAsUser
+ * @see DevicePolicyManager#getActiveAdminsAsUser
*/
public @Nullable List<ComponentName> getActiveAdminsAsUser(int userId) {
return mDpm.getActiveAdminsAsUser(userId);
/**
* Calls {@code DevicePolicyManager.getMaximumFailedPasswordsForWipe()}.
*
- * @see android.app.admin.DevicePolicyManager#getMaximumFailedPasswordsForWipe
+ * @see DevicePolicyManager#getMaximumFailedPasswordsForWipe
*/
public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) {
return mDpm.getMaximumFailedPasswordsForWipe(admin, userHandle);
/**
* Calls {@code DevicePolicyManager.getDeviceOwnerComponentOnCallingUser()}.
*
- * @see android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnCallingUser
+ * @see DevicePolicyManager#getDeviceOwnerComponentOnCallingUser
*/
public ComponentName getDeviceOwnerComponentOnCallingUser() {
return mDpm.getDeviceOwnerComponentOnCallingUser();
/**
* Calls {@code DevicePolicyManager.getDeviceOwnerComponentOnAnyUser()}.
*
- * @see android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnAnyUser
+ * @see DevicePolicyManager#getDeviceOwnerComponentOnAnyUser
*/
public ComponentName getDeviceOwnerComponentOnAnyUser() {
return mDpm.getDeviceOwnerComponentOnAnyUser();
/**
* Calls {@code DevicePolicyManager.getProfileOwnerAsUser()}.
*
- * @see android.app.admin.DevicePolicyManager#getProfileOwnerAsUser
+ * @see DevicePolicyManager#getProfileOwnerAsUser
*/
public @Nullable ComponentName getProfileOwnerAsUser(final int userId) {
return mDpm.getProfileOwnerAsUser(userId);
/**
* Calls {@code DevicePolicyManager.getDeviceOwnerNameOnAnyUser()}.
*
- * @see android.app.admin.DevicePolicyManager#getDeviceOwnerNameOnAnyUser
+ * @see DevicePolicyManager#getDeviceOwnerNameOnAnyUser
*/
public CharSequence getDeviceOwnerOrganizationName() {
return mDpm.getDeviceOwnerOrganizationName();
/**
* Calls {@code DevicePolicyManager.getPermissionGrantState()}.
*
- * @see android.app.admin.DevicePolicyManager#getPermissionGrantState
+ * @see DevicePolicyManager#getPermissionGrantState
*/
public int getPermissionGrantState(@Nullable ComponentName admin, String packageName,
String permission) {
/**
* Calls {@code DevicePolicyManager.isSecurityLoggingEnabled()}.
*
- * @see android.app.admin.DevicePolicyManager#isSecurityLoggingEnabled
+ * @see DevicePolicyManager#isSecurityLoggingEnabled
*/
public boolean isSecurityLoggingEnabled(@Nullable ComponentName admin) {
return mDpm.isSecurityLoggingEnabled(admin);
/**
* Calls {@code DevicePolicyManager.isNetworkLoggingEnabled()}.
*
- * @see android.app.admin.DevicePolicyManager#isNetworkLoggingEnabled
+ * @see DevicePolicyManager#isNetworkLoggingEnabled
*/
public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin) {
return mDpm.isNetworkLoggingEnabled(admin);
/**
* Calls {@code DevicePolicyManager.getLastSecurityLogRetrievalTime()}.
*
- * @see android.app.admin.DevicePolicyManager#getLastSecurityLogRetrievalTime
+ * @see DevicePolicyManager#getLastSecurityLogRetrievalTime
*/
public long getLastSecurityLogRetrievalTime() {
return mDpm.getLastSecurityLogRetrievalTime();
/**
* Calls {@code DevicePolicyManager.getLastBugReportRequestTime()}.
*
- * @see android.app.admin.DevicePolicyManager#getLastBugReportRequestTime
+ * @see DevicePolicyManager#getLastBugReportRequestTime
*/
public long getLastBugReportRequestTime() {
return mDpm.getLastBugReportRequestTime();
/**
* Calls {@code DevicePolicyManager.getLastNetworkLogRetrievalTime()}.
*
- * @see android.app.admin.DevicePolicyManager#getLastNetworkLogRetrievalTime
+ * @see DevicePolicyManager#getLastNetworkLogRetrievalTime
*/
public long getLastNetworkLogRetrievalTime() {
return mDpm.getLastNetworkLogRetrievalTime();
/**
* Calls {@code DevicePolicyManager.isCurrentInputMethodSetByOwner()}.
*
- * @see android.app.admin.DevicePolicyManager#isCurrentInputMethodSetByOwner
+ * @see DevicePolicyManager#isCurrentInputMethodSetByOwner
*/
public boolean isCurrentInputMethodSetByOwner() {
return mDpm.isCurrentInputMethodSetByOwner();
/**
* Calls {@code DevicePolicyManager.getOwnerInstalledCaCerts()}.
*
- * @see android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts
+ * @see DevicePolicyManager#getOwnerInstalledCaCerts
*/
public List<String> getOwnerInstalledCaCerts(@NonNull UserHandle user) {
return mDpm.getOwnerInstalledCaCerts(user);
/**
* Calls {@code DevicePolicyManager.isDeviceOwnerAppOnAnyUser()}.
*
- * @see android.app.admin.DevicePolicyManager#isDeviceOwnerAppOnAnyUser
+ * @see DevicePolicyManager#isDeviceOwnerAppOnAnyUser
*/
public boolean isDeviceOwnerAppOnAnyUser(String packageName) {
return mDpm.isDeviceOwnerAppOnAnyUser(packageName);
/**
* Calls {@code DevicePolicyManager.packageHasActiveAdmins()}.
*
- * @see android.app.admin.DevicePolicyManager#packageHasActiveAdmins
+ * @see DevicePolicyManager#packageHasActiveAdmins
*/
public boolean packageHasActiveAdmins(String packageName) {
return mDpm.packageHasActiveAdmins(packageName);
/**
* Calls {@code DevicePolicyManager.isUninstallInQueue()}.
*
- * @see android.app.admin.DevicePolicyManager#isUninstallInQueue
+ * @see DevicePolicyManager#isUninstallInQueue
*/
public boolean isUninstallInQueue(String packageName) {
return mDpm.isUninstallInQueue(packageName);
/**
* Calls {@code DevicePolicyManager.createAdminSupportIntent()}.
*
- * @see android.app.admin.DevicePolicyManager#createAdminSupportIntent
+ * @see DevicePolicyManager#createAdminSupportIntent(String)
*/
public Intent createAdminSupportIntent(@NonNull String restriction) {
return mDpm.createAdminSupportIntent(restriction);
}
+
+ /**
+ * Calls {@code DevicePolicyManager#getDeviceOwnerUserId()}.
+ *
+ * @see DevicePolicyManager#getDeviceOwnerUserId()
+ */
+ public int getDeviceOwnerUserId() {
+ return mDpm.getDeviceOwnerUserId();
+ }
}
--- /dev/null
+/*
+ * Copyright (C) 2017 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.testutils.shadow;
+
+import android.content.ComponentName;
+
+import com.android.settings.wrapper.DevicePolicyManagerWrapper;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/**
+ * Shadow for {@link DevicePolicyManagerWrapper} to allow stubbing hidden methods.
+ */
+@Implements(DevicePolicyManagerWrapper.class)
+public class ShadowDevicePolicyManagerWrapper {
+ private static ComponentName deviceOComponentName = null;
+ private static int deviceOwnerUserId = -1;
+
+ @Implementation
+ public ComponentName getDeviceOwnerComponentOnAnyUser() {
+ return deviceOComponentName;
+ }
+
+ @Implementation
+ public int getDeviceOwnerUserId() {
+ return deviceOwnerUserId;
+ }
+
+ public static void setDeviceOComponentName(ComponentName deviceOComponentName) {
+ ShadowDevicePolicyManagerWrapper.deviceOComponentName = deviceOComponentName;
+ }
+
+ public static void setDeviceOwnerUserId(int deviceOwnerUserId) {
+ ShadowDevicePolicyManagerWrapper.deviceOwnerUserId = deviceOwnerUserId;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 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.testutils.shadow;
+
+import android.content.pm.PackageManager.NameNotFoundException;
+
+import com.android.settingslib.wrapper.PackageManagerWrapper;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.HashMap;
+
+/**
+ * Shadow for {@link PackageManagerWrapper} to allow stubbing hidden methods.
+ */
+@Implements(PackageManagerWrapper.class)
+public class ShadowPackageManagerWrapper {
+ private static final HashMap<String, Integer> packageUids = new HashMap<>();
+
+ @Implementation
+ public int getPackageUidAsUser(String packageName, int userId) throws NameNotFoundException {
+ Integer res = packageUids.get(packageName + userId);
+ if (res == null) {
+ throw new NameNotFoundException();
+ }
+ return res;
+ }
+
+ public static void setPackageUidAsUser(String packageName, int userId, int uid) {
+ packageUids.put(packageName + userId, uid);
+ }
+}
import static org.mockito.Mockito.when;
import android.app.Activity;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
+import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowDevicePolicyManagerWrapper;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
+import com.android.settings.testutils.shadow.ShadowPackageManagerWrapper;
import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.widget.ActionButtonPreferenceTest;
import com.android.settings.widget.EntityHeaderController;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = ShadowEntityHeaderController.class)
+ shadows = {
+ ShadowDevicePolicyManagerWrapper.class,
+ ShadowEntityHeaderController.class,
+ ShadowPackageManagerWrapper.class,
+ })
public class WifiDetailPreferenceControllerTest {
private static final int LEVEL = 1;
when(mockHeaderController.setSummary(anyString())).thenReturn(mockHeaderController);
when(mockIconInjector.getIcon(anyInt())).thenReturn(new ColorDrawable());
- doReturn(null).when(mContext).getSystemService(eq(Context.DEVICE_POLICY_SERVICE));
-
setupMockedPreferenceScreen();
mController = newWifiDetailPreferenceController();
}
}
@Test
+ public void canForgetNetwork_lockedDown() {
+ lockDownNetwork();
+
+ displayAndResume();
+
+ verify(mockButtonsPref).setButton1Visible(false);
+ }
+
+ @Test
+ public void canModifyNetwork_saved() {
+ assertThat(mController.canModifyNetwork()).isTrue();
+ }
+
+ @Test
+ public void canModifyNetwork_lockedDown() {
+ lockDownNetwork();
+
+ assertThat(mController.canModifyNetwork()).isFalse();
+ }
+
+ /**
+ * Pretends that current network is locked down by device owner.
+ */
+ private void lockDownNetwork() {
+ final int doUserId = 123;
+ final int doUid = 1234;
+ String doPackage = "some.package";
+
+ mockWifiConfig.creatorUid = doUid;
+ ComponentName doComponent = new ComponentName(doPackage, "some.Class");
+ ShadowPackageManagerWrapper.setPackageUidAsUser(doPackage, doUserId, doUid);
+ ShadowDevicePolicyManagerWrapper.setDeviceOComponentName(doComponent);
+ ShadowDevicePolicyManagerWrapper.setDeviceOwnerUserId(doUserId);
+
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 1);
+ }
+
+ @Test
public void forgetNetwork_ephemeral() {
String ssid = "ssid";
when(mockWifiInfo.isEphemeral()).thenReturn(true);