diff --git a/src/com/android/settings/RestrictedListPreference.java b/src/com/android/settings/RestrictedListPreference.java index 25d4fc98d8f..d581af6ad26 100644 --- a/src/com/android/settings/RestrictedListPreference.java +++ b/src/com/android/settings/RestrictedListPreference.java @@ -16,10 +16,16 @@ package com.android.settings; +import android.app.ActivityManager; import android.app.AlertDialog; +import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; +import android.os.RemoteException; +import android.os.UserManager; +import android.support.annotation.VisibleForTesting; import android.support.v14.preference.ListPreferenceDialogFragment; import android.support.v7.preference.PreferenceViewHolder; import android.util.AttributeSet; @@ -32,6 +38,7 @@ import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; +import com.android.settings.Utils; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreferenceHelper; @@ -43,6 +50,8 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; public class RestrictedListPreference extends CustomListPreference { private final RestrictedPreferenceHelper mHelper; private final List mRestrictedItems = new ArrayList<>(); + private boolean mRequiresActiveUnlockedProfile = false; + private int mProfileUserId; public RestrictedListPreference(Context context, AttributeSet attrs) { super(context, attrs); @@ -68,6 +77,24 @@ public class RestrictedListPreference extends CustomListPreference { @Override public void performClick() { + if (mRequiresActiveUnlockedProfile) { + // Check if the profile is started, first. + if (Utils.startQuietModeDialogIfNecessary(getContext(), UserManager.get(getContext()), + mProfileUserId)) { + return; + } + + // Next, check if the profile is unlocked. + KeyguardManager manager = + (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); + if (manager.isDeviceLocked(mProfileUserId)) { + Intent intent = manager.createConfirmDeviceCredentialIntent( + null, null, mProfileUserId); + getContext().startActivity(intent); + return; + } + } + if (!mHelper.performClick()) { super.performClick(); } @@ -92,6 +119,14 @@ public class RestrictedListPreference extends CustomListPreference { return mHelper.isDisabledByAdmin(); } + public void setRequiresActiveUnlockedProfile(boolean reqState) { + mRequiresActiveUnlockedProfile = reqState; + } + + public void setProfileUserId(int profileUserId) { + mProfileUserId = profileUserId; + } + public boolean isRestrictedForEntry(CharSequence entry) { if (entry == null) { return false; @@ -263,4 +298,4 @@ public class RestrictedListPreference extends CustomListPreference { this.enforcedAdmin = enforcedAdmin; } } -} \ No newline at end of file +} diff --git a/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java b/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java index 2dfe8f35ab6..3b4f00eebb5 100644 --- a/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java +++ b/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java @@ -19,16 +19,12 @@ package com.android.settings.notification; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; -import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; -import android.app.KeyguardManager; import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; -import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -101,6 +97,8 @@ public class LockScreenNotificationPreferenceController extends AbstractPreferen } if (mProfileUserId != UserHandle.USER_NULL) { mLockscreenProfile = (RestrictedListPreference) screen.findPreference(mWorkSettingKey); + mLockscreenProfile.setRequiresActiveUnlockedProfile(true); + mLockscreenProfile.setProfileUserId(mProfileUserId); } else { setVisible(screen, mWorkSettingKey, false /* visible */); setVisible(screen, mWorkSettingCategoryKey, false /* visible */); @@ -244,39 +242,6 @@ public class LockScreenNotificationPreferenceController extends AbstractPreferen return false; } - @Override - public boolean handlePreferenceTreeClick(Preference preference) { - final String key = preference.getKey(); - if (!TextUtils.equals(mWorkSettingKey, key)) { - return false; - } - - // Check if the profile is started, first. - if (Utils.startQuietModeDialogIfNecessary(mContext, UserManager.get(mContext), - mProfileUserId)) { - return true; - } - - // Next, check if the profile is unlocked. - KeyguardManager manager = - (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); - if (manager.isDeviceLocked(mProfileUserId)) { - //TODO: Figure out how to return the user to the current activity so they - //don't have to navigate to the settings again. - Intent intent = manager.createConfirmDeviceCredentialIntent( - null, null, mProfileUserId); - try { - ActivityManager.getService().startConfirmDeviceCredentialIntent(intent, - null /*options*/); - } catch (RemoteException ignored) { - } - - return true; - } - - return false; - } - private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry, CharSequence entryValue, int keyguardNotificationFeatures) { RestrictedLockUtils.EnforcedAdmin admin = diff --git a/tests/robotests/src/com/android/settings/RestrictedListPreferenceTest.java b/tests/robotests/src/com/android/settings/RestrictedListPreferenceTest.java new file mode 100644 index 00000000000..1cca8428761 --- /dev/null +++ b/tests/robotests/src/com/android/settings/RestrictedListPreferenceTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2018 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; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.RuntimeEnvironment.application; +import static org.robolectric.Shadows.shadowOf; + +import android.app.KeyguardManager; +import android.content.Intent; +import android.os.Bundle; +import android.util.AttributeSet; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowUserManager; +import com.android.settingslib.RestrictedPreferenceHelper; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowKeyguardManager; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config( + shadows = { + ShadowUserManager.class, + ShadowKeyguardManager.class, + }) +public class RestrictedListPreferenceTest { + private static final int PROFILE_USER_ID = 11; + // From UnlaunchableAppActivity + private static final int UNLAUNCHABLE_REASON_QUIET_MODE = 1; + private static final String EXTRA_UNLAUNCHABLE_REASON = "unlaunchable_reason"; + + private ShadowUserManager mShadowUserManager; + private ShadowKeyguardManager mShadowKeyguardManager; + private RestrictedListPreference mPreference; + private RestrictedPreferenceHelper mMockHelper; + + @Before + public void setUp() { + mShadowKeyguardManager = + Shadows.shadowOf(application.getSystemService(KeyguardManager.class)); + mMockHelper = mock(RestrictedPreferenceHelper.class); + mShadowUserManager = ShadowUserManager.getShadow(); + mPreference = new RestrictedListPreference(application, mock(AttributeSet.class)); + mPreference.setProfileUserId(PROFILE_USER_ID); + ReflectionHelpers.setField(mPreference, "mHelper", mMockHelper); + } + + @Test + public void performClick_profileLocked() { + mPreference.setRequiresActiveUnlockedProfile(true); + mShadowUserManager.setQuietModeEnabled(false); + mShadowKeyguardManager.setIsDeviceLocked(PROFILE_USER_ID, true); + // Device has to be marked as secure so the real KeyguardManager will create a non-null + // intent. + mShadowKeyguardManager.setIsDeviceSecure(PROFILE_USER_ID, true); + mPreference.performClick(); + // Make sure that the performClick method on the helper is never reached. + verify(mMockHelper, never()).performClick(); + // Assert that a CONFIRM_DEVICE_CREDENTIAL intent has been started. + Intent started = shadowOf(application).getNextStartedActivity(); + assertThat(started.getExtras().getInt(Intent.EXTRA_USER_ID)).isEqualTo(PROFILE_USER_ID); + assertThat(started.getAction()) + .isEqualTo(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER); + } + + @Test + public void performClick_profileDisabled() { + mPreference.setRequiresActiveUnlockedProfile(true); + mShadowUserManager.setQuietModeEnabled(true); + mShadowKeyguardManager.setIsDeviceLocked(PROFILE_USER_ID, false); + mPreference.performClick(); + // Make sure that the performClick method on the helper is never reached. + verify(mMockHelper, never()).performClick(); + // Assert that a new intent for enabling the work profile is started. + Intent started = shadowOf(application).getNextStartedActivity(); + Bundle extras = started.getExtras(); + int reason = extras.getInt(EXTRA_UNLAUNCHABLE_REASON); + assertThat(reason).isEqualTo(UNLAUNCHABLE_REASON_QUIET_MODE); + } + + @Test + public void performClick_profileAvailable() { + // Verify that the helper's perfomClick method is called if the profile is + // available and unlocked. + mPreference.setRequiresActiveUnlockedProfile(true); + mShadowUserManager.setQuietModeEnabled(false); + mShadowKeyguardManager.setIsDeviceLocked(PROFILE_USER_ID, false); + when(mMockHelper.performClick()).thenReturn(true); + mPreference.performClick(); + verify(mMockHelper).performClick(); + } + + @Test + public void performClick_profileLockedAndUnlockedProfileNotRequired() { + // Verify that even if the profile is disabled, if the Preference class does not + // require it than the regular flow takes place. + mPreference.setRequiresActiveUnlockedProfile(false); + mShadowUserManager.setQuietModeEnabled(true); + when(mMockHelper.performClick()).thenReturn(true); + mPreference.performClick(); + verify(mMockHelper).performClick(); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java index f7fd12f58fe..d83c8148fff 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java @@ -44,6 +44,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager private final Map> mRestrictionSources = new HashMap<>(); private final List mUserProfileInfos = new ArrayList<>(); private final Set mManagedProfiles = new HashSet<>(); + private boolean mIsQuietModeEnabled = false; @Resetter public void reset() { @@ -52,6 +53,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager mUserProfileInfos.clear(); mRestrictionSources.clear(); mManagedProfiles.clear(); + mIsQuietModeEnabled = false; } public void setUserInfo(int userHandle, UserInfo userInfo) { @@ -110,4 +112,13 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager public void addManagedProfile(int userId) { mManagedProfiles.add(userId); } + + @Implementation + public boolean isQuietModeEnabled(UserHandle userHandle) { + return mIsQuietModeEnabled; + } + + public void setQuietModeEnabled(boolean enabled) { + mIsQuietModeEnabled = enabled; + } }