When Remove Account is disallowed, show dialog

When DISALLOW_MODIFY_ACCOUNT is set by a device admin, and
the user wants to remove an account, show the support dialog
instead of showing the confirm dialog.

To use the O-API DPM.createAdminSupportIntent(), a wrapper
needs to be used, because existing Robolectric tests otherwise
don't compile.

Bug: 37413849
Test: make RunSettingsRoboTests -j40 ROBOTEST_FILTER=*RemoveAccountPreferenceControllerTest

Change-Id: If23ea304ab8b9df1748e6acf3032310843b04780
This commit is contained in:
phweiss
2017-06-02 19:38:50 +02:00
parent d5612408af
commit 7a34e9c28e
4 changed files with 56 additions and 3 deletions

View File

@@ -21,6 +21,7 @@ import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture; import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException; import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException; import android.accounts.OperationCanceledException;
import android.app.admin.DevicePolicyManager;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@@ -30,16 +31,20 @@ import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.Button; import android.widget.Button;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.applications.LayoutPreference; import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.enterprise.DevicePolicyManagerWrapper;
import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import java.io.IOException; import java.io.IOException;
@@ -52,10 +57,19 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
private Account mAccount; private Account mAccount;
private Fragment mParentFragment; private Fragment mParentFragment;
private UserHandle mUserHandle; private UserHandle mUserHandle;
private DevicePolicyManagerWrapper mDpm;
public RemoveAccountPreferenceController(Context context, Fragment parent) { public RemoveAccountPreferenceController(Context context, Fragment parent) {
this(context, parent, new DevicePolicyManagerWrapperImpl(
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)));
}
@VisibleForTesting
RemoveAccountPreferenceController(Context context, Fragment parent,
DevicePolicyManagerWrapper dpm) {
super(context); super(context);
mParentFragment = parent; mParentFragment = parent;
mDpm = dpm;
} }
@Override @Override
@@ -79,6 +93,12 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final Intent intent = mDpm.createAdminSupportIntent(UserManager.DISALLOW_MODIFY_ACCOUNTS);
if (intent != null) {
// DISALLOW_MODIFY_ACCOUNTS is active, show admin support dialog
mContext.startActivity(intent);
return;
}
ConfirmRemoveAccountDialog.show(mParentFragment, mAccount, mUserHandle); ConfirmRemoveAccountDialog.show(mParentFragment, mAccount, mUserHandle);
} }

View File

@@ -18,6 +18,7 @@ package com.android.settings.enterprise;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent;
import android.os.UserHandle; import android.os.UserHandle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@@ -143,4 +144,11 @@ public interface DevicePolicyManagerWrapper {
* @see android.app.admin.DevicePolicyManager#isUninstallInQueue * @see android.app.admin.DevicePolicyManager#isUninstallInQueue
*/ */
boolean isUninstallInQueue(String packageName); boolean isUninstallInQueue(String packageName);
/**
* Calls {@code DevicePolicyManager.createAdminSupportIntent()}.
*
* @see android.app.admin.DevicePolicyManager#createAdminSupportIntent
*/
Intent createAdminSupportIntent(String restriction);
} }

View File

@@ -19,6 +19,7 @@ package com.android.settings.enterprise;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent;
import android.os.UserHandle; import android.os.UserHandle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@@ -111,4 +112,9 @@ public class DevicePolicyManagerWrapperImpl implements DevicePolicyManagerWrappe
public boolean isUninstallInQueue(String packageName) { public boolean isUninstallInQueue(String packageName) {
return mDpm.isUninstallInQueue(packageName); return mDpm.isUninstallInQueue(packageName);
} }
@Override
public Intent createAdminSupportIntent(@NonNull String restriction) {
return mDpm.createAdminSupportIntent(restriction);
}
} }

View File

@@ -21,6 +21,7 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -33,17 +34,20 @@ import android.app.Activity;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager;
import android.support.v14.preference.PreferenceFragment; import android.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.widget.Button; import android.widget.Button;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.applications.LayoutPreference; import com.android.settings.applications.LayoutPreference;
import com.android.settings.enterprise.DevicePolicyManagerWrapper;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowAccountManager; import com.android.settings.testutils.shadow.ShadowAccountManager;
import com.android.settings.testutils.shadow.ShadowContentResolver; import com.android.settings.testutils.shadow.ShadowContentResolver;
@@ -64,6 +68,8 @@ public class RemoveAccountPreferenceControllerTest {
@Mock(answer = RETURNS_DEEP_STUBS) @Mock(answer = RETURNS_DEEP_STUBS)
private AccountManager mAccountManager; private AccountManager mAccountManager;
@Mock
private DevicePolicyManagerWrapper mDevicePolicyManager;
@Mock(answer = RETURNS_DEEP_STUBS) @Mock(answer = RETURNS_DEEP_STUBS)
private PreferenceFragment mFragment; private PreferenceFragment mFragment;
@Mock @Mock
@@ -92,7 +98,8 @@ public class RemoveAccountPreferenceControllerTest {
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn( when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
new AuthenticatorDescription[0]); new AuthenticatorDescription[0]);
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]); when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
mController = new RemoveAccountPreferenceController(mContext, mFragment); mController = new RemoveAccountPreferenceController(mContext, mFragment,
mDevicePolicyManager);
} }
@Test @Test
@@ -116,6 +123,18 @@ public class RemoveAccountPreferenceControllerTest {
eq(TAG_REMOVE_ACCOUNT_DIALOG)); eq(TAG_REMOVE_ACCOUNT_DIALOG));
} }
@Test
public void onClick_shouldNotStartConfirmDialogWhenModifyAccountsIsDisallowed() {
when(mFragment.isAdded()).thenReturn(true);
when(mDevicePolicyManager.createAdminSupportIntent(UserManager.DISALLOW_MODIFY_ACCOUNTS))
.thenReturn(new Intent());
mController.onClick(null);
verify(mFragmentTransaction, never()).add(
any(RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.class),
eq(TAG_REMOVE_ACCOUNT_DIALOG));
}
@Test @Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class}) @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void confirmRemove_shouldRemoveAccount() { public void confirmRemove_shouldRemoveAccount() {