/* * 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.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. */ 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> mPolicyItems = new ArrayList>(); 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 = TestDeviceAdminReceiver.getComponent(this); 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, TestDeviceAdminReceiver.getComponent(this)); 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 = TestDeviceAdminReceiver.getComponent(this); 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> { 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 { 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 implements PolicyItem { 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 { 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 { 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); } } }