blob: 73d6be2d68e514e29f29436ec73c9af4c8a1e482 [file] [log] [blame]
/*
* Copyright (C) 2011 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.cts.verifier.admin;
import com.android.cts.verifier.ConditionalTest;
import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Test that checks that device policies are properly saved and loaded across reboots. The user
* clicks a button to generate a random policy and is then asked to reboot the device. When
* returning to the test, the activity checks that the device manager is reporting the values
* it set before the user rebooted the device.
*/
@ConditionalTest(required_features = "android.software.device_admin")
public class PolicySerializationTestActivity extends PassFailButtons.ListActivity {
/**
* Whether or not to load the expected policy from the preferences and check against
* what the {@link DevicePolicyManager} reports.
*/
private static final String LOAD_EXPECTED_POLICY_PREFERENCE = "load-expected-policy";
private static final int ADD_DEVICE_ADMIN_REQUEST_CODE = 1;
private DevicePolicyManager mDevicePolicyManager;
private ComponentName mAdmin;
private List<PolicyItem<?>> mPolicyItems = new ArrayList<PolicyItem<?>>();
private PolicyAdapter mAdapter;
private View mGeneratePolicyButton;
private View mApplyPolicyButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.da_policy_main);
setInfoResources(R.string.da_policy_serialization_test,
R.string.da_policy_serialization_info, -1);
setPassFailButtonClickListeners();
mDevicePolicyManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
mAdmin = DeviceAdminTestReceiver.getReceiverComponentName();
mGeneratePolicyButton = findViewById(R.id.generate_policy_button);
mGeneratePolicyButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
generateRandomPolicy();
updateWidgets();
}
});
mApplyPolicyButton = findViewById(R.id.apply_policy_button);
mApplyPolicyButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
applyPolicy();
}
});
mPolicyItems.add(new PasswordQualityPolicy(this));
mPolicyItems.add(new PasswordMinimumLengthPolicy(this));
mPolicyItems.add(new MaximumFailedPasswordsForWipePolicy(this));
mPolicyItems.add(new MaximumTimeToLockPolicy(this));
mAdapter = new PolicyAdapter(this);
setListAdapter(mAdapter);
loadPolicy();
updateWidgets();
}
private void loadPolicy() {
mAdapter.clear();
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
if (prefs.getBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false)) {
for (PolicyItem<?> item : mPolicyItems) {
item.loadExpectedValue(prefs);
item.loadActualValue(mDevicePolicyManager, mAdmin);
mAdapter.add(item);
}
}
}
private void generateRandomPolicy() {
Random random = new Random();
mAdapter.clear();
for (PolicyItem<?> item : mPolicyItems) {
item.setRandomExpectedValue(random);
item.resetActualValue();
mAdapter.add(item);
}
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false);
editor.apply();
Toast.makeText(this, R.string.da_random_policy, Toast.LENGTH_SHORT).show();
}
private void applyPolicy() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
DeviceAdminTestReceiver.getReceiverComponentName());
startActivityForResult(intent, ADD_DEVICE_ADMIN_REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case ADD_DEVICE_ADMIN_REQUEST_CODE:
handleAddDeviceAdminResult(resultCode, data);
break;
}
}
private void handleAddDeviceAdminResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
for (PolicyItem<?> item : mPolicyItems) {
item.applyExpectedValue(mDevicePolicyManager, admin);
}
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, true);
for (PolicyItem<?> item : mPolicyItems) {
item.saveExpectedValue(editor);
}
editor.apply();
showRebootDialog();
}
}
private void showRebootDialog() {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.da_policy_serialization_test)
.setMessage(R.string.da_policy_reboot)
.setPositiveButton(android.R.string.ok, null)
.show();
}
private void updateWidgets() {
mApplyPolicyButton.setEnabled(!mAdapter.isEmpty());
// All items need to have been serialized properly for the pass button to activate.
boolean enablePass = !mAdapter.isEmpty();
int numItems = mAdapter.getCount();
for (int i = 0; i < numItems; i++) {
PolicyItem<?> item = mAdapter.getItem(i);
if (!item.matchesExpectedValue()) {
enablePass = false;
}
}
getPassButton().setEnabled(enablePass);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
PolicyItem<?> item = mAdapter.getItem(position);
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(item.getDisplayName())
.setMessage(getString(R.string.da_policy_info,
item.getDisplayExpectedValue(),
item.getDisplayActualValue()))
.setPositiveButton(android.R.string.ok, null)
.show();
}
static class PolicyAdapter extends ArrayAdapter<PolicyItem<?>> {
public PolicyAdapter(Context context) {
super(context, android.R.layout.simple_list_item_1);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view = (TextView) super.getView(position, convertView, parent);
PolicyItem<?> item = getItem(position);
int backgroundResource = 0;
int iconResource = 0;
if (item.getExpectedValue() != null && item.getActualValue() != null) {
if (item.matchesExpectedValue()) {
backgroundResource = R.drawable.test_pass_gradient;
iconResource = R.drawable.fs_good;
} else {
backgroundResource = R.drawable.test_fail_gradient;
iconResource = R.drawable.fs_error;
}
}
view.setBackgroundResource(backgroundResource);
view.setPadding(10, 0, 10, 0);
view.setCompoundDrawablePadding(10);
view.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0);
return view;
}
}
interface PolicyItem<T> {
void setRandomExpectedValue(Random random);
void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin);
void loadExpectedValue(SharedPreferences prefs);
void saveExpectedValue(SharedPreferences.Editor editor);
void resetActualValue();
void loadActualValue(DevicePolicyManager deviceManager, ComponentName admin);
String getDisplayName();
T getExpectedValue();
String getDisplayExpectedValue();
T getActualValue();
String getDisplayActualValue();
boolean matchesExpectedValue();
}
static abstract class BasePolicyItem<T> implements PolicyItem<T> {
private String mDisplayName;
private T mExpectedValue;
private T mActualValue;
BasePolicyItem(Context context, int nameResId) {
mDisplayName = context.getString(nameResId);
}
@Override
public final void setRandomExpectedValue(Random random) {
mExpectedValue = getRandomExpectedValue(random);
}
protected abstract T getRandomExpectedValue(Random random);
@Override
public final void loadExpectedValue(SharedPreferences prefs) {
mExpectedValue = getPreferencesValue(prefs);
}
protected abstract T getPreferencesValue(SharedPreferences prefs);
@Override
public final void loadActualValue(DevicePolicyManager deviceManager, ComponentName admin) {
mActualValue = getDeviceManagerValue(deviceManager, admin);
}
protected abstract T getDeviceManagerValue(DevicePolicyManager deviceManager,
ComponentName admin);
@Override
public final void resetActualValue() {
mActualValue = null;
}
@Override
public final String getDisplayName() {
return mDisplayName;
}
@Override
public final T getExpectedValue() {
return mExpectedValue;
}
@Override
public final String getDisplayExpectedValue() {
return mExpectedValue != null ? getDisplayValue(mExpectedValue) : "";
}
@Override
public final T getActualValue() {
return mActualValue;
}
@Override
public final String getDisplayActualValue() {
return mActualValue != null ? getDisplayValue(mActualValue) : "";
}
protected String getDisplayValue(T value) {
return "" + value;
}
@Override
public final boolean matchesExpectedValue() {
return mExpectedValue != null && mExpectedValue.equals(mActualValue);
}
@Override
public String toString() {
return getDisplayName();
}
}
static abstract class IntegerPolicyItem extends BasePolicyItem<Integer> {
private String mPreferenceKey;
IntegerPolicyItem(Context context, int nameResId, String preferenceKey) {
super(context, nameResId);
mPreferenceKey = preferenceKey;
}
@Override
protected final Integer getPreferencesValue(SharedPreferences prefs) {
return prefs.getInt(mPreferenceKey, -1);
}
@Override
public final void saveExpectedValue(Editor editor) {
editor.putInt(mPreferenceKey, getExpectedValue());
}
}
static abstract class LongPolicyItem extends BasePolicyItem<Long> {
private String mPreferenceKey;
LongPolicyItem(Context context, int nameResId, String preferenceKey) {
super(context, nameResId);
mPreferenceKey = preferenceKey;
}
@Override
protected final Long getPreferencesValue(SharedPreferences prefs) {
return prefs.getLong(mPreferenceKey, -1);
}
@Override
public final void saveExpectedValue(Editor editor) {
editor.putLong(mPreferenceKey, getExpectedValue());
}
}
static class PasswordQualityPolicy extends IntegerPolicyItem {
private final Context mContext;
public PasswordQualityPolicy(Context context) {
super(context, R.string.da_password_quality, "password-quality");
mContext = context;
}
@Override
protected Integer getRandomExpectedValue(Random random) {
int[] passwordQualities = new int[] {
DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
};
int index = random.nextInt(passwordQualities.length);
return passwordQualities[index];
}
@Override
public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
deviceManager.setPasswordQuality(admin, getExpectedValue());
}
@Override
protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
ComponentName admin) {
return deviceManager.getPasswordQuality(admin);
}
@Override
protected String getDisplayValue(Integer value) {
switch (value) {
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
return mContext.getString(R.string.da_password_quality_alphabetic);
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
return mContext.getString(R.string.da_password_quality_alphanumeric);
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
return mContext.getString(R.string.da_password_quality_numeric);
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
return mContext.getString(R.string.da_password_quality_something);
default:
return Integer.toString(value);
}
}
}
static class PasswordMinimumLengthPolicy extends IntegerPolicyItem {
PasswordMinimumLengthPolicy(Context context) {
super(context, R.string.da_password_minimum_length, "password-minimum-length");
}
@Override
protected Integer getRandomExpectedValue(Random random) {
return random.nextInt(50);
}
@Override
public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
deviceManager.setPasswordMinimumLength(admin, getExpectedValue());
}
@Override
protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
ComponentName admin) {
return deviceManager.getPasswordMinimumLength(admin);
}
}
static class MaximumFailedPasswordsForWipePolicy extends IntegerPolicyItem {
MaximumFailedPasswordsForWipePolicy(Context context) {
super(context, R.string.da_maximum_failed_passwords_for_wipe,
"maximum-failed-passwords-for-wipe");
}
@Override
protected Integer getRandomExpectedValue(Random random) {
return random.nextInt(50);
}
@Override
public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
deviceManager.setMaximumFailedPasswordsForWipe(admin, getExpectedValue());
}
@Override
protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
ComponentName admin) {
return deviceManager.getMaximumFailedPasswordsForWipe(admin);
}
}
static class MaximumTimeToLockPolicy extends LongPolicyItem {
MaximumTimeToLockPolicy(Context context) {
super(context, R.string.da_maximum_time_to_lock, "maximum-time-to-lock");
}
@Override
protected Long getRandomExpectedValue(Random random) {
return (long)(1000 + random.nextInt(60 * 60 * 1000));
}
@Override
public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
deviceManager.setMaximumTimeToLock(admin, getExpectedValue());
}
@Override
protected Long getDeviceManagerValue(DevicePolicyManager deviceManager,
ComponentName admin) {
return deviceManager.getMaximumTimeToLock(admin);
}
}
}