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