Merge "Sample app for Android U lesson: Building apps for enterprise - Device administration." into ics-mr0

This commit is contained in:
Scott Main
2011-12-15 10:11:55 -08:00
committed by Android (Google) Code Review
16 changed files with 976 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
<!--
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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.training.deviceadmin"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8"
android:targetSdkVersion="14" />
<application android:label="@string/app_name">
<activity android:name=".PolicySetupActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.training.deviceadmin.SecureActivity"
android:label="@string/app_name"/>
<receiver android:name="com.example.training.deviceadmin.Policy$PolicyAdmin"
android:label="@string/app_policy_admin_name"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -0,0 +1,3 @@
<p>This is a security-aware sample application that demonstrates the enforcement of device administration policies on Android 2.2 or above platforms.</p>
<p>Refer to the <a href="/training/enterprise/device-management-policy.html" />Enhancing Security with Device Management Policies</a> class for detail.

View File

@@ -0,0 +1,93 @@
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/top_padding"
android:paddingLeft="@dimen/side_padding"
android:paddingRight="@dimen/side_padding" >
<TextView android:id="@+id/policy_instructions"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/setup_policy_instruction"
android:textSize="@dimen/text_size_medium" />
<!-- Password type -->
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/setup_password_quality"
android:textSize="@dimen/text_size_small"
android:paddingTop="3dp" />
<Spinner android:id="@+id/policy_password_quality"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:prompt="@string/setup_password_quality"
android:paddingBottom="3dp"
android:focusable="true" >
<requestFocus/>
</Spinner>
<!-- Minimum password length -->
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/setup_password_length"
android:textSize="@dimen/text_size_small"
android:paddingTop="3dp" />
<EditText android:id="@+id/policy_password_length"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:hint="@string/setup_password_length"
android:inputType="number" />
<!-- Minimum password uppercase characters -->
<LinearLayout android:id="@+id/password_uppercase_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/setup_password_uppercase"
android:textSize="@dimen/text_size_small"
android:paddingTop="3dp" />
<EditText android:id="@+id/policy_password_uppercase"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:hint="@string/setup_password_uppercase"
android:inputType="number" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<TextView android:id="@+id/setup_message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_medium"
android:paddingBottom="5dp"
android:paddingLeft="@dimen/side_padding"
android:paddingRight="@dimen/side_padding" />
<Button android:id="@+id/setup_action_btn"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:minWidth="200dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/top_padding" />
</LinearLayout>

View File

@@ -0,0 +1,26 @@
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView android:layout_height="wrap_content"
android:text="@string/secure_message"
android:textSize="@dimen/text_size_large"
android:layout_width="wrap_content"
android:gravity="center_vertical|center_horizontal" />
</LinearLayout>

View File

@@ -0,0 +1,89 @@
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/top_padding"
android:paddingLeft="@dimen/side_padding"
android:paddingRight="@dimen/side_padding" >
<TextView android:id="@+id/policy_instructions"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/view_policy_instruction"
android:textSize="@dimen/text_size_medium" />
<!-- Password type -->
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/view_password_quality"
android:textSize="@dimen/text_size_small"
android:paddingTop="3dp" />
<TextView android:id="@+id/policy_password_quality"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingBottom="3dp"
android:paddingLeft="3dp" />
<!-- Minimum password length -->
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/view_password_length"
android:textSize="@dimen/text_size_small"
android:paddingTop="3dp" />
<TextView android:id="@+id/policy_password_length"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingBottom="3dp"
android:paddingLeft="3dp" />
<!-- Minimum password uppercase characters -->
<LinearLayout android:id="@+id/password_uppercase_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/view_password_uppercase"
android:textSize="@dimen/text_size_small"
android:paddingTop="3dp" />
<TextView android:id="@+id/policy_password_uppercase"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingLeft="3dp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<TextView android:id="@+id/setup_message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_medium"
android:paddingBottom="5dp"
android:paddingLeft="@dimen/side_padding"
android:paddingRight="@dimen/side_padding" />
<Button android:id="@+id/setup_action_btn"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:minWidth="200dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/top_padding" />
</LinearLayout>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<string-array name="password_types">
<item>Anything</item>
<item>Something</item>
<item>Numeric</item>
<item>Alphabetic</item>
<item>Alphanumeric</item>
<item>Complex</item>
</string-array>
</resources>

