From ccd4fa8e609a8fe9d2535ec78922b12d03ec0120 Mon Sep 17 00:00:00 2001 From: Bartosz Fabianowski Date: Tue, 17 Jan 2017 12:42:35 +0100 Subject: [PATCH] Add Device Owner disclosure to Add Accounts dialog This CL adds a footer to the Add Accounts dialog that tells the user when the device is managed by a Device Owner app. Bug: 32692748 Test: make RunSettingsRoboTests Change-Id: I0dd161eb0bbbc87c04692d4fa6547bd41dab05e0 --- res/values/strings.xml | 8 +++ .../accounts/ChooseAccountActivity.java | 27 ++++++++++ .../DevicePolicyManagerWrapper.java | 7 +++ .../DevicePolicyManagerWrapperImpl.java | 5 ++ .../EnterprisePrivacyFeatureProvider.java | 11 ++++ .../EnterprisePrivacyFeatureProviderImpl.java | 52 ++++++++++++++++++- .../settings/overlay/FeatureFactoryImpl.java | 3 +- .../applications/InstalledAppCounterTest.java | 4 +- ...erprisePrivacyFeatureProviderImplTest.java | 38 +++++++++++++- 9 files changed, 150 insertions(+), 5 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 54ed1dfd762..f7f438c2fde 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8034,6 +8034,14 @@ Always-on VPN turned on in your work profile Global HTTP proxy set + + This device is managed. + + This device is managed by %s. + + " " + + Learn more Photos & Videos diff --git a/src/com/android/settings/accounts/ChooseAccountActivity.java b/src/com/android/settings/accounts/ChooseAccountActivity.java index ea39426f436..6f0c110ab3a 100644 --- a/src/com/android/settings/accounts/ChooseAccountActivity.java +++ b/src/com/android/settings/accounts/ChooseAccountActivity.java @@ -22,6 +22,7 @@ import static android.content.Intent.EXTRA_USER; import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; +import android.app.Activity; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -41,6 +42,10 @@ import com.android.internal.util.CharSequences; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; +import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.widget.FooterPreference; +import com.android.settings.widget.FooterPreferenceMixin; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; @@ -61,6 +66,10 @@ import java.util.Map; public class ChooseAccountActivity extends SettingsPreferenceFragment { private static final String TAG = "ChooseAccountActivity"; + + private EnterprisePrivacyFeatureProvider mFeatureProvider; + private FooterPreference mEnterpriseDisclosurePreference = null; + private String[] mAuthorities; private PreferenceGroup mAddAccountGroup; private final ArrayList mProviderList = new ArrayList(); @@ -101,6 +110,10 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment { public void onCreate(Bundle icicle) { super.onCreate(icicle); + final Activity activity = getActivity(); + mFeatureProvider = FeatureFactory.getFactory(activity) + .getEnterprisePrivacyFeatureProvider(activity); + addPreferencesFromResource(R.xml.add_account_settings); mAuthorities = getIntent().getStringArrayExtra( AccountPreferenceBase.AUTHORITIES_FILTER_KEY); @@ -187,6 +200,7 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment { p.checkAccountManagementAndSetDisabled(mUserHandle.getIdentifier()); mAddAccountGroup.addPreference(p); } + addEnterpriseDisclosure(); } else { if (Log.isLoggable(TAG, Log.VERBOSE)) { final StringBuilder auths = new StringBuilder(); @@ -201,6 +215,19 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment { } } + private void addEnterpriseDisclosure() { + final CharSequence disclosure = mFeatureProvider.getDeviceOwnerDisclosure(getActivity()); + if (disclosure == null) { + return; + } + if (mEnterpriseDisclosurePreference == null) { + mEnterpriseDisclosurePreference = mFooterPreferenceMixin.createFooterPreference(); + mEnterpriseDisclosurePreference.setSelectable(false); + } + mEnterpriseDisclosurePreference.setTitle(disclosure); + mAddAccountGroup.addPreference(mEnterpriseDisclosurePreference); + } + public ArrayList getAuthoritiesForAccountType(String type) { if (mAccountTypeToAuthorities == null) { mAccountTypeToAuthorities = Maps.newHashMap(); diff --git a/src/com/android/settings/enterprise/DevicePolicyManagerWrapper.java b/src/com/android/settings/enterprise/DevicePolicyManagerWrapper.java index a23448ebd43..5be78849280 100644 --- a/src/com/android/settings/enterprise/DevicePolicyManagerWrapper.java +++ b/src/com/android/settings/enterprise/DevicePolicyManagerWrapper.java @@ -33,6 +33,13 @@ public interface DevicePolicyManagerWrapper { */ ComponentName getDeviceOwnerComponentOnAnyUser(); + /** + * Calls {@code DevicePolicyManager.getDeviceOwnerNameOnAnyUser()}. + * + * @see android.app.admin.DevicePolicyManager#getDeviceOwnerNameOnAnyUser + */ + public CharSequence getDeviceOwnerOrganizationName(); + /** * Calls {@code DevicePolicyManager.getPermissionGrantState()}. * diff --git a/src/com/android/settings/enterprise/DevicePolicyManagerWrapperImpl.java b/src/com/android/settings/enterprise/DevicePolicyManagerWrapperImpl.java index d122ec645ef..6e162a8bf59 100644 --- a/src/com/android/settings/enterprise/DevicePolicyManagerWrapperImpl.java +++ b/src/com/android/settings/enterprise/DevicePolicyManagerWrapperImpl.java @@ -32,6 +32,11 @@ public class DevicePolicyManagerWrapperImpl implements DevicePolicyManagerWrappe return mDpm.getDeviceOwnerComponentOnAnyUser(); } + @Override + public CharSequence getDeviceOwnerOrganizationName() { + return mDpm.getDeviceOwnerOrganizationName(); + } + @Override public int getPermissionGrantState(@Nullable ComponentName admin, String packageName, String permission) { diff --git a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java index 43f69032a13..91ad119a7fc 100644 --- a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java +++ b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java @@ -16,6 +16,8 @@ package com.android.settings.enterprise; +import android.content.Context; + import java.util.Date; public interface EnterprisePrivacyFeatureProvider { @@ -31,6 +33,15 @@ public interface EnterprisePrivacyFeatureProvider { */ boolean isInCompMode(); + /** + * Returns a message informing the user that the device is managed by a Device Owner app. The + * message includes a Learn More link that takes the user to the enterprise privacy section of + * Settings. If the device is not managed by a Device Owner app, returns {@code null}. + * + * @param context The context in which to show the enterprise privacy section of Settings + */ + CharSequence getDeviceOwnerDisclosure(Context context); + /** * Returns the time at which the Device Owner last retrieved security logs, or {@code null} if * logs were never retrieved by the Device Owner on this device. diff --git a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java index 9fbb0835721..bb5412b8cbc 100644 --- a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java +++ b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java @@ -16,11 +16,19 @@ package com.android.settings.enterprise; +import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.content.res.Resources; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; +import android.text.SpannableStringBuilder; +import android.text.style.ClickableSpan; +import android.view.View; +import com.android.settings.R; import com.android.settings.applications.PackageManagerWrapper; import com.android.settings.vpn2.ConnectivityManagerWrapper; import com.android.settings.vpn2.VpnUtils; @@ -34,15 +42,18 @@ public class EnterprisePrivacyFeatureProviderImpl implements EnterprisePrivacyFe private final PackageManagerWrapper mPm; private final UserManager mUm; private final ConnectivityManagerWrapper mCm; + private final Resources mResources; private static final int MY_USER_ID = UserHandle.myUserId(); public EnterprisePrivacyFeatureProviderImpl(DevicePolicyManagerWrapper dpm, - PackageManagerWrapper pm, UserManager um, ConnectivityManagerWrapper cm) { + PackageManagerWrapper pm, UserManager um, ConnectivityManagerWrapper cm, + Resources resources) { mDpm = dpm; mPm = pm; mUm = um; mCm = cm; + mResources = resources; } @Override @@ -67,6 +78,26 @@ public class EnterprisePrivacyFeatureProviderImpl implements EnterprisePrivacyFe return hasDeviceOwner() && getManagedProfileUserId() != -1; } + @Override + public CharSequence getDeviceOwnerDisclosure(Context context) { + if (!hasDeviceOwner()) { + return null; + } + + final SpannableStringBuilder disclosure = new SpannableStringBuilder(); + final CharSequence organizationName = mDpm.getDeviceOwnerOrganizationName(); + if (organizationName != null) { + disclosure.append(mResources.getString(R.string.do_disclosure_with_name, + organizationName)); + } else { + disclosure.append(mResources.getString(R.string.do_disclosure_generic)); + } + disclosure.append(mResources.getString(R.string.do_disclosure_learn_more_separator)); + disclosure.append(mResources.getString(R.string.do_disclosure_learn_more), + new EnterprisePrivacySpan(context), 0); + return disclosure; + } + @Override public Date getLastSecurityLogRetrievalTime() { final long timestamp = mDpm.getLastSecurityLogRetrievalTime(); @@ -101,4 +132,23 @@ public class EnterprisePrivacyFeatureProviderImpl implements EnterprisePrivacyFe public boolean isGlobalHttpProxySet() { return mCm.getGlobalProxy() != null; } + + protected static class EnterprisePrivacySpan extends ClickableSpan { + private final Context mContext; + + public EnterprisePrivacySpan(Context context) { + mContext = context; + } + + @Override + public void onClick(View widget) { + mContext.startActivity(new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)); + } + + @Override + public boolean equals(Object object) { + return object instanceof EnterprisePrivacySpan + && ((EnterprisePrivacySpan) object).mContext == mContext; + } + } } diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java index 18fcaafaa1e..342ac731c64 100644 --- a/src/com/android/settings/overlay/FeatureFactoryImpl.java +++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java @@ -111,7 +111,8 @@ public class FeatureFactoryImpl extends FeatureFactory { new PackageManagerWrapperImpl(context.getPackageManager()), UserManager.get(context), new ConnectivityManagerWrapperImpl((ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE))); + .getSystemService(Context.CONNECTIVITY_SERVICE)), + context.getResources()); } return mEnterprisePrivacyFeatureProvider; } diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java index 8495603482f..458959ca653 100644 --- a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java +++ b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java @@ -198,7 +198,7 @@ public final class InstalledAppCounterTest { } } - private class IsLaunchIntentFor extends ArgumentMatcher { + private static class IsLaunchIntentFor extends ArgumentMatcher { private final String mPackageName; IsLaunchIntentFor(String packageName) { @@ -211,7 +211,7 @@ public final class InstalledAppCounterTest { if (intent == null) { return false; } - if (intent.getAction() != Intent.ACTION_MAIN) { + if (!Intent.ACTION_MAIN.equals(intent.getAction())) { return false; } final Set categories = intent.getCategories(); diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java index be1296cbe9a..7724db8f84f 100644 --- a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java @@ -17,12 +17,16 @@ package com.android.settings.enterprise; import android.content.ComponentName; +import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.content.res.Resources; import android.net.ProxyInfo; import android.os.UserHandle; import android.os.UserManager; +import android.text.SpannableStringBuilder; +import com.android.settings.R; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.applications.PackageManagerWrapper; @@ -34,12 +38,14 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; import java.util.ArrayList; import java.util.Date; import java.util.List; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** @@ -50,6 +56,7 @@ import static org.mockito.Mockito.when; public final class EnterprisePrivacyFeatureProviderImplTest { private final ComponentName DEVICE_OWNER = new ComponentName("dummy", "component"); + private final String DEVICE_OWNER_ORGANIZATION = new String("ACME"); private final Date TIMESTAMP = new Date(2011, 11, 11); private final int MY_USER_ID = UserHandle.myUserId(); private final int MANAGED_PROFILE_USER_ID = MY_USER_ID + 1; @@ -61,6 +68,7 @@ public final class EnterprisePrivacyFeatureProviderImplTest { private @Mock PackageManagerWrapper mPackageManager; private @Mock UserManager mUserManager; private @Mock ConnectivityManagerWrapper mConnectivityManger; + private Resources mResources; private EnterprisePrivacyFeatureProvider mProvider; @@ -72,9 +80,10 @@ public final class EnterprisePrivacyFeatureProviderImplTest { .thenReturn(true); when(mUserManager.getProfiles(MY_USER_ID)).thenReturn(mProfiles); mProfiles.add(new UserInfo(MY_USER_ID, "", "", 0 /* flags */)); + mResources = ShadowApplication.getInstance().getApplicationContext().getResources(); mProvider = new EnterprisePrivacyFeatureProviderImpl(mDevicePolicyManager, mPackageManager, - mUserManager, mConnectivityManger); + mUserManager, mConnectivityManger, mResources); } @Test @@ -95,6 +104,33 @@ public final class EnterprisePrivacyFeatureProviderImplTest { assertThat(mProvider.isInCompMode()).isTrue(); } + @Test + public void testGetDeviceOwnerDisclosure() { + final Context context = mock(Context.class); + + when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(null); + assertThat(mProvider.getDeviceOwnerDisclosure(context)).isNull(); + + SpannableStringBuilder disclosure = new SpannableStringBuilder(); + disclosure.append(mResources.getString(R.string.do_disclosure_generic)); + disclosure.append(mResources.getString(R.string.do_disclosure_learn_more_separator)); + disclosure.append(mResources.getString(R.string.do_disclosure_learn_more), + new EnterprisePrivacyFeatureProviderImpl.EnterprisePrivacySpan(context), 0); + when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(DEVICE_OWNER); + when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null); + assertThat(mProvider.getDeviceOwnerDisclosure(context)).isEqualTo(disclosure); + + disclosure = new SpannableStringBuilder(); + disclosure.append(mResources.getString(R.string.do_disclosure_with_name, + DEVICE_OWNER_ORGANIZATION)); + disclosure.append(mResources.getString(R.string.do_disclosure_learn_more_separator)); + disclosure.append(mResources.getString(R.string.do_disclosure_learn_more), + new EnterprisePrivacyFeatureProviderImpl.EnterprisePrivacySpan(context), 0); + when(mDevicePolicyManager.getDeviceOwnerOrganizationName()) + .thenReturn(DEVICE_OWNER_ORGANIZATION); + assertThat(mProvider.getDeviceOwnerDisclosure(context)).isEqualTo(disclosure); + } + @Test public void testGetLastSecurityLogRetrievalTime() { when(mDevicePolicyManager.getLastSecurityLogRetrievalTime()).thenReturn(-1L);