Snap for 4759746 from f249555f97 to pi-release

Change-Id: If4a6919ce0aa7856040fa5a7e39fe879bd8532b6
This commit is contained in:
android-build-team Robot
2018-05-03 07:21:58 +00:00
15 changed files with 420 additions and 72 deletions

View File

@@ -7365,9 +7365,9 @@
<!-- Do not disturb onboarding dialog, do not accept new settings [CHAR LIMIT=30]-->
<string name="zen_onboarding_no_update">Don\'t update</string>
<!-- Do not disturb onboarding dialog, description of new settings [CHAR LIMIT=NONE]-->
<string name="zen_onboarding_dnd_visual_disturbances_description">Your phone mutes sounds &amp; vibrations\n\nUpdate settings to also:\n\n- Hide notifications\n\n- Only show calls from starred contacts</string>
<string name="zen_onboarding_dnd_visual_disturbances_description">Your phone can do more to help you focus.\n\nUpdate settings to:\n\n- Hide notifications completely\n\n- Allow calls from starred contacts and repeat callers</string>
<!-- Do not disturb onboarding dialog, header prompt for settings [CHAR LIMIT=80]-->
<string name="zen_onboarding_dnd_visual_disturbances_header">Update your Do Not Disturb settings?</string>
<string name="zen_onboarding_dnd_visual_disturbances_header">Update Do Not Disturb?</string>
<!-- obsolete -->
<string name="zen_onboarding_settings">Settings</string>

View File

@@ -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<RestrictedItem> 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;
}
}
}
}

View File