View File

@@ -0,0 +1,26 @@
<!--
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.
-->
<resources>
<!-- UI elements -->
<dimen name="top_padding">60dp</dimen>
<dimen name="side_padding">100dp</dimen>
<!-- body content -->
<dimen name="text_size_small">18sp</dimen>
<dimen name="text_size_medium">24sp</dimen>
<dimen name="text_size_large">26sp</dimen>
</resources>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<string-array name="password_types">
<item>Anything</item>
<item>Something</item>
<item>Numeric</item>
<item>Alphabetic</item>
<item>Alphanumeric</item>
</string-array>
</resources>

View File

@@ -0,0 +1,50 @@
<!--
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.
-->
<resources>
<declare-styleable name="AppTheme">
<attr name="actionbarCompatTitleStyle" format="reference" />
<attr name="actionbarCompatButtonStyle" format="reference" />
<attr name="actionbarCompatButtonHomeStyle" format="reference" />
<attr name="actionbarCompatProgressIndicatorStyle" format="reference" />
</declare-styleable>
<!-- Mostly taken from frameworks/base.git/core/res/res/values/attrs.xml -->
<declare-styleable name="TextAppearance">
<attr name="textColor" format="color" />
<attr name="textSize" format="dimension" />
<attr name="textStyle">
<flag name="normal" value="0" />
<flag name="bold" value="1" />
<flag name="italic" value="2" />
</attr>
<attr name="typeface">
<enum name="normal" value="0" />
<enum name="sans" value="1" />
<enum name="serif" value="2" />
<enum name="monospace" value="3" />
</attr>
<attr name="shadowRadius" format="float" />
<attr name="shadowDx" format="float" />
<attr name="shadowDy" format="float" />
<attr name="shadowColor" format="color" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,19 @@
<!--
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.
-->
<resources>
<color name="accent_1">#224894</color>
</resources>

View File

@@ -0,0 +1,26 @@
<!--
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.
-->
<resources>
<!-- UI elements -->
<dimen name="top_padding">10dp</dimen>
<dimen name="side_padding">5dp</dimen>
<!-- body content -->
<dimen name="text_size_small">14sp</dimen>
<dimen name="text_size_medium">18sp</dimen>
<dimen name="text_size_large">20sp</dimen>
</resources>

View File

@@ -0,0 +1,43 @@
<!--
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.
-->
<resources>
<string name="app_name">Device Admin Lesson</string>
<string name="app_policy_admin_name">Policy Admin Receiver</string>
<!-- Setup activity -->
<string name="setup_policy_instruction">Set up device administration policy:</string>
<string name="setup_password_quality">Select a password quality</string>
<string name="setup_password_length">Set min. pw. length</string>
<string name="setup_password_uppercase">Set min. pw. uppercase</string>
<string name="setup_action_activate">Activate</string>
<string name="setup_message_activate">Press button to activate the device administrator</string>
<string name="setup_action_set_policy">Enforce Policy</string>
<string name="setup_message_set_policy">Press button to enforce specified policy.</string>
<string name="setup_action_enforce_policy">Update Password</string>
<string name="setup_message_enforce_policy">Current password doesn\'t conform to the policy.\nPress button to update password.</string>
<string name="setup_action_go_secured">Go</string>
<string name="setup_message_go_secured">Current password conforms to policy. Device is protected.\nPress button to access secured content.</string>
<!-- View policy activity -->
<string name="view_policy_instruction">Review device administration policy:</string>
<string name="view_password_quality">Password quality:</string>
<string name="view_password_length">Minimum password length:</string>
<string name="view_password_uppercase">Minimum password upper case:</string>
<string name="secure_message">Device is properly secured. Access is granted to secured content</string>
<string name="device_admin_activation_message">Provide a message here explaining why an application needs to become a device administrator.</string>
</resources>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2011 Google Inc.
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.
-->
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
</uses-policies>
</device-admin>

View File

