1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.verifier.admin; 18 19 import com.android.cts.verifier.PassFailButtons; 20 import com.android.cts.verifier.R; 21 22 import android.app.AlertDialog; 23 import android.app.admin.DevicePolicyManager; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.SharedPreferences; 28 import android.content.SharedPreferences.Editor; 29 import android.os.Bundle; 30 import android.view.View; 31 import android.view.View.OnClickListener; 32 import android.view.ViewGroup; 33 import android.widget.ArrayAdapter; 34 import android.widget.ListView; 35 import android.widget.TextView; 36 import android.widget.Toast; 37 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Random; 41 42 /** 43 * Test that checks that device policies are properly saved and loaded across reboots. The user 44 * clicks a button to generate a random policy and is then asked to reboot the device. When 45 * returning to the test, the activity checks that the device manager is reporting the values 46 * it set before the user rebooted the device. 47 */ 48 public class PolicySerializationTestActivity extends PassFailButtons.ListActivity { 49 50 /** 51 * Whether or not to load the expected policy from the preferences and check against 52 * what the {@link DevicePolicyManager} reports. 53 */ 54 private static final String LOAD_EXPECTED_POLICY_PREFERENCE = "load-expected-policy"; 55 56 private static final int ADD_DEVICE_ADMIN_REQUEST_CODE = 1; 57 58 private DevicePolicyManager mDevicePolicyManager; 59 private ComponentName mAdmin; 60 61 private List<PolicyItem<?>> mPolicyItems = new ArrayList<PolicyItem<?>>(); 62 private PolicyAdapter mAdapter; 63 64 private View mGeneratePolicyButton; 65 private View mApplyPolicyButton; 66 67 @Override 68 protected void onCreate(Bundle savedInstanceState) { 69 super.onCreate(savedInstanceState); 70 setContentView(R.layout.da_policy_main); 71 setInfoResources(R.string.da_policy_serialization_test, 72 R.string.da_policy_serialization_info, -1); 73 setPassFailButtonClickListeners(); 74 75 mDevicePolicyManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE); 76 mAdmin = TestDeviceAdminReceiver.getComponent(this); 77 78 mGeneratePolicyButton = findViewById(R.id.generate_policy_button); 79 mGeneratePolicyButton.setOnClickListener(new OnClickListener() { 80 @Override 81 public void onClick(View v) { 82 generateRandomPolicy(); 83 updateWidgets(); 84 } 85 }); 86 87 mApplyPolicyButton = findViewById(R.id.apply_policy_button); 88 mApplyPolicyButton.setOnClickListener(new OnClickListener() { 89 @Override 90 public void onClick(View v) { 91 applyPolicy(); 92 } 93 }); 94 95 mPolicyItems.add(new PasswordQualityPolicy(this)); 96 mPolicyItems.add(new PasswordMinimumLengthPolicy(this)); 97 mPolicyItems.add(new MaximumFailedPasswordsForWipePolicy(this)); 98 mPolicyItems.add(new MaximumTimeToLockPolicy(this)); 99 mAdapter = new PolicyAdapter(this); 100 setListAdapter(mAdapter); 101 102 loadPolicy(); 103 updateWidgets(); 104 } 105 106 private void loadPolicy() { 107 mAdapter.clear(); 108 SharedPreferences prefs = getPreferences(MODE_PRIVATE); 109 if (prefs.getBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false)) { 110 for (PolicyItem<?> item : mPolicyItems) { 111 item.loadExpectedValue(prefs); 112 item.loadActualValue(mDevicePolicyManager, mAdmin); 113 mAdapter.add(item); 114 } 115 } 116 } 117 118 private void generateRandomPolicy() { 119 Random random = new Random(); 120 mAdapter.clear(); 121 for (PolicyItem<?> item : mPolicyItems) { 122 item.setRandomExpectedValue(random); 123 item.resetActualValue(); 124 mAdapter.add(item); 125 } 126 127 SharedPreferences prefs = getPreferences(MODE_PRIVATE); 128 SharedPreferences.Editor editor = prefs.edit(); 129 editor.clear(); 130 editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false); 131 editor.apply(); 132 133 Toast.makeText(this, R.string.da_random_policy, Toast.LENGTH_SHORT).show(); 134 } 135 136 private void applyPolicy() { 137 Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); 138 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, 139 TestDeviceAdminReceiver.getComponent(this)); 140 startActivityForResult(intent, ADD_DEVICE_ADMIN_REQUEST_CODE); 141 } 142 143 @Override 144 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 145 super.onActivityResult(requestCode, resultCode, data); 146 switch (requestCode) { 147 case ADD_DEVICE_ADMIN_REQUEST_CODE: 148 handleAddDeviceAdminResult(resultCode, data); 149 break; 150 } 151 } 152 153 private void handleAddDeviceAdminResult(int resultCode, Intent data) { 154 if (resultCode == RESULT_OK) { 155 ComponentName admin = TestDeviceAdminReceiver.getComponent(this); 156 for (PolicyItem<?> item : mPolicyItems) { 157 item.applyExpectedValue(mDevicePolicyManager, admin); 158 } 159 160 SharedPreferences prefs = getPreferences(MODE_PRIVATE); 161 SharedPreferences.Editor editor = prefs.edit(); 162 editor.clear(); 163 editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, true); 164 for (PolicyItem<?> item : mPolicyItems) { 165 item.saveExpectedValue(editor); 166 } 167 editor.apply(); 168 showRebootDialog(); 169 } 170 } 171 172 private void showRebootDialog() { 173 new AlertDialog.Builder(this) 174 .setIcon(android.R.drawable.ic_dialog_info) 175 .setTitle(R.string.da_policy_serialization_test) 176 .setMessage(R.string.da_policy_reboot) 177 .setPositiveButton(android.R.string.ok, null) 178 .show(); 179 } 180 181 private void updateWidgets() { 182 mApplyPolicyButton.setEnabled(!mAdapter.isEmpty()); 183 184 // All items need to have been serialized properly for the pass button to activate. 185 boolean enablePass = !mAdapter.isEmpty(); 186 int numItems = mAdapter.getCount(); 187 for (int i = 0; i < numItems; i++) { 188 PolicyItem<?> item = mAdapter.getItem(i); 189 if (!item.matchesExpectedValue()) { 190 enablePass = false; 191 } 192 } 193 getPassButton().setEnabled(enablePass); 194 } 195 196 @Override 197 protected void onListItemClick(ListView l, View v, int position, long id) { 198 super.onListItemClick(l, v, position, id); 199 PolicyItem<?> item = mAdapter.getItem(position); 200 new AlertDialog.Builder(this) 201 .setIcon(android.R.drawable.ic_dialog_info) 202 .setTitle(item.getDisplayName()) 203 .setMessage(getString(R.string.da_policy_info, 204 item.getDisplayExpectedValue(), 205 item.getDisplayActualValue())) 206 .setPositiveButton(android.R.string.ok, null) 207 .show(); 208 } 209 210 static class PolicyAdapter extends ArrayAdapter<PolicyItem<?>> { 211 212 public PolicyAdapter(Context context) { 213 super(context, android.R.layout.simple_list_item_1); 214 } 215 216 @Override 217 public View getView(int position, View convertView, ViewGroup parent) { 218 TextView view = (TextView) super.getView(position, convertView, parent); 219 220 PolicyItem<?> item = getItem(position); 221 int backgroundResource = 0; 222 int iconResource = 0; 223 if (item.getExpectedValue() != null && item.getActualValue() != null) { 224 if (item.matchesExpectedValue()) { 225 backgroundResource = R.drawable.test_pass_gradient; 226 iconResource = R.drawable.fs_good; 227 } else { 228 backgroundResource = R.drawable.test_fail_gradient; 229 iconResource = R.drawable.fs_error; 230 } 231 } 232 view.setBackgroundResource(backgroundResource); 233 view.setPadding(10, 0, 10, 0); 234 view.setCompoundDrawablePadding(10); 235 view.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0); 236 237 return view; 238 } 239 } 240 241 interface PolicyItem<T> { 242 243 void setRandomExpectedValue(Random random); 244 245 void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin); 246 247 void loadExpectedValue(SharedPreferences prefs); 248 249 void saveExpectedValue(SharedPreferences.Editor editor); 250 251 void resetActualValue(); 252 253 void loadActualValue(DevicePolicyManager deviceManager, ComponentName admin); 254 255 String getDisplayName(); 256 257 T getExpectedValue(); 258 259 String getDisplayExpectedValue(); 260 261 T getActualValue(); 262 263 String getDisplayActualValue(); 264 265 boolean matchesExpectedValue(); 266 } 267 268 static abstract class BasePolicyItem<T> implements PolicyItem<T> { 269 private String mDisplayName; 270 private T mExpectedValue; 271 private T mActualValue; 272 273 BasePolicyItem(Context context, int nameResId) { 274 mDisplayName = context.getString(nameResId); 275 } 276 277 @Override 278 public final void setRandomExpectedValue(Random random) { 279 mExpectedValue = getRandomExpectedValue(random); 280 } 281 282 protected abstract T getRandomExpectedValue(Random random); 283 284 @Override 285 public final void loadExpectedValue(SharedPreferences prefs) { 286 mExpectedValue = getPreferencesValue(prefs); 287 } 288 289 protected abstract T getPreferencesValue(SharedPreferences prefs); 290 291 @Override 292 public final void loadActualValue(DevicePolicyManager deviceManager, ComponentName admin) { 293 mActualValue = getDeviceManagerValue(deviceManager, admin); 294 } 295 296 protected abstract T getDeviceManagerValue(DevicePolicyManager deviceManager, 297 ComponentName admin); 298 299 @Override 300 public final void resetActualValue() { 301 mActualValue = null; 302 } 303 304 @Override 305 public final String getDisplayName() { 306 return mDisplayName; 307 } 308 309 @Override 310 public final T getExpectedValue() { 311 return mExpectedValue; 312 } 313 314 @Override 315 public final String getDisplayExpectedValue() { 316 return mExpectedValue != null ? getDisplayValue(mExpectedValue) : ""; 317 } 318 319 @Override 320 public final T getActualValue() { 321 return mActualValue; 322 } 323 324 @Override 325 public final String getDisplayActualValue() { 326 return mActualValue != null ? getDisplayValue(mActualValue) : ""; 327 } 328 329 protected String getDisplayValue(T value) { 330 return "" + value; 331 } 332 333 @Override 334 public final boolean matchesExpectedValue() { 335 return mExpectedValue != null && mExpectedValue.equals(mActualValue); 336 } 337 338 @Override 339 public String toString() { 340 return getDisplayName(); 341 } 342 } 343 344 static abstract class IntegerPolicyItem extends BasePolicyItem<Integer> { 345 346 private String mPreferenceKey; 347 348 IntegerPolicyItem(Context context, int nameResId, String preferenceKey) { 349 super(context, nameResId); 350 mPreferenceKey = preferenceKey; 351 } 352 353 @Override 354 protected final Integer getPreferencesValue(SharedPreferences prefs) { 355 return prefs.getInt(mPreferenceKey, -1); 356 } 357 358 @Override 359 public final void saveExpectedValue(Editor editor) { 360 editor.putInt(mPreferenceKey, getExpectedValue()); 361 } 362 } 363 364 static abstract class LongPolicyItem extends BasePolicyItem<Long> { 365 366 private String mPreferenceKey; 367 368 LongPolicyItem(Context context, int nameResId, String preferenceKey) { 369 super(context, nameResId); 370 mPreferenceKey = preferenceKey; 371 } 372 373 @Override 374 protected final Long getPreferencesValue(SharedPreferences prefs) { 375 return prefs.getLong(mPreferenceKey, -1); 376 } 377 378 @Override 379 public final void saveExpectedValue(Editor editor) { 380 editor.putLong(mPreferenceKey, getExpectedValue()); 381 } 382 } 383 384 static class PasswordQualityPolicy extends IntegerPolicyItem { 385 386 private final Context mContext; 387 388 public PasswordQualityPolicy(Context context) { 389 super(context, R.string.da_password_quality, "password-quality"); 390 mContext = context; 391 } 392 393 @Override 394 protected Integer getRandomExpectedValue(Random random) { 395 int[] passwordQualities = new int[] { 396 DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, 397 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, 398 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, 399 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING 400 }; 401 402 int index = random.nextInt(passwordQualities.length); 403 return passwordQualities[index]; 404 } 405 406 @Override 407 public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) { 408 deviceManager.setPasswordQuality(admin, getExpectedValue()); 409 } 410 411 @Override 412 protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager, 413 ComponentName admin) { 414 return deviceManager.getPasswordQuality(admin); 415 } 416 417 @Override 418 protected String getDisplayValue(Integer value) { 419 switch (value) { 420 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 421 return mContext.getString(R.string.da_password_quality_alphabetic); 422 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 423 return mContext.getString(R.string.da_password_quality_alphanumeric); 424 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 425 return mContext.getString(R.string.da_password_quality_numeric); 426 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 427 return mContext.getString(R.string.da_password_quality_something); 428 default: 429 return Integer.toString(value); 430 } 431 } 432 } 433 434 static class PasswordMinimumLengthPolicy extends IntegerPolicyItem { 435 436 PasswordMinimumLengthPolicy(Context context) { 437 super(context, R.string.da_password_minimum_length, "password-minimum-length"); 438 } 439 440 @Override 441 protected Integer getRandomExpectedValue(Random random) { 442 return random.nextInt(50); 443 } 444 445 @Override 446 public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) { 447 deviceManager.setPasswordMinimumLength(admin, getExpectedValue()); 448 } 449 450 @Override 451 protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager, 452 ComponentName admin) { 453 return deviceManager.getPasswordMinimumLength(admin); 454 } 455 } 456 457 static class MaximumFailedPasswordsForWipePolicy extends IntegerPolicyItem { 458 459 MaximumFailedPasswordsForWipePolicy(Context context) { 460 super(context, R.string.da_maximum_failed_passwords_for_wipe, 461 "maximum-failed-passwords-for-wipe"); 462 } 463 464 @Override 465 protected Integer getRandomExpectedValue(Random random) { 466 return random.nextInt(50); 467 } 468 469 @Override 470 public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) { 471 deviceManager.setMaximumFailedPasswordsForWipe(admin, getExpectedValue()); 472 } 473 474 @Override 475 protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager, 476 ComponentName admin) { 477 return deviceManager.getMaximumFailedPasswordsForWipe(admin); 478 } 479 } 480 481 static class MaximumTimeToLockPolicy extends LongPolicyItem { 482 483 MaximumTimeToLockPolicy(Context context) { 484 super(context, R.string.da_maximum_time_to_lock, "maximum-time-to-lock"); 485 } 486 487 @Override 488 protected Long getRandomExpectedValue(Random random) { 489 return (long)(1000 + random.nextInt(60 * 60 * 1000)); 490 } 491 492 @Override 493 public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) { 494 deviceManager.setMaximumTimeToLock(admin, getExpectedValue()); 495 } 496 497 @Override 498 protected Long getDeviceManagerValue(DevicePolicyManager deviceManager, 499 ComponentName admin) { 500 return deviceManager.getMaximumTimeToLock(admin); 501 } 502 } 503 } 504