Snap for 4759746 from f249555f97 to pi-release
Change-Id: If4a6919ce0aa7856040fa5a7e39fe879bd8532b6
This commit is contained in:
@@ -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 & 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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user