@@ -0,0 +1,168 @@
/*
* 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.example.training.deviceadmin;
import android.app.Activity;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
public class Policy {
public static final int REQUEST_ADD_DEVICE_ADMIN = 1;
private static final String APP_PREF = "APP_PREF";
private static final String KEY_PASSWORD_LENGTH = "PW_LENGTH";
private static final String KEY_PASSWORD_QUALITY = "PW_QUALITY";
private static final String KEY_PASSWORD_MIN_UPPERCASE = "PW_MIN_UPPERCASE";
// Password quality values. This list must match the list
// found in res/values/arrays.xml
final static int[] PASSWORD_QUALITY_VALUES = new int[] {
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
};
private int mPasswordQuality;
private int mPasswordLength;
private int mPasswordMinUpperCase;
private Context mContext;
private DevicePolicyManager mDPM;
private ComponentName mPolicyAdmin;
public Policy(Context context) {
mContext = context;
mPasswordQuality = -1;
mPasswordLength = 0;
mPasswordMinUpperCase = 0;
mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
mPolicyAdmin = new ComponentName(context, PolicyAdmin.class);
}
/**
* Saves the policy parameters.
*
* @param passwordQuality Password quality.
* @param passwordLength Password minimum length.
* @param passwordUppercase Password minimum number of upper case alphabets.
*/
public void saveToLocal(int passwordQuality, int passwordLength, int passwordMinUppercase) {
SharedPreferences.Editor editor =
mContext.getSharedPreferences(APP_PREF, Context.MODE_PRIVATE).edit();
if (mPasswordQuality != passwordQuality) {
editor.putInt(KEY_PASSWORD_QUALITY, passwordQuality);
mPasswordQuality = passwordQuality;
}
if (mPasswordLength != passwordLength) {
editor.putInt(KEY_PASSWORD_LENGTH, passwordLength);
mPasswordLength = passwordLength;
}
if (mPasswordMinUpperCase != passwordMinUppercase) {
editor.putInt(KEY_PASSWORD_MIN_UPPERCASE, passwordMinUppercase);
mPasswordMinUpperCase = passwordMinUppercase;
}
editor.commit();
}
public void readFromLocal() {
SharedPreferences prefs = mContext.getSharedPreferences(APP_PREF, Context.MODE_PRIVATE);
mPasswordQuality = prefs.getInt(KEY_PASSWORD_QUALITY, -1);
mPasswordLength = prefs.getInt(KEY_PASSWORD_LENGTH, -1);
mPasswordMinUpperCase = prefs.getInt(KEY_PASSWORD_MIN_UPPERCASE, -1);
}
/**
* Getter for password quality.
*
* @return
*/
public int getPasswordQuality() { return mPasswordQuality; }
/**
* Getter for password length.
*
* @return
*/
public int getPasswordLength() { return mPasswordLength; }
/**
* Getter for password minimum upper case alphabets.
*
* @return
*/
public int getPasswordMinUpperCase() { return mPasswordMinUpperCase; }
/**
* Getter for the policy administrator ComponentName object.
*
* @return
*/
public ComponentName getPolicyAdmin() { return mPolicyAdmin; }
/**
* Indicates whether the device administrator is currently active.
*
* @return
*/
public boolean isAdminActive() {
return mDPM.isAdminActive(mPolicyAdmin);
}
public boolean isActivePasswordSufficient() {
return mDPM.isActivePasswordSufficient();
}
public boolean isDeviceSecured() {
return isAdminActive() && isActivePasswordSufficient();
}
/**
* Configure policy defined in the object.
*/
public void configurePolicy() {
mDPM.setPasswordQuality(mPolicyAdmin, PASSWORD_QUALITY_VALUES[mPasswordQuality]);
mDPM.setPasswordMinimumLength(mPolicyAdmin, mPasswordLength);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mDPM.setPasswordMinimumUpperCase(mPolicyAdmin, mPasswordMinUpperCase);
}
}
/**
* Through the PolicyAdmin receiver, the app can use this to trap various device
* administration events, such as password change, incorrect password entry, etc.
*
*/
public static class PolicyAdmin extends DeviceAdminReceiver {
@Override
public void onDisabled(Context context, Intent intent) {
// Called when the app is about to be deactivated as a device administrator.
// Deletes previously stored password policy.
super.onDisabled(context, intent);
SharedPreferences prefs = context.getSharedPreferences(APP_PREF, Activity.MODE_PRIVATE);
prefs.edit().clear().commit();
}
}
}

View File

