Merge "Sample app for Android U lesson: Building apps for enterprise - Device administration." into ics-mr0
This commit is contained in:
@@ -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>
|
||||
3
samples/training/device-management-policy/_index.html
Executable file
3
samples/training/device-management-policy/_index.html
Executable 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.
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user