@@ -56,6 +56,7 @@ public final class BluetoothDevicePreference extends GearPreference implements
private AlertDialog mDisconnectDialog;
private String contentDescription = null;
private boolean mHideSecondTarget = false;
/* Talk-back descriptions for various BT icons */
Resources mResources;
@@ -86,7 +87,8 @@ public final class BluetoothDevicePreference extends GearPreference implements
protected boolean shouldHideSecondTarget() {
return mCachedDevice == null
|| mCachedDevice.getBondState() != BluetoothDevice.BOND_BONDED
|| mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH);
|| mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)
|| mHideSecondTarget;
}
@Override
@@ -112,6 +114,10 @@ public final class BluetoothDevicePreference extends GearPreference implements
return mCachedDevice;
}
public void hideSecondTarget(boolean hideSecondTarget) {
mHideSecondTarget = hideSecondTarget;
}
public void onDeviceAttributesChanged() {
/*
* The preference framework takes care of making sure the value has

View File

@@ -56,29 +56,14 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
protected final DevicePreferenceCallback mDevicePreferenceCallback;
protected final Map<BluetoothDevice, Preference> mPreferenceMap;
protected Context mPrefContext;
protected DashboardFragment mFragment;
private final boolean mShowDeviceWithoutNames;
private DashboardFragment mFragment;
private Preference.OnPreferenceClickListener mDevicePreferenceClickListener = null;
@VisibleForTesting
final GearPreference.OnGearClickListener mDeviceProfilesListener = pref -> {
final CachedBluetoothDevice device =
((BluetoothDevicePreference) pref).getBluetoothDevice();
if (device == null) {
return;
}
final Bundle args = new Bundle();
args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS,
device.getDevice().getAddress());
new SubSettingLauncher(mFragment.getContext())
.setDestination(BluetoothDeviceDetailsFragment.class.getName())
.setArguments(args)
.setTitle(R.string.device_details_title)
.setSourceMetricsCategory(mFragment.getMetricsCategory())
.launch();
launchDeviceDetails(pref);
};
private class PreferenceClickListener implements
@@ -201,7 +186,7 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
public abstract boolean isFilterMatched(CachedBluetoothDevice cachedBluetoothDevice);
/**
* Update whether to show {@cde cachedBluetoothDevice} in the list.
* Update whether to show {@link CachedBluetoothDevice} in the list.
*/
protected void update(CachedBluetoothDevice cachedBluetoothDevice) {
if (isFilterMatched(cachedBluetoothDevice)) {
@@ -239,6 +224,28 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
}
}
/**
* Get {@link CachedBluetoothDevice} from {@link Preference} and it is used to init
* {@link SubSettingLauncher} to launch {@link BluetoothDeviceDetailsFragment}
*/
protected void launchDeviceDetails(Preference preference) {
final CachedBluetoothDevice device =
((BluetoothDevicePreference) preference).getBluetoothDevice();
if (device == null) {
return;
}
final Bundle args = new Bundle();
args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS,
device.getDevice().getAddress());
new SubSettingLauncher(mFragment.getContext())
.setDestination(BluetoothDeviceDetailsFragment.class.getName())
.setArguments(args)
.setTitle(R.string.device_details_title)
.setSourceMetricsCategory(mFragment.getMetricsCategory())
.launch();
}
/**
* @return {@code true} if {@code cachedBluetoothDevice} is connected
* and the bond state is bonded.

View File

@@ -16,11 +16,14 @@
package com.android.settings.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.util.Log;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -116,4 +119,20 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater {
}
return isFilterMatched;
}
@Override
protected void addPreference(CachedBluetoothDevice cachedDevice) {
super.addPreference(cachedDevice);
final BluetoothDevice device = cachedDevice.getDevice();
if (mPreferenceMap.containsKey(device)) {
final BluetoothDevicePreference btPreference =
(BluetoothDevicePreference) mPreferenceMap.get(device);
btPreference.setOnGearClickListener(null);
btPreference.hideSecondTarget(true);
btPreference.setOnPreferenceClickListener((Preference p) -> {
launchDeviceDetails(p);
return true;
});
}
}
}

View File

@@ -24,6 +24,10 @@ import android.content.Context;
import android.content.ContentResolver;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties;
import android.net.Network;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -31,6 +35,7 @@ import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.internal.util.ArrayUtils;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
@@ -38,6 +43,8 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import java.net.InetAddress;
import java.util.List;
public class PrivateDnsPreferenceController extends BasePreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
@@ -50,12 +57,15 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
private final Handler mHandler;
private final ContentObserver mSettingsObserver;
private final ConnectivityManager mConnectivityManager;
private LinkProperties mLatestLinkProperties;
private Preference mPreference;
public PrivateDnsPreferenceController(Context context) {
super(context, KEY_PRIVATE_DNS_SETTINGS);
mHandler = new Handler(Looper.getMainLooper());
mSettingsObserver = new PrivateDnsSettingsObserver(mHandler);
mConnectivityManager = context.getSystemService(ConnectivityManager.class);
}
@Override
@@ -80,11 +90,17 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
for (Uri uri : SETTINGS_URIS) {
mContext.getContentResolver().registerContentObserver(uri, false, mSettingsObserver);
}
final Network defaultNetwork = mConnectivityManager.getActiveNetwork();
if (defaultNetwork != null) {
mLatestLinkProperties = mConnectivityManager.getLinkProperties(defaultNetwork);
}
mConnectivityManager.registerDefaultNetworkCallback(mNetworkCallback, mHandler);
}
@Override
public void onStop() {
mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
@Override
@@ -92,13 +108,23 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
final Resources res = mContext.getResources();
final ContentResolver cr = mContext.getContentResolver();
final String mode = PrivateDnsModeDialogPreference.getModeFromSettings(cr);
final LinkProperties lp = mLatestLinkProperties;
final List<InetAddress> dnses = (lp == null) ? null : lp.getValidatedPrivateDnsServers();
final boolean dnsesResolved = !ArrayUtils.isEmpty(dnses);
switch (mode) {
case PRIVATE_DNS_MODE_OFF:
return res.getString(R.string.private_dns_mode_off);
case PRIVATE_DNS_MODE_OPPORTUNISTIC:
return res.getString(R.string.private_dns_mode_opportunistic);
// TODO (b/79122154) : create a string specifically for this, instead of
// hijacking a string from notifications. This is necessary at this time
// because string freeze is in the past and this string has the right
// content at this moment.
return dnsesResolved ? res.getString(R.string.switch_on_text)
: res.getString(R.string.private_dns_mode_opportunistic);
case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
return PrivateDnsModeDialogPreference.getHostnameFromSettings(cr);
return dnsesResolved
? PrivateDnsModeDialogPreference.getHostnameFromSettings(cr)
: res.getString(R.string.private_dns_mode_provider_failure);
}
return "";
}
@@ -111,8 +137,25 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
@Override
public void onChange(boolean selfChange) {
if (mPreference != null) {
PrivateDnsPreferenceController.this.updateState(mPreference);
updateState(mPreference);
}
}
}
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
mLatestLinkProperties = lp;
if (mPreference != null) {
updateState(mPreference);
}
}
@Override
public void onLost(Network network) {
mLatestLinkProperties = null;
if (mPreference != null) {
updateState(mPreference);
}
}
};
}

View File

@@ -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 =

View File

@@ -18,12 +18,10 @@ package com.android.settings.notification;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.Intent;
import android.app.NotificationManager.Policy;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.view.View;
import android.widget.CheckBox;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -67,12 +65,13 @@ public class ZenOnboardingActivity extends Activity {
public void save(View button) {
mMetrics.action(MetricsEvent.ACTION_ZEN_ONBOARDING_OK);
NotificationManager.Policy policy = mNm.getNotificationPolicy();
Policy policy = mNm.getNotificationPolicy();
NotificationManager.Policy newPolicy = new NotificationManager.Policy(
policy.priorityCategories, NotificationManager.Policy.PRIORITY_SENDERS_STARRED,
Policy newPolicy = new NotificationManager.Policy(
Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | policy.priorityCategories,
Policy.PRIORITY_SENDERS_STARRED,
policy.priorityMessageSenders,
NotificationManager.Policy.getAllSuppressedVisualEffects());
Policy.getAllSuppressedVisualEffects());
mNm.setNotificationPolicy(newPolicy);
finishAndRemoveTask();

View File

@@ -25,6 +25,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.ColorInt;
import android.support.annotation.StringRes;
import android.support.annotation.VisibleForTesting;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.TextAppearanceSpan;
@@ -132,6 +133,17 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
(switchView, isChecked) -> setTextViewLabelAndBackground(isChecked));
mRestrictedIcon = findViewById(R.id.restricted_icon);
mRestrictedIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mDisabledByAdmin) {
mMetricsFeatureProvider.count(mContext,
mMetricsTag + "/switch_bar|restricted", 1);
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context,
mEnforcedAdmin);
}
}
});
// Default is hide
setVisibility(View.GONE);
@@ -196,6 +208,11 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
mSwitch.setEnabled(enabled);
}
@VisibleForTesting
View getDelegatingView() {
return mDisabledByAdmin ? mRestrictedIcon : mSwitch;
}
/**
* If admin is not null, disables the text and switch but keeps the view clickable.
* Otherwise, calls setEnabled which will enables the entire view including
@@ -216,6 +233,8 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
mRestrictedIcon.setVisibility(View.GONE);
setEnabled(true);
}
setTouchDelegate(new TouchDelegate(new Rect(0, 0, getWidth(), getHeight()),
getDelegatingView()));
}
public final ToggleSwitch getSwitch() {
@@ -228,7 +247,8 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
mSwitch.setOnCheckedChangeListener(this);
// Make the entire bar work as a switch
post(() -> setTouchDelegate(
new TouchDelegate(new Rect(0, 0, getWidth(), getHeight()), mSwitch)));
new TouchDelegate(new Rect(0, 0, getWidth(), getHeight()),
getDelegatingView())));
}
}
@@ -242,7 +262,8 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if ((w > 0) && (h > 0)) {
setTouchDelegate(new TouchDelegate(new Rect(0, 0, w, h), mSwitch));
setTouchDelegate(new TouchDelegate(new Rect(0, 0, w, h),
getDelegatingView()));
}
}

View File

@@ -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();
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.android.settings.bluetooth;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -207,4 +208,15 @@ public class ConnectedBluetoothDeviceUpdaterTest {
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
}
@Test
public void addPreference_addPreference_shouldHideSecondTarget() {
BluetoothDevicePreference btPreference =
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, true);
mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, btPreference);
mBluetoothDeviceUpdater.addPreference(mCachedBluetoothDevice);
assertThat(btPreference.shouldHideSecondTarget()).isTrue();
}
}

View File

@@ -24,17 +24,29 @@ import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.withSettings;
import static org.mockito.Mockito.when;
import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties;
import android.net.Network;
import android.os.Handler;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
@@ -46,22 +58,45 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowContentResolver;
import org.robolectric.shadows.ShadowServiceManager;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class PrivateDnsPreferenceControllerTest {
private final static String HOSTNAME = "dns.example.com";
private final static List<InetAddress> NON_EMPTY_ADDRESS_LIST;
static {
try {
NON_EMPTY_ADDRESS_LIST = Arrays.asList(
InetAddress.getByAddress(new byte[] { 8, 8, 8, 8 }));
} catch (UnknownHostException e) {
throw new RuntimeException("Invalid hardcoded IP addresss: " + e);
}
}
@Mock
private PreferenceScreen mScreen;
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
private Network mNetwork;
@Mock
private Preference mPreference;
@Captor
private ArgumentCaptor<NetworkCallback> mCallbackCaptor;
private PrivateDnsPreferenceController mController;
private Context mContext;
private ContentResolver mContentResolver;
@@ -75,15 +110,41 @@ public class PrivateDnsPreferenceControllerTest {
mContext = spy(RuntimeEnvironment.application);
mContentResolver = mContext.getContentResolver();
mShadowContentResolver = Shadow.extract(mContentResolver);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(mConnectivityManager);
doNothing().when(mConnectivityManager).registerDefaultNetworkCallback(
mCallbackCaptor.capture(), nullable(Handler.class));
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
mController = spy(new PrivateDnsPreferenceController(mContext));
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mLifecycle.addObserver(mController);
}
private void updateLinkProperties(LinkProperties lp) {
NetworkCallback nc = mCallbackCaptor.getValue();
// The network callback that has been captured by the captor is the `mNetworkCallback'
// member of mController. mController being a spy, it has copied that member from the
// original object it was spying on, which means the object returned by the captor
// has a reference to the original object instead of the mock as its outer instance
// and will call methods and modify members of the original object instead of the spy,
// so methods subsequently called on the spy will not be aware of the changes. To work
// around this, the following code will create a new instance of the same class with
// the same code, but it sets the spy as the outer instance.
// A more recent version of Mockito would have made possible to create the spy with
// spy(PrivateDnsPreferenceController.class, withSettings().useConstructor(mContext))
// and that would have solved the problem by removing the original object entirely
// in a more elegant manner, but useConstructor(Object...) is only available starting
// with Mockito 2.7.14. Other solutions involve modifying the code under test for
// the sake of the test.
nc = mock(nc.getClass(), withSettings().useConstructor().outerInstance(mController)
.defaultAnswer(CALLS_REAL_METHODS));
nc.onLinkPropertiesChanged(mNetwork, lp);
}
@Test
public void goThroughLifecycle_shouldRegisterUnregisterSettingsObserver() {
mLifecycle.handleLifecycleEvent(ON_START);
@@ -113,20 +174,50 @@ public class PrivateDnsPreferenceControllerTest {
@Test
public void getSummary_PrivateDnsModeOpportunistic() {
mLifecycle.handleLifecycleEvent(ON_START);
setPrivateDnsMode(PRIVATE_DNS_MODE_OPPORTUNISTIC);
setPrivateDnsProviderHostname(HOSTNAME);
mController.updateState(mPreference);
verify(mController, atLeastOnce()).getSummary();
verify(mPreference).setSummary(getResourceString(R.string.private_dns_mode_opportunistic));
LinkProperties lp = mock(LinkProperties.class);
when(lp.getValidatedPrivateDnsServers()).thenReturn(NON_EMPTY_ADDRESS_LIST);
updateLinkProperties(lp);
mController.updateState(mPreference);
verify(mPreference).setSummary(getResourceString(R.string.switch_on_text));
reset(mPreference);
lp = mock(LinkProperties.class);
when(lp.getValidatedPrivateDnsServers()).thenReturn(Collections.emptyList());
updateLinkProperties(lp);
mController.updateState(mPreference);
verify(mPreference).setSummary(getResourceString(R.string.private_dns_mode_opportunistic));
}
@Test
public void getSummary_PrivateDnsModeProviderHostname() {
mLifecycle.handleLifecycleEvent(ON_START);
setPrivateDnsMode(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
setPrivateDnsProviderHostname(HOSTNAME);
mController.updateState(mPreference);
verify(mController, atLeastOnce()).getSummary();
verify(mPreference).setSummary(
getResourceString(R.string.private_dns_mode_provider_failure));
LinkProperties lp = mock(LinkProperties.class);
when(lp.getValidatedPrivateDnsServers()).thenReturn(NON_EMPTY_ADDRESS_LIST);
updateLinkProperties(lp);
mController.updateState(mPreference);
verify(mPreference).setSummary(HOSTNAME);
reset(mPreference);
lp = mock(LinkProperties.class);
when(lp.getValidatedPrivateDnsServers()).thenReturn(Collections.emptyList());
updateLinkProperties(lp);
mController.updateState(mPreference);
verify(mPreference).setSummary(
getResourceString(R.string.private_dns_mode_provider_failure));
}
private void setPrivateDnsMode(String mode) {

View File

@@ -17,6 +17,7 @@
package com.android.settings.notification;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
@@ -94,7 +95,8 @@ public class ZenOnboardingActivityTest {
verify(mNm).setNotificationPolicy(captor.capture());
Policy actual = captor.getValue();
assertThat(actual.priorityCategories).isEqualTo(PRIORITY_CATEGORY_ALARMS);
assertThat(actual.priorityCategories).isEqualTo(PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_REPEAT_CALLERS);
assertThat(actual.priorityCallSenders).isEqualTo(Policy.PRIORITY_SENDERS_STARRED);
assertThat(actual.priorityMessageSenders).isEqualTo(Policy.PRIORITY_SENDERS_ANY);
assertThat(actual.suppressedVisualEffects).isEqualTo(

View File

@@ -44,6 +44,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>();
private final List<UserInfo> mUserProfileInfos = new ArrayList<>();
private final Set<Integer> 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;
}
}

View File

@@ -26,6 +26,7 @@ import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -82,4 +83,16 @@ public class SwitchBarTest {
assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
.isEqualTo(mContext.getString(onText));
}
@Test
public void disabledByAdmin_shouldDelegateToRestrictedIcon() {
mBar.setDisabledByAdmin(new EnforcedAdmin());
assertThat(mBar.getDelegatingView().getId()).isEqualTo(R.id.restricted_icon);
}
@Test
public void notDisabledByAdmin_shouldDelegateToSwitch() {
mBar.setDisabledByAdmin(null);
assertThat(mBar.getDelegatingView().getId()).isEqualTo(R.id.switch_widget);
}
}