1 /* 2 * Copyright (C) 2010 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.example.android.apis.app; 18 19 import com.example.android.apis.R; 20 21 import android.app.Activity; 22 import android.app.ActivityManager; 23 import android.app.AlertDialog; 24 import android.app.admin.DeviceAdminReceiver; 25 import android.app.admin.DevicePolicyManager; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.DialogInterface; 29 import android.content.Intent; 30 import android.content.SharedPreferences; 31 import android.os.Bundle; 32 import android.text.Editable; 33 import android.text.TextWatcher; 34 import android.util.Log; 35 import android.view.View; 36 import android.view.View.OnClickListener; 37 import android.widget.AdapterView; 38 import android.widget.ArrayAdapter; 39 import android.widget.Button; 40 import android.widget.EditText; 41 import android.widget.Spinner; 42 import android.widget.Toast; 43 import android.widget.AdapterView.OnItemSelectedListener; 44 45 /** 46 * Example of a do-nothing admin class. When enabled, it lets you control 47 * some of its policy and reports when there is interesting activity. 48 */ 49 public class DeviceAdminSample extends DeviceAdminReceiver { 50 51 static SharedPreferences getSamplePreferences(Context context) { 52 return context.getSharedPreferences(DeviceAdminReceiver.class.getName(), 0); 53 } 54 55 static String PREF_PASSWORD_QUALITY = "password_quality"; 56 static String PREF_PASSWORD_LENGTH = "password_length"; 57 static String PREF_MAX_FAILED_PW = "max_failed_pw"; 58 59 void showToast(Context context, CharSequence msg) { 60 Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); 61 } 62 63 @Override 64 public void onEnabled(Context context, Intent intent) { 65 showToast(context, "Sample Device Admin: enabled"); 66 } 67 68 @Override 69 public CharSequence onDisableRequested(Context context, Intent intent) { 70 return "This is an optional message to warn the user about disabling."; 71 } 72 73 @Override 74 public void onDisabled(Context context, Intent intent) { 75 showToast(context, "Sample Device Admin: disabled"); 76 } 77 78 @Override 79 public void onPasswordChanged(Context context, Intent intent) { 80 showToast(context, "Sample Device Admin: pw changed"); 81 } 82 83 @Override 84 public void onPasswordFailed(Context context, Intent intent) { 85 showToast(context, "Sample Device Admin: pw failed"); 86 } 87 88 @Override 89 public void onPasswordSucceeded(Context context, Intent intent) { 90 showToast(context, "Sample Device Admin: pw succeeded"); 91 } 92 93 /** 94 * <p>UI control for the sample device admin. This provides an interface 95 * to enable, disable, and perform other operations with it to see 96 * their effect.</p> 97 * 98 * <p>Note that this is implemented as an inner class only keep the sample 99 * all together; typically this code would appear in some separate class. 100 */ 101 public static class Controller extends Activity { 102 static final int RESULT_ENABLE = 1; 103 104 DevicePolicyManager mDPM; 105 ActivityManager mAM; 106 ComponentName mDeviceAdminSample; 107 108 Button mEnableButton; 109 Button mDisableButton; 110 111 // Password quality spinner choices 112 // This list must match the list found in samples/ApiDemos/res/values/arrays.xml 113 final static int mPasswordQualityValues[] = new int[] { 114 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 115 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 116 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, 117 DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, 118 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC 119 }; 120 Spinner mPasswordQuality; 121 EditText mPasswordLength; 122 Button mSetPasswordButton; 123 124 EditText mPassword; 125 Button mResetPasswordButton; 126 127 EditText mMaxFailedPw; 128 129 Button mForceLockButton; 130 Button mWipeDataButton; 131 132 private Button mTimeoutButton; 133 134 private EditText mTimeout; 135 136 @Override 137 protected void onCreate(Bundle savedInstanceState) { 138 super.onCreate(savedInstanceState); 139 140 mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); 141 mAM = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); 142 mDeviceAdminSample = new ComponentName(Controller.this, DeviceAdminSample.class); 143 144 setContentView(R.layout.device_admin_sample); 145 146 // Watch for button clicks. 147 mEnableButton = (Button)findViewById(R.id.enable); 148 mEnableButton.setOnClickListener(mEnableListener); 149 mDisableButton = (Button)findViewById(R.id.disable); 150 mDisableButton.setOnClickListener(mDisableListener); 151 152 mPasswordQuality = (Spinner)findViewById(R.id.password_quality); 153 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource( 154 this, R.array.password_qualities, android.R.layout.simple_spinner_item); 155 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 156 mPasswordQuality.setAdapter(adapter); 157 mPasswordQuality.setOnItemSelectedListener( 158 new OnItemSelectedListener() { 159 public void onItemSelected( 160 AdapterView<?> parent, View view, int position, long id) { 161 setPasswordQuality(mPasswordQualityValues[position]); 162 } 163 164 public void onNothingSelected(AdapterView<?> parent) { 165 setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); 166 } 167 }); 168 mPasswordLength = (EditText)findViewById(R.id.password_length); 169 mPasswordLength.addTextChangedListener(new TextWatcher() { 170 public void afterTextChanged(Editable s) { 171 } 172 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 173 } 174 public void onTextChanged(CharSequence s, int start, int before, int count) { 175 try { 176 setPasswordLength(Integer.parseInt(s.toString())); 177 } catch (NumberFormatException e) { 178 } 179 } 180 }); 181 mSetPasswordButton = (Button)findViewById(R.id.set_password); 182 mSetPasswordButton.setOnClickListener(mSetPasswordListener); 183 184 mPassword = (EditText)findViewById(R.id.password); 185 mResetPasswordButton = (Button)findViewById(R.id.reset_password); 186 mResetPasswordButton.setOnClickListener(mResetPasswordListener); 187 188 mMaxFailedPw = (EditText)findViewById(R.id.max_failed_pw); 189 mMaxFailedPw.addTextChangedListener(new TextWatcher() { 190 public void afterTextChanged(Editable s) { 191 } 192 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 193 } 194 public void onTextChanged(CharSequence s, int start, int before, int count) { 195 try { 196 int maxFailCount = Integer.parseInt(s.toString()); 197 if (maxFailCount > 0) { 198 Toast.makeText(Controller.this, "WARNING: Phone will wipe after " + 199 s + " incorrect passwords", Toast.LENGTH_SHORT).show(); 200 } 201 setMaxFailedPw(maxFailCount); 202 } catch (NumberFormatException e) { 203 } 204 } 205 }); 206 207 mForceLockButton = (Button)findViewById(R.id.force_lock); 208 mForceLockButton.setOnClickListener(mForceLockListener); 209 mWipeDataButton = (Button)findViewById(R.id.wipe_data); 210 mWipeDataButton.setOnClickListener(mWipeDataListener); 211 212 mTimeout = (EditText) findViewById(R.id.timeout); 213 mTimeoutButton = (Button) findViewById(R.id.set_timeout); 214 mTimeoutButton.setOnClickListener(mSetTimeoutListener); 215 } 216 217 void updateButtonStates() { 218 boolean active = mDPM.isAdminActive(mDeviceAdminSample); 219 if (active) { 220 mEnableButton.setEnabled(false); 221 mDisableButton.setEnabled(true); 222 mPasswordQuality.setEnabled(true); 223 mPasswordLength.setEnabled(true); 224 mSetPasswordButton.setEnabled(true); 225 mPassword.setEnabled(true); 226 mResetPasswordButton.setEnabled(true); 227 mForceLockButton.setEnabled(true); 228 mWipeDataButton.setEnabled(true); 229 } else { 230 mEnableButton.setEnabled(true); 231 mDisableButton.setEnabled(false); 232 mPasswordQuality.setEnabled(false); 233 mPasswordLength.setEnabled(false); 234 mSetPasswordButton.setEnabled(false); 235 mPassword.setEnabled(false); 236 mResetPasswordButton.setEnabled(false); 237 mForceLockButton.setEnabled(false); 238 mWipeDataButton.setEnabled(false); 239 } 240 } 241 242 void updateControls() { 243 SharedPreferences prefs = getSamplePreferences(this); 244 final int pwQuality = prefs.getInt(PREF_PASSWORD_QUALITY, 245 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); 246 final int pwLength = prefs.getInt(PREF_PASSWORD_LENGTH, 0); 247 final int maxFailedPw = prefs.getInt(PREF_MAX_FAILED_PW, 0); 248 249 for (int i=0; i<mPasswordQualityValues.length; i++) { 250 if (mPasswordQualityValues[i] == pwQuality) { 251 mPasswordQuality.setSelection(i); 252 } 253 } 254 mPasswordLength.setText(Integer.toString(pwLength)); 255 mMaxFailedPw.setText(Integer.toString(maxFailedPw)); 256 } 257 258 void updatePolicies() { 259 SharedPreferences prefs = getSamplePreferences(this); 260 final int pwQuality = prefs.getInt(PREF_PASSWORD_QUALITY, 261 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); 262 final int pwLength = prefs.getInt(PREF_PASSWORD_LENGTH, 0); 263 final int maxFailedPw = prefs.getInt(PREF_MAX_FAILED_PW, 0); 264 265 boolean active = mDPM.isAdminActive(mDeviceAdminSample); 266 if (active) { 267 mDPM.setPasswordQuality(mDeviceAdminSample, pwQuality); 268 mDPM.setPasswordMinimumLength(mDeviceAdminSample, pwLength); 269 mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw); 270 } 271 } 272 273 void setPasswordQuality(int quality) { 274 SharedPreferences prefs = getSamplePreferences(this); 275 prefs.edit().putInt(PREF_PASSWORD_QUALITY, quality).commit(); 276 updatePolicies(); 277 } 278 279 void setPasswordLength(int length) { 280 SharedPreferences prefs = getSamplePreferences(this); 281 prefs.edit().putInt(PREF_PASSWORD_LENGTH, length).commit(); 282 updatePolicies(); 283 } 284 285 void setMaxFailedPw(int length) { 286 SharedPreferences prefs = getSamplePreferences(this); 287 prefs.edit().putInt(PREF_MAX_FAILED_PW, length).commit(); 288 updatePolicies(); 289 } 290 291 @Override 292 protected void onResume() { 293 super.onResume(); 294 updateButtonStates(); 295 } 296 297 @Override 298 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 299 switch (requestCode) { 300 case RESULT_ENABLE: 301 if (resultCode == Activity.RESULT_OK) { 302 Log.i("DeviceAdminSample", "Admin enabled!"); 303 } else { 304 Log.i("DeviceAdminSample", "Admin enable FAILED!"); 305 } 306 return; 307 } 308 309 super.onActivityResult(requestCode, resultCode, data); 310 } 311 312 private OnClickListener mEnableListener = new OnClickListener() { 313 public void onClick(View v) { 314 // Launch the activity to have the user enable our admin. 315 Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); 316 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, 317 mDeviceAdminSample); 318 intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, 319 "Additional text explaining why this needs to be added."); 320 startActivityForResult(intent, RESULT_ENABLE); 321 } 322 }; 323 324 private OnClickListener mDisableListener = new OnClickListener() { 325 public void onClick(View v) { 326 mDPM.removeActiveAdmin(mDeviceAdminSample); 327 updateButtonStates(); 328 } 329 }; 330 331 private OnClickListener mSetPasswordListener = new OnClickListener() { 332 public void onClick(View v) { 333 // Launch the activity to have the user set a new password. 334 Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); 335 startActivity(intent); 336 } 337 }; 338 339 private OnClickListener mResetPasswordListener = new OnClickListener() { 340 public void onClick(View v) { 341 if (mAM.isUserAMonkey()) { 342 // Don't trust monkeys to do the right thing! 343 AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this); 344 builder.setMessage("You can't reset my password because you are a monkey!"); 345 builder.setPositiveButton("I admit defeat", null); 346 builder.show(); 347 return; 348 } 349 boolean active = mDPM.isAdminActive(mDeviceAdminSample); 350 if (active) { 351 mDPM.resetPassword(mPassword.getText().toString(), 352 DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY); 353 } 354 } 355 }; 356 357 private OnClickListener mForceLockListener = new OnClickListener() { 358 public void onClick(View v) { 359 if (mAM.isUserAMonkey()) { 360 // Don't trust monkeys to do the right thing! 361 AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this); 362 builder.setMessage("You can't lock my screen because you are a monkey!"); 363 builder.setPositiveButton("I admit defeat", null); 364 builder.show(); 365 return; 366 } 367 boolean active = mDPM.isAdminActive(mDeviceAdminSample); 368 if (active) { 369 mDPM.lockNow(); 370 } 371 } 372 }; 373 374 private OnClickListener mWipeDataListener = new OnClickListener() { 375 public void onClick(View v) { 376 if (mAM.isUserAMonkey()) { 377 // Don't trust monkeys to do the right thing! 378 AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this); 379 builder.setMessage("You can't wipe my data because you are a monkey!"); 380 builder.setPositiveButton("I admit defeat", null); 381 builder.show(); 382 return; 383 } 384 AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this); 385 builder.setMessage("This will erase all of your data. Are you sure?"); 386 builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { 387 public void onClick(DialogInterface dialog, int which) { 388 AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this); 389 builder.setMessage("This is not a test. " 390 + "This WILL erase all of your data! " 391 + "Are you really absolutely sure?"); 392 builder.setPositiveButton("BOOM!", new DialogInterface.OnClickListener() { 393 public void onClick(DialogInterface dialog, int which) { 394 boolean active = mDPM.isAdminActive(mDeviceAdminSample); 395 if (active) { 396 mDPM.wipeData(0); 397 } 398 } 399 }); 400 builder.setNegativeButton("Oops, run away!", null); 401 builder.show(); 402 } 403 }); 404 builder.setNegativeButton("No way!", null); 405 builder.show(); 406 } 407 }; 408 409 private OnClickListener mSetTimeoutListener = new OnClickListener() { 410 411 public void onClick(View v) { 412 if (mAM.isUserAMonkey()) { 413 // Don't trust monkeys to do the right thing! 414 AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this); 415 builder.setMessage("You can't lock my screen because you are a monkey!"); 416 builder.setPositiveButton("I admit defeat", null); 417 builder.show(); 418 return; 419 } 420 boolean active = mDPM.isAdminActive(mDeviceAdminSample); 421 if (active) { 422 long timeMs = 1000L*Long.parseLong(mTimeout.getText().toString()); 423 mDPM.setMaximumTimeToLock(mDeviceAdminSample, timeMs); 424 } 425 } 426 }; 427 } 428 } 429