Snap for 4507345 from 3a2573b812 to pi-release

Change-Id: I4c0fe2b7972aaddfebde3f1e5c4de6a018c56e9d
This commit is contained in:
android-build-team Robot
2017-12-17 08:27:44 +00:00
25 changed files with 753 additions and 223 deletions

View File

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

View File

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

View File

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

View File

@@ -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" />

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(),

View File

@@ -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(),

View File

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

View File

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

View File

@@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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" />

View File

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

View File

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

View File

@@ -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.
}

View File

@@ -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.
}