@@ -0,0 +1,275 @@
/*
* 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.example.training.deviceadmin;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
/**
* Main Activity for the sample application.
*
* The Activity maintains and presents 2 different
* screens to the user -- a screen for configuring device administration policy and another screen
* for viewing configured policy. When it is detected that the screen-lock password satisfies
* the password strength required by the policy, the user is sent to an Activity containing
* protected content.
*/
public class PolicySetupActivity extends Activity {
private static final int REQ_ACTIVATE_DEVICE_ADMIN = 10;
private static final String SCREEN_ID_KEY = "LAYOUT_ID";
private static final String APP_PREF = "APP_PREF";
private static final int UNKNOWN_SCREEN_ID = -1;
// UI controls in policy setup screen.
private Spinner mPasswordQualityInputField;
private EditText mPasswordLengthInputField;
private EditText mPasswordMinUppercaseInputField;
private Policy mPolicy;
private int mCurrentScreenId;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPolicy = new Policy(this);
}
@Override
protected void onResume() {
super.onResume();
SharedPreferences prefs = getSharedPreferences(APP_PREF, MODE_PRIVATE);
final int savedScreenId = prefs.getInt(SCREEN_ID_KEY, UNKNOWN_SCREEN_ID);
if (savedScreenId == UNKNOWN_SCREEN_ID || !mPolicy.isAdminActive()) {
setScreenContent(R.layout.activity_policy_setup);
} else {
setScreenContent(savedScreenId);
}
}
private void setScreenContent(final int screenId) {
mCurrentScreenId = screenId;
setContentView(mCurrentScreenId);
getSharedPreferences(APP_PREF, MODE_PRIVATE).edit().putInt(
SCREEN_ID_KEY, mCurrentScreenId).commit();
switch (mCurrentScreenId) {
case R.layout.activity_policy_setup:
initPolicySetupScreen();
initNavigation();
break;
case R.layout.activity_view_policy:
initViewPolicyScreen();
initNavigation();
break;
}
}
@Override
protected void onPause() {
super.onPause();
if (mCurrentScreenId == R.layout.activity_policy_setup) writePolicy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQ_ACTIVATE_DEVICE_ADMIN && resultCode == RESULT_OK) {
// User just activated the application as a device administrator.
setScreenContent(mCurrentScreenId);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onBackPressed() {
if (mCurrentScreenId == R.layout.activity_view_policy) {
setScreenContent(R.layout.activity_policy_setup);
return;
}
super.onBackPressed();
}
// Initialize policy set up screen.
private void initPolicySetupScreen() {
mPasswordQualityInputField = (Spinner) findViewById(R.id.policy_password_quality);
mPasswordLengthInputField = (EditText) findViewById(R.id.policy_password_length);
mPasswordMinUppercaseInputField = (EditText) findViewById(R.id.policy_password_uppercase);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.password_types, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mPasswordQualityInputField.setAdapter(adapter);
mPasswordQualityInputField.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
LinearLayout passwordMinUppercaseView =
(LinearLayout) findViewById(R.id.password_uppercase_view);
// The minimum number of upper case field is only applicable for password
// qualities: alpha, alphanumeric, or complex.
if (pos > 2)
passwordMinUppercaseView.setVisibility(View.VISIBLE);
else
passwordMinUppercaseView.setVisibility(View.GONE);
}
public void onNothingSelected(AdapterView<?> parent) {}
});
// Read previously saved policy and populate on the UI.
mPolicy.readFromLocal();
mPasswordQualityInputField.setSelection(mPolicy.getPasswordQuality());
if (mPolicy.getPasswordLength() > 0) {
mPasswordLengthInputField.setText(String.valueOf(mPolicy.getPasswordLength()));
} else {
mPasswordLengthInputField.setText("");
}
if (mPolicy.getPasswordMinUpperCase() > 0) {
mPasswordMinUppercaseInputField.setText(
String.valueOf(mPolicy.getPasswordMinUpperCase()));
} else {
mPasswordMinUppercaseInputField.setText("");
}
}
// Initialize policy viewing screen.
private void initViewPolicyScreen() {
TextView passwordQualityView = (TextView) findViewById(R.id.policy_password_quality);
TextView passwordLengthView = (TextView) findViewById(R.id.policy_password_length);
// Read previously saved policy and populate on the UI.
mPolicy.readFromLocal();
int passwordQualitySelection = mPolicy.getPasswordQuality();
passwordQualityView.setText(
getResources().getStringArray(R.array.password_types)[passwordQualitySelection]);
passwordLengthView.setText(String.valueOf(mPolicy.getPasswordLength()));
if (passwordQualitySelection > 2) {
LinearLayout passwordMinUppercaseView =
(LinearLayout) findViewById(R.id.password_uppercase_view);
passwordMinUppercaseView.setVisibility(View.VISIBLE);
((TextView) findViewById(R.id.policy_password_uppercase)).setText(
String.valueOf(mPolicy.getPasswordMinUpperCase()));
}
}
// Set up navigation message and action button.
private void initNavigation() {
if (!mPolicy.isAdminActive()) {
// Activates device administrator.
setupNavigation(R.string.setup_message_activate,
R.string.setup_action_activate,
mActivateButtonListener);
} else if (mCurrentScreenId == R.layout.activity_policy_setup) {
setupNavigation(R.string.setup_message_set_policy,
R.string.setup_action_set_policy,
new View.OnClickListener() {
public void onClick(View view) {
writePolicy();
mPolicy.configurePolicy();
setScreenContent(R.layout.activity_view_policy);
}
});
}
else if (!mPolicy.isActivePasswordSufficient()) {
// Launches password set-up screen in Settings.
setupNavigation(R.string.setup_message_enforce_policy,
R.string.setup_action_enforce_policy,
mEnforcePolicyListener);
} else {
// Grants access to secure content.
setupNavigation(R.string.setup_message_go_secured,
R.string.setup_action_go_secured,
new View.OnClickListener() {
public void onClick(View view) {
startActivity(new Intent(view.getContext(), SecureActivity.class));
}
});
}
}
private View.OnClickListener mActivateButtonListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// First, persist the policy. Then, launch intent to trigger the system screen
// requesting user to confirm the activation of the device administrator.
writePolicy();
Intent activateDeviceAdminIntent =
new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
activateDeviceAdminIntent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
mPolicy.getPolicyAdmin());
// It is good practice to include the optional explanation text to explain to
// user why the application is requesting to be a device administrator. The system
// will display this message on the activation screen.
activateDeviceAdminIntent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
getResources().getString(R.string.device_admin_activation_message));
startActivityForResult(activateDeviceAdminIntent, REQ_ACTIVATE_DEVICE_ADMIN);
}
};
private View.OnClickListener mEnforcePolicyListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
writePolicy();
// The device administration API does not "fix" the password if it is
// determined that the current password does not conform to what is requested
// by the policy. The caller is responsible for triggering the password set up
// screen via the below intent.
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
startActivity(intent);
}
};
// Setup action button text and listener.
private void setupNavigation(int messageResId, int buttonTextResId,
View.OnClickListener listener) {
TextView setupMessage = (TextView) findViewById(R.id.setup_message);
setupMessage.setText(messageResId);
Button actionBtn = (Button) findViewById(R.id.setup_action_btn);
actionBtn.setText(buttonTextResId);
actionBtn.setOnClickListener(listener);
}
// Save policy to shared preferences.
private void writePolicy() {
int passwordQuality = (int) mPasswordQualityInputField.getSelectedItemId();
int passwordLength = 0;
try {
passwordLength = Integer.valueOf(mPasswordLengthInputField.getText().toString());
} catch (NumberFormatException nfe) {} // Defaults to 0.
int passwordMinUppercase = 0;
try {
passwordMinUppercase =
Integer.valueOf(mPasswordMinUppercaseInputField.getText().toString());
} catch (NumberFormatException nfe) {} // Defaults to 0.
mPolicy.saveToLocal(passwordQuality, passwordLength, passwordMinUppercase);
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.example.training.deviceadmin;
import android.app.Activity;
import android.content.Intent;
public class SecureActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
// Check to see if the device is properly secured as per the policy. Send user
// back to policy set up screen if necessary.
Policy policy = new Policy(this);
policy.readFromLocal();
if (!policy.isDeviceSecured()) {
Intent intent = new Intent();
intent.setClass(this, PolicySetupActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP |
Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
setContentView(R.layout.activity_secure);
}
}