Require work profile to be unlocked for changing notification settings in a different way
Rather than check for the state of the work profile in LockScreenNotificationPreferenceController#handlePreferenceTreeClick, do so in the RestrictedListPreference#performClick. The drawback of checking the state in handlePreferenceTreeClick is that the preferences are displayed first and then the requirement to unlock/enable the work profile is displayed on top of it. This is rather poor UX, so switch to doing the check in performClick and returning early if the work profile needs to be unlocked/enabled. This is similar to Patchset 1 from ag/3805482. The main difference is that the user is returned to the settings screen both after enabling the work profile and unlocking it. Test: Manually with TestDPC Test: atest SettingsRoboTests:RestrictedListPreferenceTest Bug: 77408805 Change-Id: Id168911b082fffac193cd7c7a658ab92d6ce2c15
This commit is contained in:
@@ -16,10 +16,16 @@
|
|||||||
|
|
||||||
package com.android.settings;
|
package com.android.settings;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.app.KeyguardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.ListPreferenceDialogFragment;
|
import androidx.preference.ListPreferenceDialogFragment;
|
||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -32,6 +38,7 @@ import android.widget.ImageView;
|
|||||||
import android.widget.ListAdapter;
|
import android.widget.ListAdapter;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import com.android.settings.Utils;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
import com.android.settingslib.RestrictedPreferenceHelper;
|
import com.android.settingslib.RestrictedPreferenceHelper;
|
||||||
|
|
||||||
@@ -43,6 +50,8 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
|||||||
public class RestrictedListPreference extends CustomListPreference {
|
public class RestrictedListPreference extends CustomListPreference {
|
||||||
private final RestrictedPreferenceHelper mHelper;
|
private final RestrictedPreferenceHelper mHelper;
|
||||||
private final List<RestrictedItem> mRestrictedItems = new ArrayList<>();
|
private final List<RestrictedItem> mRestrictedItems = new ArrayList<>();
|
||||||
|
private boolean mRequiresActiveUnlockedProfile = false;
|
||||||
|
private int mProfileUserId;
|
||||||
|
|
||||||
public RestrictedListPreference(Context context, AttributeSet attrs) {
|
public RestrictedListPreference(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@@ -68,6 +77,24 @@ public class RestrictedListPreference extends CustomListPreference {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performClick() {
|
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()) {
|
if (!mHelper.performClick()) {
|
||||||
super.performClick();
|
super.performClick();
|
||||||
}
|
}
|
||||||
@@ -92,6 +119,14 @@ public class RestrictedListPreference extends CustomListPreference {
|
|||||||
return mHelper.isDisabledByAdmin();
|
return mHelper.isDisabledByAdmin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRequiresActiveUnlockedProfile(boolean reqState) {
|
||||||
|
mRequiresActiveUnlockedProfile = reqState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfileUserId(int profileUserId) {
|
||||||
|
mProfileUserId = profileUserId;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRestrictedForEntry(CharSequence entry) {
|
public boolean isRestrictedForEntry(CharSequence entry) {
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -263,4 +298,4 @@ public class RestrictedListPreference extends CustomListPreference {
|
|||||||
this.enforcedAdmin = enforcedAdmin;
|
this.enforcedAdmin = enforcedAdmin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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_SECURE_NOTIFICATIONS;
|
||||||
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
|
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.app.KeyguardManager;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -101,6 +97,8 @@ public class LockScreenNotificationPreferenceController extends AbstractPreferen
|
|||||||
}
|
}
|
||||||
if (mProfileUserId != UserHandle.USER_NULL) {
|
if (mProfileUserId != UserHandle.USER_NULL) {
|
||||||
mLockscreenProfile = (RestrictedListPreference) screen.findPreference(mWorkSettingKey);
|
mLockscreenProfile = (RestrictedListPreference) screen.findPreference(mWorkSettingKey);
|
||||||
|
mLockscreenProfile.setRequiresActiveUnlockedProfile(true);
|
||||||
|
mLockscreenProfile.setProfileUserId(mProfileUserId);
|
||||||
} else {
|
} else {
|
||||||
setVisible(screen, mWorkSettingKey, false /* visible */);
|
setVisible(screen, mWorkSettingKey, false /* visible */);
|
||||||
setVisible(screen, mWorkSettingCategoryKey, false /* visible */);
|
setVisible(screen, mWorkSettingCategoryKey, false /* visible */);
|
||||||
@@ -244,39 +242,6 @@ public class LockScreenNotificationPreferenceController extends AbstractPreferen
|
|||||||
return false;
|
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,
|
private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry,
|
||||||
CharSequence entryValue, int keyguardNotificationFeatures) {
|
CharSequence entryValue, int keyguardNotificationFeatures) {
|
||||||
RestrictedLockUtils.EnforcedAdmin admin =
|
RestrictedLockUtils.EnforcedAdmin admin =
|
||||||
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
@@ -44,6 +44,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
|||||||
private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>();
|
private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>();
|
||||||
private final List<UserInfo> mUserProfileInfos = new ArrayList<>();
|
private final List<UserInfo> mUserProfileInfos = new ArrayList<>();
|
||||||
private final Set<Integer> mManagedProfiles = new HashSet<>();
|
private final Set<Integer> mManagedProfiles = new HashSet<>();
|
||||||
|
private boolean mIsQuietModeEnabled = false;
|
||||||
|
|
||||||
@Resetter
|
@Resetter
|
||||||
public void reset() {
|
public void reset() {
|
||||||
@@ -52,6 +53,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
|||||||
mUserProfileInfos.clear();
|
mUserProfileInfos.clear();
|
||||||
mRestrictionSources.clear();
|
mRestrictionSources.clear();
|
||||||
mManagedProfiles.clear();
|
mManagedProfiles.clear();
|
||||||
|
mIsQuietModeEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserInfo(int userHandle, UserInfo userInfo) {
|
public void setUserInfo(int userHandle, UserInfo userInfo) {
|
||||||
@@ -110,4 +112,13 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
|||||||
public void addManagedProfile(int userId) {
|
public void addManagedProfile(int userId) {
|
||||||
mManagedProfiles.add(userId);
|
mManagedProfiles.add(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public boolean isQuietModeEnabled(UserHandle userHandle) {
|
||||||
|
return mIsQuietModeEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuietModeEnabled(boolean enabled) {
|
||||||
|
mIsQuietModeEnabled = enabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user