Snap for 4507345 from 3a2573b812 to pi-release
Change-Id: I4c0fe2b7972aaddfebde3f1e5c4de6a018c56e9d
This commit is contained in:
@@ -178,7 +178,6 @@
|
||||
</activity>
|
||||
|
||||
<activity android:name=".Settings$ConnectedDeviceDashboardActivity"
|
||||
android:enabled="false"
|
||||
android:taskAffinity="com.android.settings"
|
||||
android:label="@string/connected_devices_dashboard_title"
|
||||
android:icon="@drawable/ic_devices_other"
|
||||
@@ -204,6 +203,7 @@
|
||||
</activity>
|
||||
|
||||
<activity android:name=".Settings$ConnectedDeviceDashboardActivityOld"
|
||||
android:enabled="false"
|
||||
android:taskAffinity="com.android.settings"
|
||||
android:label="@string/connected_devices_dashboard_title"
|
||||
android:icon="@drawable/ic_devices_other"
|
||||
|
||||
@@ -4353,6 +4353,8 @@
|
||||
<string name="accessibility_power_button_ends_call_prerefence_title">Power button ends call</string>
|
||||
<!-- Title for the accessibility preference for enabling/disabling large icons for mouse/trackpad pointers. [CHAR LIMIT=35] -->
|
||||
<string name="accessibility_toggle_large_pointer_icon_title">Large mouse pointer</string>
|
||||
<!-- Title for the accessibility preference for disabling animations. [CHAR LIMIT=35] -->
|
||||
<string name="accessibility_disable_animations">Remove animations</string>
|
||||
<!-- Title for the accessibility preference for master mono. [CHAR LIMIT=35] -->
|
||||
<string name="accessibility_toggle_master_mono_title">Mono audio</string>
|
||||
<!-- Summary for the accessibility preference for master mono. [CHAR LIMIT=50] -->
|
||||
@@ -7318,8 +7320,8 @@
|
||||
<!-- [CHAR LIMIT=50] Zen mode settings: Media option -->
|
||||
<string name="zen_mode_media_system_other">Media</string>
|
||||
|
||||
<!-- [CHAR LIMIT=50] Zen mode settings: Media secondary text explaining sounds include system feedback such as system tapping sounds, haptic feedback, etc. -->
|
||||
<string name="zen_mode_media_system_other_secondary_text">Includes system feedback</string>
|
||||
<!-- [CHAR LIMIT=120] Zen mode settings: Media secondary text explaining sounds include system feedback such as system tapping sounds, haptic feedback, etc. -->
|
||||
<string name="zen_mode_media_system_other_secondary_text">Includes system feedback like touch and charging sounds</string>
|
||||
|
||||
<!-- [CHAR LIMIT=50] Zen mode settings: Reminders option -->
|
||||
<string name="zen_mode_reminders">Reminders</string>
|
||||
@@ -9132,4 +9134,9 @@
|
||||
<!-- Note displayed when certain features are not available on low ram devices. [CHAR LIMIT=NONE] -->
|
||||
<string name="disabled_low_ram_device">This feature is not available on this device</string>
|
||||
|
||||
<!-- UI debug setting: enable gnss raw meas full tracking [CHAR LIMIT=25] -->
|
||||
<string name="enable_gnss_raw_meas_full_tracking">Force Full GnssMeasurement</string>
|
||||
<!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] -->
|
||||
<string name="enable_gnss_raw_meas_full_tracking_summary">Disable GNSS duty-cycling, track all constellations and frequencies.</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
<SwitchPreference
|
||||
android:key="toggle_large_pointer_icon"
|
||||
android:title="@string/accessibility_toggle_large_pointer_icon_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="toggle_disable_animations"
|
||||
android:title="@string/accessibility_disable_animations" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
|
||||
@@ -132,6 +132,11 @@
|
||||
<Preference android:key="mock_location_app"
|
||||
android:title="@string/mock_location_app" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="enable_gnss_raw_meas_full_tracking"
|
||||
android:title="@string/enable_gnss_raw_meas_full_tracking"
|
||||
android:summary="@string/enable_gnss_raw_meas_full_tracking_summary"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="debug_view_attributes"
|
||||
android:title="@string/debug_view_attributes" />
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/security_settings_title">
|
||||
|
||||
<SwitchPreference
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="unification"
|
||||
android:title="@string/lock_settings_profile_unification_title"
|
||||
android:summary="@string/lock_settings_profile_unification_summary"
|
||||
|
||||
@@ -37,6 +37,8 @@ import android.security.IKeyChainService;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChain.KeyChainConnection;
|
||||
import android.security.KeyStore;
|
||||
import android.security.keymaster.KeyCharacteristics;
|
||||
import android.security.keymaster.KeymasterDefs;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
@@ -48,19 +50,15 @@ import android.widget.TextView;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
public class UserCredentialsSettings extends SettingsPreferenceFragment
|
||||
implements View.OnClickListener {
|
||||
private static final String TAG = "UserCredentialsSettings";
|
||||
@@ -254,27 +252,57 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
|
||||
return credentials;
|
||||
}
|
||||
|
||||
private boolean isAsymmetric(KeyStore keyStore, String alias, int uid)
|
||||
throws UnrecoverableKeyException {
|
||||
KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
|
||||
int errorCode = keyStore.getKeyCharacteristics(alias, null, null, uid,
|
||||
keyCharacteristics);
|
||||
if (errorCode != KeyStore.NO_ERROR) {
|
||||
throw (UnrecoverableKeyException)
|
||||
new UnrecoverableKeyException("Failed to obtain information about key")
|
||||
.initCause(KeyStore.getKeyStoreException(errorCode));
|
||||
}
|
||||
Integer keymasterAlgorithm = keyCharacteristics.getEnum(
|
||||
KeymasterDefs.KM_TAG_ALGORITHM);
|
||||
if (keymasterAlgorithm == null) {
|
||||
throw new UnrecoverableKeyException("Key algorithm unknown");
|
||||
}
|
||||
return keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA ||
|
||||
keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC;
|
||||
}
|
||||
|
||||
private SortedMap<String, Credential> getCredentialsForUid(KeyStore keyStore, int uid) {
|
||||
final SortedMap<String, Credential> aliasMap = new TreeMap<>();
|
||||
for (final Credential.Type type : Credential.Type.values()) {
|
||||
for (final String alias : keyStore.list(type.prefix, uid)) {
|
||||
if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
|
||||
// Do not show work profile keys in user credentials
|
||||
if (alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT) ||
|
||||
alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT)) {
|
||||
for (final String prefix : type.prefix) {
|
||||
for (final String alias : keyStore.list(prefix, uid)) {
|
||||
if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
|
||||
// Do not show work profile keys in user credentials
|
||||
if (alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT) ||
|
||||
alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT)) {
|
||||
continue;
|
||||
}
|
||||
// Do not show synthetic password keys in user credential
|
||||
if (alias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (type == Credential.Type.USER_KEY &&
|
||||
!isAsymmetric(keyStore, prefix + alias, uid)) {
|
||||
continue;
|
||||
}
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
Log.e(TAG, "Unable to determine algorithm of key: " + prefix + alias, e);
|
||||
continue;
|
||||
}
|
||||
// Do not show synthetic password keys in user credential
|
||||
if (alias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) {
|
||||
continue;
|
||||
Credential c = aliasMap.get(alias);
|
||||
if (c == null) {
|
||||
c = new Credential(alias, uid);
|
||||
aliasMap.put(alias, c);
|
||||
}
|
||||
c.storedTypes.add(type);
|
||||
}
|
||||
Credential c = aliasMap.get(alias);
|
||||
if (c == null) {
|
||||
c = new Credential(alias, uid);
|
||||
aliasMap.put(alias, c);
|
||||
}
|
||||
c.storedTypes.add(type);
|
||||
}
|
||||
}
|
||||
return aliasMap;
|
||||
@@ -344,7 +372,7 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
|
||||
*/
|
||||
private static final SparseArray<Credential.Type> credentialViewTypes = new SparseArray<>();
|
||||
static {
|
||||
credentialViewTypes.put(R.id.contents_userkey, Credential.Type.USER_PRIVATE_KEY);
|
||||
credentialViewTypes.put(R.id.contents_userkey, Credential.Type.USER_KEY);
|
||||
credentialViewTypes.put(R.id.contents_usercrt, Credential.Type.USER_CERTIFICATE);
|
||||
credentialViewTypes.put(R.id.contents_cacrt, Credential.Type.CA_CERTIFICATE);
|
||||
}
|
||||
@@ -380,12 +408,11 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
|
||||
static enum Type {
|
||||
CA_CERTIFICATE (Credentials.CA_CERTIFICATE),
|
||||
USER_CERTIFICATE (Credentials.USER_CERTIFICATE),
|
||||
USER_PRIVATE_KEY (Credentials.USER_PRIVATE_KEY),
|
||||
USER_SECRET_KEY (Credentials.USER_SECRET_KEY);
|
||||
USER_KEY(Credentials.USER_PRIVATE_KEY, Credentials.USER_SECRET_KEY);
|
||||
|
||||
final String prefix;
|
||||
final String[] prefix;
|
||||
|
||||
Type(String prefix) {
|
||||
Type(String... prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
}
|
||||
@@ -407,8 +434,7 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
|
||||
* <ul>
|
||||
* <li>{@link Credentials.CA_CERTIFICATE}</li>
|
||||
* <li>{@link Credentials.USER_CERTIFICATE}</li>
|
||||
* <li>{@link Credentials.USER_PRIVATE_KEY}</li>
|
||||
* <li>{@link Credentials.USER_SECRET_KEY}</li>
|
||||
* <li>{@link Credentials.USER_KEY}</li>
|
||||
* </ul>
|
||||
*/
|
||||
final EnumSet<Type> storedTypes = EnumSet.noneOf(Type.class);
|
||||
|
||||
@@ -97,6 +97,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
"toggle_lock_screen_rotation_preference";
|
||||
private static final String TOGGLE_LARGE_POINTER_ICON =
|
||||
"toggle_large_pointer_icon";
|
||||
private static final String TOGGLE_DISABLE_ANIMATIONS = "toggle_disable_animations";
|
||||
private static final String TOGGLE_MASTER_MONO =
|
||||
"toggle_master_mono";
|
||||
private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
|
||||
@@ -135,6 +136,14 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
// presentation.
|
||||
private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
|
||||
|
||||
// Settings that should be changed when toggling animations
|
||||
private static final String[] TOGGLE_ANIMATION_TARGETS = {
|
||||
Settings.Global.WINDOW_ANIMATION_SCALE, Settings.Global.TRANSITION_ANIMATION_SCALE,
|
||||
Settings.Global.ANIMATOR_DURATION_SCALE
|
||||
};
|
||||
private static final String ANIMATION_ON_VALUE = "1";
|
||||
private static final String ANIMATION_OFF_VALUE = "0";
|
||||
|
||||
private final Map<String, String> mLongPressTimeoutValueToTitleMap = new HashMap<>();
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
@@ -194,6 +203,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
private SwitchPreference mTogglePowerButtonEndsCallPreference;
|
||||
private SwitchPreference mToggleLockScreenRotationPreference;
|
||||
private SwitchPreference mToggleLargePointerIconPreference;
|
||||
private SwitchPreference mToggleDisableAnimationsPreference;
|
||||
private SwitchPreference mToggleMasterMonoPreference;
|
||||
private ListPreference mSelectLongPressTimeoutPreference;
|
||||
private Preference mNoServicesMessagePreference;
|
||||
@@ -317,6 +327,9 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
} else if (mToggleLargePointerIconPreference == preference) {
|
||||
handleToggleLargePointerIconPreferenceClick();
|
||||
return true;
|
||||
} else if (mToggleDisableAnimationsPreference == preference) {
|
||||
handleToggleDisableAnimations();
|
||||
return true;
|
||||
} else if (mToggleMasterMonoPreference == preference) {
|
||||
handleToggleMasterMonoPreferenceClick();
|
||||
return true;
|
||||
@@ -349,6 +362,14 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
mToggleLargePointerIconPreference.isChecked() ? 1 : 0);
|
||||
}
|
||||
|
||||
private void handleToggleDisableAnimations() {
|
||||
String newAnimationValue = mToggleDisableAnimationsPreference.isChecked()
|
||||
? ANIMATION_OFF_VALUE : ANIMATION_ON_VALUE;
|
||||
for (String animationPreference : TOGGLE_ANIMATION_TARGETS) {
|
||||
Settings.Global.putString(getContentResolver(), animationPreference, newAnimationValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleToggleMasterMonoPreferenceClick() {
|
||||
Settings.System.putIntForUser(getContentResolver(), Settings.System.MASTER_MONO,
|
||||
mToggleMasterMonoPreference.isChecked() ? 1 : 0, UserHandle.USER_CURRENT);
|
||||
@@ -389,6 +410,9 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
mToggleLargePointerIconPreference =
|
||||
(SwitchPreference) findPreference(TOGGLE_LARGE_POINTER_ICON);
|
||||
|
||||
mToggleDisableAnimationsPreference =
|
||||
(SwitchPreference) findPreference(TOGGLE_DISABLE_ANIMATIONS);
|
||||
|
||||
// Master Mono
|
||||
mToggleMasterMonoPreference =
|
||||
(SwitchPreference) findPreference(TOGGLE_MASTER_MONO);
|
||||
@@ -620,6 +644,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
mToggleLargePointerIconPreference.setChecked(Settings.Secure.getInt(getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 0) != 0);
|
||||
|
||||
updateDisableAnimationsToggle();
|
||||
|
||||
// Master mono
|
||||
updateMasterMono();
|
||||
|
||||
@@ -702,6 +728,19 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDisableAnimationsToggle() {
|
||||
boolean allAnimationsDisabled = true;
|
||||
for (String animationSetting : TOGGLE_ANIMATION_TARGETS) {
|
||||
if (!TextUtils.equals(
|
||||
Settings.Global.getString(getContentResolver(), animationSetting),
|
||||
ANIMATION_OFF_VALUE)) {
|
||||
allAnimationsDisabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mToggleDisableAnimationsPreference.setChecked(allAnimationsDisabled);
|
||||
}
|
||||
|
||||
private void updateMasterMono() {
|
||||
final boolean masterMono = Settings.System.getIntForUser(
|
||||
getContentResolver(), Settings.System.MASTER_MONO,
|
||||
|
||||
@@ -67,12 +67,6 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
|
||||
return R.xml.connected_devices_advanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategoryKey() {
|
||||
//TODO(b/69926683): remove this method and change DashboardFragmentRegistry directly for P
|
||||
return CategoryKey.CATEGORY_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
|
||||
@@ -265,6 +265,7 @@ public class SettingsGateway {
|
||||
Settings.SoundSettingsActivity.class.getName(),
|
||||
Settings.StorageDashboardActivity.class.getName(),
|
||||
Settings.PowerUsageSummaryActivity.class.getName(),
|
||||
Settings.PowerUsageSummaryLegacyActivity.class.getName(),
|
||||
Settings.UserAndAccountDashboardActivity.class.getName(),
|
||||
Settings.SecuritySettingsActivity.class.getName(),
|
||||
Settings.AccessibilitySettingsActivity.class.getName(),
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.android.settings.accounts.AccountDetailDashboardFragment;
|
||||
import com.android.settings.accounts.UserAndAccountDashboardFragment;
|
||||
import com.android.settings.applications.AppAndNotificationDashboardFragment;
|
||||
import com.android.settings.applications.DefaultAppSettings;
|
||||
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
|
||||
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragmentOld;
|
||||
import com.android.settings.development.DevelopmentSettingsDashboardFragment;
|
||||
import com.android.settings.deviceinfo.StorageDashboardFragment;
|
||||
@@ -62,6 +63,8 @@ public class DashboardFragmentRegistry {
|
||||
//TODO(b/69471219): update ConnectedDeviceDashboardFragment once new feature is done.
|
||||
PARENT_TO_CATEGORY_KEY_MAP.put(ConnectedDeviceDashboardFragmentOld.class.getName(),
|
||||
CategoryKey.CATEGORY_DEVICE);
|
||||
PARENT_TO_CATEGORY_KEY_MAP.put(AdvancedConnectedDeviceDashboardFragment.class.getName(),
|
||||
CategoryKey.CATEGORY_DEVICE);
|
||||
PARENT_TO_CATEGORY_KEY_MAP.put(AppAndNotificationDashboardFragment.class.getName(),
|
||||
CategoryKey.CATEGORY_APPS);
|
||||
PARENT_TO_CATEGORY_KEY_MAP.put(PowerUsageSummary.class.getName(),
|
||||
|
||||
@@ -446,6 +446,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
||||
controllers.add(new ResizableActivityPreferenceController(context));
|
||||
controllers.add(new FreeformWindowsPreferenceController(context));
|
||||
controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
|
||||
controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));
|
||||
return controllers;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.development;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
|
||||
|
||||
public class EnableGnssRawMeasFullTrackingPreferenceController extends
|
||||
DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
|
||||
PreferenceControllerMixin {
|
||||
|
||||
private static final String ENABLE_GNSS_RAW_MEAS_FULL_TRACKING_KEY =
|
||||
"enable_gnss_raw_meas_full_tracking";
|
||||
|
||||
static final int SETTING_VALUE_ON = 1;
|
||||
static final int SETTING_VALUE_OFF = 0;
|
||||
|
||||
private SwitchPreference mPreference;
|
||||
|
||||
public EnableGnssRawMeasFullTrackingPreferenceController(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return ENABLE_GNSS_RAW_MEAS_FULL_TRACKING_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mPreference = (SwitchPreference) screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final boolean isEnabled = (Boolean) newValue;
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
|
||||
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
final int enableGnssRawMeasFullTrackingMode =
|
||||
Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_OFF);
|
||||
mPreference.setChecked(enableGnssRawMeasFullTrackingMode != SETTING_VALUE_OFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeveloperOptionsSwitchEnabled() {
|
||||
mPreference.setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeveloperOptionsSwitchDisabled() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_OFF);
|
||||
mPreference.setEnabled(false);
|
||||
mPreference.setChecked(false);
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,11 @@ public class LocationMode extends DashboardFragment {
|
||||
return Arrays.asList(sir);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
return context.getResources().getBoolean(R.bool.config_location_mode_available);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AbstractPreferenceController> getPreferenceControllers(Context
|
||||
context) {
|
||||
|
||||
@@ -73,6 +73,7 @@ import com.android.settings.security.trustagent.TrustAgentManager.TrustAgentComp
|
||||
import com.android.settings.widget.GearPreference;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
import com.android.settingslib.RestrictedSwitchPreference;
|
||||
import com.android.settingslib.drawer.CategoryKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -144,7 +145,7 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
private ManagedLockPasswordProvider mManagedPasswordProvider;
|
||||
|
||||
private SwitchPreference mVisiblePatternProfile;
|
||||
private SwitchPreference mUnifyProfile;
|
||||
private RestrictedSwitchPreference mUnifyProfile;
|
||||
|
||||
private SwitchPreference mShowPassword;
|
||||
|
||||
@@ -319,7 +320,7 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
|
||||
mVisiblePatternProfile =
|
||||
(SwitchPreference) root.findPreference(KEY_VISIBLE_PATTERN_PROFILE);
|
||||
mUnifyProfile = (SwitchPreference) root.findPreference(KEY_UNIFICATION);
|
||||
mUnifyProfile = (RestrictedSwitchPreference) root.findPreference(KEY_UNIFICATION);
|
||||
|
||||
// Append the rest of the settings
|
||||
addPreferencesFromResource(R.xml.security_settings_misc);
|
||||
@@ -560,10 +561,17 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
mLocationcontroller.updateSummary();
|
||||
}
|
||||
|
||||
private void updateUnificationPreference() {
|
||||
@VisibleForTesting
|
||||
void updateUnificationPreference() {
|
||||
if (mUnifyProfile != null) {
|
||||
mUnifyProfile.setChecked(!mLockPatternUtils.isSeparateProfileChallengeEnabled(
|
||||
mProfileChallengeUserId));
|
||||
final boolean separate =
|
||||
mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId);
|
||||
mUnifyProfile.setChecked(!separate);
|
||||
if (separate) {
|
||||
mUnifyProfile.setDisabledByAdmin(RestrictedLockUtils.checkIfRestrictionEnforced(
|
||||
getContext(), UserManager.DISALLOW_UNIFIED_PASSWORD,
|
||||
mProfileChallengeUserId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,14 +938,11 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
.setPositiveButton(
|
||||
compliant ? R.string.lock_settings_profile_unification_dialog_confirm
|
||||
: R.string.lock_settings_profile_unification_dialog_uncompliant_confirm,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
if (compliant) {
|
||||
parentFragment.launchConfirmDeviceLockForUnification();
|
||||
} else {
|
||||
parentFragment.unifyUncompliantLocks();
|
||||
}
|
||||
(dialog, whichButton) -> {
|
||||
if (compliant) {
|
||||
parentFragment.launchConfirmDeviceLockForUnification();
|
||||
} else {
|
||||
parentFragment.unifyUncompliantLocks();
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -770,7 +770,11 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
|
||||
if (KEY_TTS_ENGINE_PREFERENCE.equals(p.getKey())) {
|
||||
EngineInfo info = mEnginesHelper.getEngineInfo(mCurrentEngine);
|
||||
final Intent settingsIntent = mEnginesHelper.getSettingsIntent(info.name);
|
||||
startActivity(settingsIntent);
|
||||
if (settingsIntent != null) {
|
||||
startActivity(settingsIntent);
|
||||
} else {
|
||||
Log.e(TAG, "settingsIntent is null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,6 +147,11 @@ public class AdvancedConnectedDeviceDashboardFragmentTest {
|
||||
assertThat(keys).doesNotContain(mSmsMirroringPreferenceController.getPreferenceKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCategoryKey_returnCategoryDevice() {
|
||||
assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_DEVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonIndexableKeys_existInXmlLayout() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.development;
|
||||
|
||||
|
||||
import static com.android.settings.development.EnableGnssRawMeasFullTrackingPreferenceController
|
||||
.SETTING_VALUE_OFF;
|
||||
import static com.android.settings.development.EnableGnssRawMeasFullTrackingPreferenceController
|
||||
.SETTING_VALUE_ON;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class EnableGnssRawMeasFullTrackingPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private SwitchPreference mPreference;
|
||||
@Mock
|
||||
private PreferenceScreen mPreferenceScreen;
|
||||
|
||||
private Context mContext;
|
||||
private EnableGnssRawMeasFullTrackingPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new EnableGnssRawMeasFullTrackingPreferenceController(mContext);
|
||||
when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
|
||||
mPreference);
|
||||
mController.displayPreference(mPreferenceScreen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_settingEnabled_enableGnssRawMeasFullTrackingShouldBeOn() {
|
||||
mController.onPreferenceChange(mPreference, true /* new value */);
|
||||
|
||||
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, -1 /* default */);
|
||||
|
||||
assertThat(mode).isEqualTo(SETTING_VALUE_ON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_settingDisabled_enableGnssRawMeasFullTrackingShouldBeOff() {
|
||||
mController.onPreferenceChange(mPreference, false /* new value */);
|
||||
|
||||
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, -1 /* default */);
|
||||
|
||||
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_OFF);
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mPreference).setChecked(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_settingEnabled_preferenceShouldBeChecked() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_ON);
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mPreference).setChecked(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
|
||||
mController.onDeveloperOptionsSwitchDisabled();
|
||||
|
||||
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, -1 /* default */);
|
||||
|
||||
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
|
||||
verify(mPreference).setChecked(false);
|
||||
verify(mPreference).setEnabled(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionsSwitchEnabled_shouldEnablePreference() {
|
||||
mController.onDeveloperOptionsSwitchEnabled();
|
||||
|
||||
verify(mPreference).setEnabled(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.location;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.XmlTestUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class LocationModeTest {
|
||||
|
||||
private Context mContext;
|
||||
private LocationMode mFragment;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mFragment = new LocationMode();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchIndexProvider_shouldIndexResource() {
|
||||
final List<SearchIndexableResource> indexRes =
|
||||
mFragment.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(mContext,
|
||||
true /* enabled */);
|
||||
|
||||
assertThat(indexRes).isNotNull();
|
||||
assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testSearchIndexProvider_ifPageDisabled_shouldNotIndexResource() {
|
||||
final List<String> niks = LocationMode.SEARCH_INDEX_DATA_PROVIDER
|
||||
.getNonIndexableKeys(mContext);
|
||||
final int xmlId = mFragment.getPreferenceScreenResId();
|
||||
|
||||
final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(mContext, xmlId);
|
||||
assertThat(niks).containsAllIn(keys);
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,11 @@
|
||||
package com.android.settings.security;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
@@ -29,7 +31,9 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.UserManager.EnforcingUser;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceGroup;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
@@ -43,6 +47,9 @@ import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.XmlTestUtils;
|
||||
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
import com.android.settingslib.RestrictedSwitchPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -55,12 +62,15 @@ import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowApplication;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
|
||||
shadows = {
|
||||
ShadowLockPatternUtils.class
|
||||
ShadowLockPatternUtils.class,
|
||||
ShadowUserManager.class,
|
||||
})
|
||||
public class SecuritySettingsTest {
|
||||
|
||||
@@ -187,4 +197,49 @@ public class SecuritySettingsTest {
|
||||
|
||||
assertThat(keys).containsAllIn(niks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnifyLockRestriction() {
|
||||
// Set up instance under test.
|
||||
final Context context = spy(RuntimeEnvironment.application);
|
||||
final SecuritySettings securitySettings = spy(new SecuritySettings());
|
||||
when(securitySettings.getContext()).thenReturn(context);
|
||||
|
||||
final int userId = 123;
|
||||
ReflectionHelpers.setField(securitySettings, "mProfileChallengeUserId", userId);
|
||||
|
||||
final LockPatternUtils utils = mock(LockPatternUtils.class);
|
||||
when(utils.isSeparateProfileChallengeEnabled(userId)).thenReturn(true);
|
||||
ReflectionHelpers.setField(securitySettings, "mLockPatternUtils", utils);
|
||||
|
||||
final RestrictedSwitchPreference unifyProfile = mock(RestrictedSwitchPreference.class);
|
||||
ReflectionHelpers.setField(securitySettings, "mUnifyProfile", unifyProfile);
|
||||
|
||||
// Pretend that no admins enforce the restriction.
|
||||
ShadowUserManager.getShadow().setUserRestrictionSources(
|
||||
UserManager.DISALLOW_UNIFIED_PASSWORD,
|
||||
UserHandle.of(userId),
|
||||
Collections.emptyList());
|
||||
|
||||
securitySettings.updateUnificationPreference();
|
||||
|
||||
verify(unifyProfile).setDisabledByAdmin(null);
|
||||
|
||||
reset(unifyProfile);
|
||||
|
||||
// Pretend that the restriction is enforced by several admins. Having just one would
|
||||
// require more mocking of implementation details.
|
||||
final EnforcingUser enforcer1 = new EnforcingUser(
|
||||
userId, UserManager.RESTRICTION_SOURCE_PROFILE_OWNER);
|
||||
final EnforcingUser enforcer2 = new EnforcingUser(
|
||||
UserHandle.USER_SYSTEM, UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
|
||||
ShadowUserManager.getShadow().setUserRestrictionSources(
|
||||
UserManager.DISALLOW_UNIFIED_PASSWORD,
|
||||
UserHandle.of(userId),
|
||||
Arrays.asList(enforcer1, enforcer2));
|
||||
|
||||
securitySettings.updateUnificationPreference();
|
||||
|
||||
verify(unifyProfile).setDisabledByAdmin(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.UserManager.EnforcingUser;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
@@ -31,14 +32,18 @@ import org.robolectric.shadow.api.Shadow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Implements(UserManager.class)
|
||||
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
|
||||
|
||||
private SparseArray<UserInfo> mUserInfos = new SparseArray<>();
|
||||
private boolean mAdminUser;
|
||||
private List<String> mRestrictions = new ArrayList<>();
|
||||
private final List<String> mRestrictions = new ArrayList<>();
|
||||
private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>();
|
||||
|
||||
|
||||
public void setIsAdminUser(boolean isAdminUser) {
|
||||
mAdminUser = isAdminUser;
|
||||
@@ -91,4 +96,15 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
||||
return (ShadowUserManager) Shadow.extract(
|
||||
RuntimeEnvironment.application.getSystemService(UserManager.class));
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public List<EnforcingUser> getUserRestrictionSources(
|
||||
String restrictionKey, UserHandle userHandle) {
|
||||
return mRestrictionSources.get(restrictionKey + userHandle.getIdentifier());
|
||||
}
|
||||
|
||||
public void setUserRestrictionSources(
|
||||
String restrictionKey, UserHandle userHandle, List<EnforcingUser> enforcers) {
|
||||
mRestrictionSources.put(restrictionKey + userHandle.getIdentifier(), enforcers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
|
||||
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public class UserCredentialsTest extends InstrumentationTestCase {
|
||||
Credential c = new Credential(alias, Process.SYSTEM_UID);
|
||||
|
||||
c.storedTypes.add(Credential.Type.CA_CERTIFICATE);
|
||||
c.storedTypes.add(Credential.Type.USER_SECRET_KEY);
|
||||
c.storedTypes.add(Credential.Type.USER_KEY);
|
||||
|
||||
Parcel p = Parcel.obtain();
|
||||
c.writeToParcel(p, /* flags */ 0);
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.applications;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.uiautomator.By;
|
||||
import android.support.test.uiautomator.BySelector;
|
||||
import android.support.test.uiautomator.Direction;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.UiObject2;
|
||||
import android.support.test.uiautomator.Until;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.MODE_DEFAULT;
|
||||
import static android.app.AppOpsManager.MODE_ERRORED;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* An abstract parent for testing settings activities that manage an AppOps permission.
|
||||
*/
|
||||
abstract public class AppOpsSettingsTest {
|
||||
private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
|
||||
private static final long START_ACTIVITY_TIMEOUT = 5000;
|
||||
|
||||
private Context mContext;
|
||||
private UiDevice mUiDevice;
|
||||
private PackageManager mPackageManager;
|
||||
private AppOpsManager mAppOpsManager;
|
||||
private List<UserInfo> mProfiles;
|
||||
private String mPackageName;
|
||||
|
||||
// These depend on which app op's settings UI is being tested.
|
||||
private final String mActivityAction;
|
||||
private final int mAppOpCode;
|
||||
|
||||
protected AppOpsSettingsTest(String activityAction, int appOpCode) {
|
||||
mActivityAction = activityAction;
|
||||
mAppOpCode = appOpCode;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mPackageName = InstrumentationRegistry.getContext().getPackageName();
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
||||
mProfiles = mContext.getSystemService(UserManager.class).getProfiles(UserHandle.myUserId());
|
||||
resetAppOpModeForAllProfiles();
|
||||
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
mUiDevice.wakeUp();
|
||||
mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
|
||||
}
|
||||
|
||||
private void resetAppOpModeForAllProfiles() throws Exception {
|
||||
for (UserInfo user : mProfiles) {
|
||||
final int uid = mPackageManager.getPackageUidAsUser(mPackageName, user.id);
|
||||
mAppOpsManager.setMode(mAppOpCode, uid, mPackageName, MODE_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an intent for showing the permission settings for all apps.
|
||||
*/
|
||||
private Intent createManageAllAppsIntent() {
|
||||
return new Intent(mActivityAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an intent for showing the permission setting for a single app.
|
||||
*/
|
||||
private Intent createManageSingleAppIntent(String packageName) {
|
||||
final Intent intent = createManageAllAppsIntent();
|
||||
intent.setData(Uri.parse("package:" + packageName));
|
||||
return intent;
|
||||
}
|
||||
|
||||
private String getApplicationLabel(String packageName) throws Exception {
|
||||
final ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
|
||||
return mPackageManager.getApplicationLabel(info).toString();
|
||||
}
|
||||
|
||||
private UiObject2 findAndVerifySwitchState(boolean checked) {
|
||||
final BySelector switchSelector = By.clazz(Switch.class).res("android:id/switch_widget");
|
||||
final UiObject2 switchPref = mUiDevice.wait(Until.findObject(switchSelector),
|
||||
START_ACTIVITY_TIMEOUT);
|
||||
assertNotNull("Switch not shown", switchPref);
|
||||
assertTrue("Switch in invalid state", switchPref.isChecked() == checked);
|
||||
return switchPref;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppList() throws Exception {
|
||||
final String testAppLabel = getApplicationLabel(mPackageName);
|
||||
|
||||
mContext.startActivity(createManageAllAppsIntent());
|
||||
final BySelector preferenceListSelector =
|
||||
By.clazz(RecyclerView.class).res("com.android.settings:id/apps_list");
|
||||
final UiObject2 preferenceList = mUiDevice.wait(Until.findObject(preferenceListSelector),
|
||||
START_ACTIVITY_TIMEOUT);
|
||||
assertNotNull("App list not shown", preferenceList);
|
||||
|
||||
final BySelector appLabelTextViewSelector = By.clazz(TextView.class)
|
||||
.res("android:id/title")
|
||||
.text(testAppLabel);
|
||||
List<UiObject2> listOfMatchingTextViews;
|
||||
do {
|
||||
listOfMatchingTextViews = preferenceList.findObjects(appLabelTextViewSelector);
|
||||
// assuming the number of profiles will be sufficiently small so that all the entries
|
||||
// for the same package will fit in one screen at some time during the scroll.
|
||||
} while (listOfMatchingTextViews.size() != mProfiles.size() &&
|
||||
preferenceList.scroll(Direction.DOWN, 0.2f));
|
||||
assertEquals("Test app not listed for each profile", mProfiles.size(),
|
||||
listOfMatchingTextViews.size());
|
||||
|
||||
for (UiObject2 matchingObject : listOfMatchingTextViews) {
|
||||
matchingObject.click();
|
||||
findAndVerifySwitchState(true);
|
||||
mUiDevice.pressBack();
|
||||
}
|
||||
}
|
||||
|
||||
private void testAppDetailScreenForAppOp(int appOpMode, int userId) throws Exception {
|
||||
final String testAppLabel = getApplicationLabel(mPackageName);
|
||||
final BySelector appDetailTitleSelector = By.clazz(TextView.class)
|
||||
.res("com.android.settings:id/app_detail_title")
|
||||
.text(testAppLabel);
|
||||
|
||||
mAppOpsManager.setMode(mAppOpCode,
|
||||
mPackageManager.getPackageUidAsUser(mPackageName, userId), mPackageName, appOpMode);
|
||||
mContext.startActivityAsUser(createManageSingleAppIntent(mPackageName),
|
||||
UserHandle.of(userId));
|
||||
mUiDevice.wait(Until.findObject(appDetailTitleSelector), START_ACTIVITY_TIMEOUT);
|
||||
findAndVerifySwitchState(appOpMode == MODE_ALLOWED || appOpMode == MODE_DEFAULT);
|
||||
mUiDevice.pressBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleApp() throws Exception {
|
||||
// App op MODE_DEFAULT is already tested in #testAppList
|
||||
for (UserInfo user : mProfiles) {
|
||||
testAppDetailScreenForAppOp(MODE_ALLOWED, user.id);
|
||||
testAppDetailScreenForAppOp(MODE_ERRORED, user.id);
|
||||
}
|
||||
}
|
||||
|
||||
private void testSwitchToggle(int fromAppOp, int toAppOp) throws Exception {
|
||||
final int packageUid = mPackageManager.getPackageUid(mPackageName, 0);
|
||||
final boolean initialState = (fromAppOp == MODE_ALLOWED || fromAppOp == MODE_DEFAULT);
|
||||
|
||||
mAppOpsManager.setMode(mAppOpCode, packageUid, mPackageName, fromAppOp);
|
||||
mContext.startActivity(createManageSingleAppIntent(mPackageName));
|
||||
final UiObject2 switchPref = findAndVerifySwitchState(initialState);
|
||||
switchPref.click();
|
||||
Thread.sleep(1000);
|
||||
assertEquals("Toggling switch did not change app op", toAppOp,
|
||||
mAppOpsManager.checkOpNoThrow(mAppOpCode, packageUid,
|
||||
mPackageName));
|
||||
mUiDevice.pressBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfSwitchTogglesAppOp() throws Exception {
|
||||
testSwitchToggle(MODE_ALLOWED, MODE_ERRORED);
|
||||
testSwitchToggle(MODE_ERRORED, MODE_ALLOWED);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mUiDevice.pressHome();
|
||||
resetAppOpModeForAllProfiles();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.applications;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class DrawOverlaySettingsTest extends AppOpsSettingsTest {
|
||||
|
||||
public DrawOverlaySettingsTest() {
|
||||
super(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, AppOpsManager.OP_SYSTEM_ALERT_WINDOW);
|
||||
}
|
||||
|
||||
// Test cases are in the superclass.
|
||||
}
|
||||
@@ -16,186 +16,21 @@
|
||||
|
||||
package com.android.settings.applications;
|
||||
|
||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.MODE_DEFAULT;
|
||||
import static android.app.AppOpsManager.MODE_ERRORED;
|
||||
import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.support.test.uiautomator.By;
|
||||
import android.support.test.uiautomator.BySelector;
|
||||
import android.support.test.uiautomator.Direction;
|
||||
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.UiObject2;
|
||||
import android.support.test.uiautomator.Until;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class ExternalSourcesSettingsTest {
|
||||
public class ExternalSourcesSettingsTest extends AppOpsSettingsTest {
|
||||
|
||||
private static final String TAG = ExternalSourcesSettingsTest.class.getSimpleName();
|
||||
private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
|
||||
private static final long START_ACTIVITY_TIMEOUT = 5000;
|
||||
|
||||
private Context mContext;
|
||||
private UiDevice mUiDevice;
|
||||
private PackageManager mPackageManager;
|
||||
private AppOpsManager mAppOpsManager;
|
||||
private List<UserInfo> mProfiles;
|
||||
private String mPackageName;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mPackageName = InstrumentationRegistry.getContext().getPackageName();
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
||||
mProfiles = mContext.getSystemService(UserManager.class).getProfiles(UserHandle.myUserId());
|
||||
resetAppOpModeForAllProfiles();
|
||||
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
mUiDevice.wakeUp();
|
||||
mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
|
||||
public ExternalSourcesSettingsTest() {
|
||||
super(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
|
||||
AppOpsManager.OP_REQUEST_INSTALL_PACKAGES);
|
||||
}
|
||||
|
||||
private void resetAppOpModeForAllProfiles() throws Exception {
|
||||
for (UserInfo user : mProfiles) {
|
||||
final int uid = mPackageManager.getPackageUidAsUser(mPackageName, user.id);
|
||||
mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES, uid, mPackageName, MODE_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
private Intent createManageExternalSourcesListIntent() {
|
||||
final Intent manageExternalSourcesIntent = new Intent();
|
||||
manageExternalSourcesIntent.setAction(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
|
||||
return manageExternalSourcesIntent;
|
||||
}
|
||||
|
||||
private Intent createManageExternalSourcesAppIntent(String packageName) {
|
||||
final Intent intent = createManageExternalSourcesListIntent();
|
||||
intent.setData(Uri.parse("package:" + packageName));
|
||||
return intent;
|
||||
}
|
||||
|
||||
private String getApplicationLabel(String packageName) throws Exception {
|
||||
final ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
|
||||
return mPackageManager.getApplicationLabel(info).toString();
|
||||
}
|
||||
|
||||
private UiObject2 findAndVerifySwitchState(boolean checked) {
|
||||
final BySelector switchSelector = By.clazz(Switch.class).res("android:id/switch_widget");
|
||||
final UiObject2 switchPref = mUiDevice.wait(Until.findObject(switchSelector),
|
||||
START_ACTIVITY_TIMEOUT);
|
||||
assertNotNull("Switch not shown", switchPref);
|
||||
assertTrue("Switch in invalid state", switchPref.isChecked() == checked);
|
||||
return switchPref;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManageExternalSourcesList() throws Exception {
|
||||
final String testAppLabel = getApplicationLabel(mPackageName);
|
||||
|
||||
mContext.startActivity(createManageExternalSourcesListIntent());
|
||||
final BySelector preferenceListSelector =
|
||||
By.clazz(RecyclerView.class).res("com.android.settings:id/apps_list");
|
||||
final UiObject2 preferenceList = mUiDevice.wait(Until.findObject(preferenceListSelector),
|
||||
START_ACTIVITY_TIMEOUT);
|
||||
assertNotNull("App list not shown", preferenceList);
|
||||
|
||||
final BySelector appLabelTextViewSelector = By.clazz(TextView.class)
|
||||
.res("android:id/title")
|
||||
.text(testAppLabel);
|
||||
List<UiObject2> listOfMatchingTextViews;
|
||||
do {
|
||||
listOfMatchingTextViews = preferenceList.findObjects(appLabelTextViewSelector);
|
||||
// assuming the number of profiles will be sufficiently small so that all the entries
|
||||
// for the same package will fit in one screen at some time during the scroll.
|
||||
} while (listOfMatchingTextViews.size() != mProfiles.size() &&
|
||||
preferenceList.scroll(Direction.DOWN, 0.2f));
|
||||
assertEquals("Test app not listed for each profile", mProfiles.size(),
|
||||
listOfMatchingTextViews.size());
|
||||
|
||||
for (UiObject2 matchingObject : listOfMatchingTextViews) {
|
||||
matchingObject.click();
|
||||
findAndVerifySwitchState(true);
|
||||
mUiDevice.pressBack();
|
||||
}
|
||||
}
|
||||
|
||||
private void testAppDetailScreenForAppOp(int appOpMode, int userId) throws Exception {
|
||||
final String testAppLabel = getApplicationLabel(mPackageName);
|
||||
final BySelector appDetailTitleSelector = By.clazz(TextView.class)
|
||||
.res("com.android.settings:id/app_detail_title")
|
||||
.text(testAppLabel);
|
||||
|
||||
mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES,
|
||||
mPackageManager.getPackageUidAsUser(mPackageName, userId), mPackageName, appOpMode);
|
||||
mContext.startActivityAsUser(createManageExternalSourcesAppIntent(mPackageName),
|
||||
UserHandle.of(userId));
|
||||
mUiDevice.wait(Until.findObject(appDetailTitleSelector), START_ACTIVITY_TIMEOUT);
|
||||
findAndVerifySwitchState(appOpMode == MODE_ALLOWED || appOpMode == MODE_DEFAULT);
|
||||
mUiDevice.pressBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManageExternalSourcesForApp() throws Exception {
|
||||
// App op MODE_DEFAULT is already tested in #testManageExternalSourcesList
|
||||
for (UserInfo user : mProfiles) {
|
||||
testAppDetailScreenForAppOp(MODE_ALLOWED, user.id);
|
||||
testAppDetailScreenForAppOp(MODE_ERRORED, user.id);
|
||||
}
|
||||
}
|
||||
|
||||
private void testSwitchToggle(int fromAppOp, int toAppOp) throws Exception {
|
||||
final int packageUid = mPackageManager.getPackageUid(mPackageName, 0);
|
||||
final boolean initialState = (fromAppOp == MODE_ALLOWED || fromAppOp == MODE_DEFAULT);
|
||||
|
||||
mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES, packageUid, mPackageName, fromAppOp);
|
||||
mContext.startActivity(createManageExternalSourcesAppIntent(mPackageName));
|
||||
final UiObject2 switchPref = findAndVerifySwitchState(initialState);
|
||||
switchPref.click();
|
||||
Thread.sleep(1000);
|
||||
assertEquals("Toggling switch did not change app op", toAppOp,
|
||||
mAppOpsManager.checkOpNoThrow(OP_REQUEST_INSTALL_PACKAGES, packageUid,
|
||||
mPackageName));
|
||||
mUiDevice.pressBack();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfSwitchTogglesAppOp() throws Exception {
|
||||
testSwitchToggle(MODE_ALLOWED, MODE_ERRORED);
|
||||
testSwitchToggle(MODE_ERRORED, MODE_ALLOWED);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mUiDevice.pressHome();
|
||||
resetAppOpModeForAllProfiles();
|
||||
}
|
||||
// Test cases are in the superclass.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user