aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuichi Araki <yaraki@google.com>2015-01-19 14:51:32 +0900
committerYuichi Araki <yaraki@google.com>2015-03-24 17:57:57 +0900
commit801f6992d533f888b51aad8b99d017246e273fbf (patch)
tree966ee688187beace5ef3f2c3da213e8956ab51a3
parent72a5ab0293b66c4ce48b6465fa0db5320db446af (diff)
downloadandroid-801f6992d533f888b51aad8b99d017246e273fbf.tar.gz
DeviceOwner: Add a new sample
This sample demonstrates device owner feature of Android for Work. Change-Id: I5cb35e2be8a115e8187d0d90180be5ecdb58c03e
-rw-r--r--admin/DeviceOwner/Application/.gitignore16
-rw-r--r--admin/DeviceOwner/Application/README-fragmentview.txt37
-rw-r--r--admin/DeviceOwner/Application/README-singleview.txt47
-rw-r--r--admin/DeviceOwner/Application/proguard-project.txt20
-rw-r--r--admin/DeviceOwner/Application/src/main/AndroidManifest.xml54
-rw-r--r--admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerFragment.java334
-rw-r--r--admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerReceiver.java56
-rw-r--r--admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/InstructionFragment.java45
-rw-r--r--admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/MainActivity.java55
-rw-r--r--admin/DeviceOwner/Application/src/main/res/drawable-hdpi/ic_launcher.pngbin0 -> 4627 bytes
-rw-r--r--admin/DeviceOwner/Application/src/main/res/drawable-mdpi/ic_launcher.pngbin0 -> 2796 bytes
-rw-r--r--admin/DeviceOwner/Application/src/main/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6533 bytes
-rw-r--r--admin/DeviceOwner/Application/src/main/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11625 bytes
-rw-r--r--admin/DeviceOwner/Application/src/main/res/layout/activity_main_real.xml24
-rw-r--r--admin/DeviceOwner/Application/src/main/res/layout/fragment_device_owner.xml83
-rw-r--r--admin/DeviceOwner/Application/src/main/res/layout/fragment_instruction.xml32
-rw-r--r--admin/DeviceOwner/Application/src/main/res/values/strings.xml34
-rw-r--r--admin/DeviceOwner/Application/src/main/res/xml/device_owner_receiver.xml28
-rw-r--r--admin/DeviceOwner/build.gradle11
-rw-r--r--admin/DeviceOwner/buildSrc/build.gradle15
-rw-r--r--admin/DeviceOwner/gradle/wrapper/gradle-wrapper.jarbin0 -> 49896 bytes
-rw-r--r--admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xadmin/DeviceOwner/gradlew164
-rw-r--r--admin/DeviceOwner/gradlew.bat90
-rw-r--r--admin/DeviceOwner/screenshots/1-main.pngbin0 -> 51004 bytes
-rwxr-xr-xadmin/DeviceOwner/screenshots/icon-web.pngbin0 -> 77003 bytes
-rw-r--r--admin/DeviceOwner/settings.gradle1
-rw-r--r--admin/DeviceOwner/template-params.xml82
28 files changed, 1234 insertions, 0 deletions
diff --git a/admin/DeviceOwner/Application/.gitignore b/admin/DeviceOwner/Application/.gitignore
new file mode 100644
index 00000000..1bac3a5f
--- /dev/null
+++ b/admin/DeviceOwner/Application/.gitignore
@@ -0,0 +1,16 @@
+# Copyright 2015 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.
+src/template/
+src/common/
+build.gradle
diff --git a/admin/DeviceOwner/Application/README-fragmentview.txt b/admin/DeviceOwner/Application/README-fragmentview.txt
new file mode 100644
index 00000000..b346a5fd
--- /dev/null
+++ b/admin/DeviceOwner/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ Copyright 2015 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/admin/DeviceOwner/Application/README-singleview.txt b/admin/DeviceOwner/Application/README-singleview.txt
new file mode 100644
index 00000000..57fa1341
--- /dev/null
+++ b/admin/DeviceOwner/Application/README-singleview.txt
@@ -0,0 +1,47 @@
+<#--
+ Copyright 2015 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.
+-->
+
+Steps to implement SingleView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+ -add a string for the action button's text using the element name "sample_action".
+ This element should be a child of <strings>:
+ <strings>
+ ...
+ <sample_action>ButtonText</sample_action>
+ ...
+ </strings>
+
+
+
+-Add a Fragment to handle behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/singleViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/admin/DeviceOwner/Application/proguard-project.txt b/admin/DeviceOwner/Application/proguard-project.txt
new file mode 100644
index 00000000..f2fe1559
--- /dev/null
+++ b/admin/DeviceOwner/Application/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/admin/DeviceOwner/Application/src/main/AndroidManifest.xml b/admin/DeviceOwner/Application/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..fb61ac9a
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2015 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
+ package="com.example.android.deviceowner"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ <receiver
+ android:name=".DeviceOwnerReceiver"
+ android:description="@string/app_name"
+ android:label="@string/app_name"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data
+ android:name="android.app.device_admin"
+ android:resource="@xml/device_owner_receiver"/>
+ <intent-filter>
+ <action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE"/>
+ </intent-filter>
+ </receiver>
+
+ </application>
+
+
+</manifest>
diff --git a/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerFragment.java b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerFragment.java
new file mode 100644
index 00000000..b5c62548
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerFragment.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2015 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.android.deviceowner;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.SimpleAdapter;
+import android.widget.Spinner;
+import android.widget.Switch;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Demonstrates the usage of the most common device management APIs for the device owner case.
+ * In addition to various features available for profile owners, device owners can perform extra
+ * actions, such as configuring global settings and enforcing a preferred Activity for a specific
+ * IntentFilter.
+ */
+public class DeviceOwnerFragment extends Fragment {
+
+ // Keys for SharedPreferences
+ private static final String PREFS_DEVICE_OWNER = "DeviceOwnerFragment";
+ private static final String PREF_LAUNCHER = "launcher";
+
+ private DevicePolicyManager mDevicePolicyManager;
+
+ // View references
+ private Switch mSwitchAutoTime;
+ private Switch mSwitchAutoTimeZone;
+ private Spinner mAvailableLaunchers;
+ private Button mButtonLauncher;
+
+ // Adapter for the spinner to show list of available launchers
+ private LauncherAdapter mAdapter;
+
+ /**
+ * Handles events on the Switches.
+ */
+ private Switch.OnCheckedChangeListener mOnCheckedChangeListener
+ = new Switch.OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ switch (buttonView.getId()) {
+ case R.id.switch_auto_time:
+ setBooleanGlobalSetting(Settings.Global.AUTO_TIME, isChecked);
+ retrieveCurrentSettings(getActivity());
+ break;
+ case R.id.switch_auto_time_zone:
+ setBooleanGlobalSetting(Settings.Global.AUTO_TIME_ZONE, isChecked);
+ retrieveCurrentSettings(getActivity());
+ break;
+ }
+ }
+
+ };
+
+ /**
+ * Handles click events on the Button.
+ */
+ private View.OnClickListener mOnClickListener
+ = new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.set_preferred_launcher:
+ if (loadPersistentPreferredLauncher(getActivity()) == null) {
+ setPreferredLauncher();
+ } else {
+ clearPreferredLauncher();
+ }
+ retrieveCurrentSettings(getActivity());
+ break;
+ }
+ }
+
+ };
+
+ /**
+ * @return A newly instantiated {@link DeviceOwnerFragment}.
+ */
+ public static DeviceOwnerFragment newInstance() {
+ return new DeviceOwnerFragment();
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_device_owner, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ // Retain references
+ mSwitchAutoTime = (Switch) view.findViewById(R.id.switch_auto_time);
+ mSwitchAutoTimeZone = (Switch) view.findViewById(R.id.switch_auto_time_zone);
+ mAvailableLaunchers = (Spinner) view.findViewById(R.id.available_launchers);
+ mButtonLauncher = (Button) view.findViewById(R.id.set_preferred_launcher);
+ // Bind event handlers
+ mSwitchAutoTime.setOnCheckedChangeListener(mOnCheckedChangeListener);
+ mSwitchAutoTimeZone.setOnCheckedChangeListener(mOnCheckedChangeListener);
+ mButtonLauncher.setOnClickListener(mOnClickListener);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mDevicePolicyManager =
+ (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE);
+ }
+
+ @Override
+ public void onDetach() {
+ mDevicePolicyManager = null;
+ super.onDetach();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Activity activity = getActivity();
+ if (activity != null) {
+ retrieveCurrentSettings(activity);
+ }
+ }
+
+ /**
+ * Retrieves the current global settings and changes the UI accordingly.
+ *
+ * @param activity The activity
+ */
+ private void retrieveCurrentSettings(Activity activity) {
+ // Global settings
+ setCheckedSafely(mSwitchAutoTime,
+ getBooleanGlobalSetting(activity.getContentResolver(), Settings.Global.AUTO_TIME));
+ setCheckedSafely(mSwitchAutoTimeZone,
+ getBooleanGlobalSetting(activity.getContentResolver(),
+ Settings.Global.AUTO_TIME_ZONE));
+
+ // Launcher
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ List<ResolveInfo> list = activity.getPackageManager()
+ .queryIntentActivities(intent, /* default flags */ 0);
+ mAdapter = new LauncherAdapter(activity, list);
+ mAvailableLaunchers.setAdapter(mAdapter);
+ String packageName = loadPersistentPreferredLauncher(activity);
+ if (packageName == null) { // No preferred launcher is set
+ mAvailableLaunchers.setEnabled(true);
+ mButtonLauncher.setText(R.string.set_as_preferred);
+ } else {
+ int position = -1;
+ for (int i = 0; i < list.size(); ++i) {
+ if (list.get(i).activityInfo.packageName.equals(packageName)) {
+ position = i;
+ break;
+ }
+ }
+ if (position != -1) {
+ mAvailableLaunchers.setSelection(position);
+ mAvailableLaunchers.setEnabled(false);
+ mButtonLauncher.setText(R.string.clear_preferred);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the current boolean value of the specified global setting.
+ *
+ * @param resolver The ContentResolver
+ * @param setting The setting to be retrieved
+ * @return The current boolean value
+ */
+ private static boolean getBooleanGlobalSetting(ContentResolver resolver, String setting) {
+ return 0 != Settings.Global.getInt(resolver, setting, 0);
+ }
+
+ /**
+ * Sets the boolean value of the specified global setting.
+ *
+ * @param setting The setting to be set
+ * @param value The value to be set
+ */
+ private void setBooleanGlobalSetting(String setting, boolean value) {
+ mDevicePolicyManager.setGlobalSetting(
+ // The ComponentName of the device owner
+ DeviceOwnerReceiver.getComponentName(getActivity()),
+ // The settings to be set
+ setting,
+ // The value we write here is a string representation for SQLite
+ value ? "1" : "0");
+ }
+
+ /**
+ * A utility method to set the checked state of the button without invoking its listener.
+ *
+ * @param button The button
+ * @param checked The value to be set
+ */
+ private void setCheckedSafely(CompoundButton button, boolean checked) {
+ button.setOnCheckedChangeListener(null);
+ button.setChecked(checked);
+ button.setOnCheckedChangeListener(mOnCheckedChangeListener);
+ }
+
+ /**
+ * Loads the package name from SharedPreferences.
+ *
+ * @param activity The activity
+ * @return The package name of the launcher currently set as preferred, or null if there is no
+ * preferred launcher.
+ */
+ private static String loadPersistentPreferredLauncher(Activity activity) {
+ return activity.getSharedPreferences(PREFS_DEVICE_OWNER, Context.MODE_PRIVATE)
+ .getString(PREF_LAUNCHER, null);
+ }
+
+ /**
+ * Saves the package name into SharedPreferences.
+ *
+ * @param activity The activity
+ * @param packageName The package name to be saved. Pass null to remove the preferred launcher.
+ */
+ private static void savePersistentPreferredLauncher(Activity activity, String packageName) {
+ SharedPreferences.Editor editor = activity.getSharedPreferences(PREFS_DEVICE_OWNER,
+ Context.MODE_PRIVATE).edit();
+ if (packageName == null) {
+ editor.remove(PREF_LAUNCHER);
+ } else {
+ editor.putString(PREF_LAUNCHER, packageName);
+ }
+ editor.apply();
+ }
+
+ /**
+ * Sets the selected launcher as preferred.
+ */
+ private void setPreferredLauncher() {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+ IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
+ filter.addCategory(Intent.CATEGORY_HOME);
+ filter.addCategory(Intent.CATEGORY_DEFAULT);
+ ComponentName componentName = mAdapter.getComponentName(
+ mAvailableLaunchers.getSelectedItemPosition());
+ mDevicePolicyManager.addPersistentPreferredActivity(
+ DeviceOwnerReceiver.getComponentName(activity), filter, componentName);
+ savePersistentPreferredLauncher(activity, componentName.getPackageName());
+ }
+
+ /**
+ * Clears the launcher currently set as preferred.
+ */
+ private void clearPreferredLauncher() {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+ mDevicePolicyManager.clearPackagePersistentPreferredActivities(
+ DeviceOwnerReceiver.getComponentName(activity),
+ loadPersistentPreferredLauncher(activity));
+ savePersistentPreferredLauncher(activity, null);
+ }
+
+ /**
+ * Shows list of {@link ResolveInfo} in a {@link Spinner}.
+ */
+ private static class LauncherAdapter extends SimpleAdapter {
+
+ private static final String KEY_PACKAGE_NAME = "package_name";
+ private static final String KEY_ACTIVITY_NAME = "activity_name";
+
+ public LauncherAdapter(Context context, List<ResolveInfo> list) {
+ super(context, createData(list), android.R.layout.simple_list_item_1,
+ new String[]{KEY_PACKAGE_NAME},
+ new int[]{android.R.id.text1});
+ }
+
+ private static List<HashMap<String, String>> createData(List<ResolveInfo> list) {
+ List<HashMap<String, String>> data = new ArrayList<>();
+ for (ResolveInfo info : list) {
+ HashMap<String, String> map = new HashMap<>();
+ map.put(KEY_PACKAGE_NAME, info.activityInfo.packageName);
+ map.put(KEY_ACTIVITY_NAME, info.activityInfo.name);
+ data.add(map);
+ }
+ return data;
+ }
+
+ public ComponentName getComponentName(int position) {
+ @SuppressWarnings("unchecked")
+ HashMap<String, String> map = (HashMap<String, String>) getItem(position);
+ return new ComponentName(map.get(KEY_PACKAGE_NAME), map.get(KEY_ACTIVITY_NAME));
+ }
+
+ }
+
+}
diff --git a/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerReceiver.java b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerReceiver.java
new file mode 100644
index 00000000..f5969fc2
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/DeviceOwnerReceiver.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 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.android.deviceowner;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Handles events related to device owner.
+ */
+public class DeviceOwnerReceiver extends DeviceAdminReceiver {
+
+ /**
+ * Called on the new profile when device owner provisioning has completed. Device owner
+ * provisioning is the process of setting up the device so that its main profile is managed by
+ * the mobile device management (MDM) application set up as the device owner.
+ */
+ @Override
+ public void onProfileProvisioningComplete(Context context, Intent intent) {
+ // Enable the profile
+ DevicePolicyManager manager =
+ (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ ComponentName componentName = getComponentName(context);
+ manager.setProfileName(componentName, context.getString(R.string.profile_name));
+ // Open the main screen
+ Intent launch = new Intent(context, MainActivity.class);
+ launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(launch);
+ }
+
+ /**
+ * @return A newly instantiated {@link android.content.ComponentName} for this
+ * DeviceAdminReceiver.
+ */
+ public static ComponentName getComponentName(Context context) {
+ return new ComponentName(context.getApplicationContext(), DeviceOwnerReceiver.class);
+ }
+
+}
diff --git a/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/InstructionFragment.java b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/InstructionFragment.java
new file mode 100644
index 00000000..2a889c39
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/InstructionFragment.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 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.android.deviceowner;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Shows instruction about this device owner.
+ */
+public class InstructionFragment extends Fragment {
+
+ /**
+ * @return A newly instantiated {@link InstructionFragment}.
+ */
+ public static InstructionFragment newInstance() {
+ return new InstructionFragment();
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_instruction, container, false);
+ }
+
+}
diff --git a/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/MainActivity.java b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/MainActivity.java
new file mode 100644
index 00000000..5a331abc
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/java/com/example/android/deviceowner/MainActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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.android.deviceowner;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+public class MainActivity extends Activity {
+
+ private static final String TAG = "MainActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main_real);
+ if (savedInstanceState == null) {
+ DevicePolicyManager manager =
+ (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (manager.isDeviceOwnerApp(getApplicationContext().getPackageName())) {
+ // This app is set up as the device owner. Show the main features.
+ Log.d(TAG, "The app is the device owner.");
+ showFragment(DeviceOwnerFragment.newInstance());
+ } else {
+ // This app is not set up as the device owner. Show instructions.
+ Log.d(TAG, "The app is not the device owner.");
+ showFragment(InstructionFragment.newInstance());
+ }
+ }
+ }
+
+ private void showFragment(Fragment fragment) {
+ getFragmentManager().beginTransaction()
+ .replace(R.id.container, fragment)
+ .commit();
+ }
+
+}
diff --git a/admin/DeviceOwner/Application/src/main/res/drawable-hdpi/ic_launcher.png b/admin/DeviceOwner/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000..282e5400
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/admin/DeviceOwner/Application/src/main/res/drawable-mdpi/ic_launcher.png b/admin/DeviceOwner/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..4ecfdf61
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/admin/DeviceOwner/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/admin/DeviceOwner/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..dfb6cabe
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/DeviceOwner/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/admin/DeviceOwner/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..650302ed
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/DeviceOwner/Application/src/main/res/layout/activity_main_real.xml b/admin/DeviceOwner/Application/src/main/res/layout/activity_main_real.xml
new file mode 100644
index 00000000..384e9f98
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/layout/activity_main_real.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2015 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.
+-->
+<FrameLayout
+ android:id="@+id/container"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.android.deviceowner.MainActivity"
+ tools:ignore="MergeRootFrame"/>
diff --git a/admin/DeviceOwner/Application/src/main/res/layout/fragment_device_owner.xml b/admin/DeviceOwner/Application/src/main/res/layout/fragment_device_owner.xml
new file mode 100644
index 00000000..aeae2194
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/layout/fragment_device_owner.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2015 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.
+-->
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.android.deviceowner.DeviceOwnerFragment">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ android:text="@string/label_global_settings"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+ <Switch
+ android:id="@+id/switch_auto_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ android:paddingEnd="@dimen/margin_medium"
+ android:paddingStart="@dimen/margin_medium"
+ android:text="@string/label_auto_time"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <Switch
+ android:id="@+id/switch_auto_time_zone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ android:paddingEnd="@dimen/margin_medium"
+ android:paddingStart="@dimen/margin_medium"
+ android:text="@string/label_auto_time_zone"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/margin_medium"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ android:text="@string/label_launcher"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+ <Spinner
+ android:id="@+id/available_launchers"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/margin_medium"
+ android:layout_marginTop="@dimen/margin_medium"/>
+
+ <Button
+ android:id="@+id/set_preferred_launcher"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/margin_medium"
+ android:text="@string/set_as_preferred"/>
+
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/admin/DeviceOwner/Application/src/main/res/layout/fragment_instruction.xml b/admin/DeviceOwner/Application/src/main/res/layout/fragment_instruction.xml
new file mode 100644
index 00000000..9d09e393
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/layout/fragment_instruction.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2015 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context="com.example.android.deviceowner.InstructionFragment">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ android:text="@string/set_up_instruction"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+</LinearLayout>
diff --git a/admin/DeviceOwner/Application/src/main/res/values/strings.xml b/admin/DeviceOwner/Application/src/main/res/values/strings.xml
new file mode 100644
index 00000000..af7d038b
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/values/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2015 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="set_up_instruction">
+ The app is not set up as the device owner of this device. Use NfcProvisioning sample to set
+ up this app as the device owner of this device (This requires factory resetting the device).
+ </string>
+
+ <string name="profile_name">Sample Device Owner</string>
+
+ <string name="label_global_settings">Global settings</string>
+ <string name="label_auto_time">Automatic date &amp; time</string>
+ <string name="label_auto_time_zone">Automatic time zone</string>
+
+ <string name="label_launcher">Home Launcher</string>
+ <string name="set_as_preferred">Set as preferred</string>
+ <string name="clear_preferred">Clear preferred</string>
+
+</resources>
diff --git a/admin/DeviceOwner/Application/src/main/res/xml/device_owner_receiver.xml b/admin/DeviceOwner/Application/src/main/res/xml/device_owner_receiver.xml
new file mode 100644
index 00000000..20109f06
--- /dev/null
+++ b/admin/DeviceOwner/Application/src/main/res/xml/device_owner_receiver.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2015 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.
+-->
+<device-admin>
+ <uses-policies>
+ <limit-password/>
+ <watch-login/>
+ <reset-password/>
+ <force-lock/>
+ <wipe-data/>
+ <expire-password/>
+ <encrypted-storage/>
+ <disable-camera/>
+ </uses-policies>
+</device-admin>
diff --git a/admin/DeviceOwner/build.gradle b/admin/DeviceOwner/build.gradle
new file mode 100644
index 00000000..2b8d1ef1
--- /dev/null
+++ b/admin/DeviceOwner/build.gradle
@@ -0,0 +1,11 @@
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/admin/DeviceOwner/buildSrc/build.gradle b/admin/DeviceOwner/buildSrc/build.gradle
new file mode 100644
index 00000000..8c294c23
--- /dev/null
+++ b/admin/DeviceOwner/buildSrc/build.gradle
@@ -0,0 +1,15 @@
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.jar b/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..8c0fb64a
--- /dev/null
+++ b/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties b/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..0973c316
--- /dev/null
+++ b/admin/DeviceOwner/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jan 20 16:50:15 JST 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/admin/DeviceOwner/gradlew b/admin/DeviceOwner/gradlew
new file mode 100755
index 00000000..91a7e269
--- /dev/null
+++ b/admin/DeviceOwner/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/admin/DeviceOwner/gradlew.bat b/admin/DeviceOwner/gradlew.bat
new file mode 100644
index 00000000..aec99730
--- /dev/null
+++ b/admin/DeviceOwner/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/admin/DeviceOwner/screenshots/1-main.png b/admin/DeviceOwner/screenshots/1-main.png
new file mode 100644
index 00000000..db827d1e
--- /dev/null
+++ b/admin/DeviceOwner/screenshots/1-main.png
Binary files differ
diff --git a/admin/DeviceOwner/screenshots/icon-web.png b/admin/DeviceOwner/screenshots/icon-web.png
new file mode 100755
index 00000000..ac670daf
--- /dev/null
+++ b/admin/DeviceOwner/screenshots/icon-web.png
Binary files differ
diff --git a/admin/DeviceOwner/settings.gradle b/admin/DeviceOwner/settings.gradle
new file mode 100644
index 00000000..9464a359
--- /dev/null
+++ b/admin/DeviceOwner/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
diff --git a/admin/DeviceOwner/template-params.xml b/admin/DeviceOwner/template-params.xml
new file mode 100644
index 00000000..27930d08
--- /dev/null
+++ b/admin/DeviceOwner/template-params.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2015 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.
+-->
+<sample>
+ <name>DeviceOwner</name>
+ <group>Admin</group>
+ <package>com.example.android.deviceowner</package>
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+<![CDATA[
+This app demonstrates how to use device owner features. Use the NfcProvisioning sample to set up
+this app as the device owner of your test device (This requires wiping out the device and resseting
+it as an unprovisioned device). As a device owner, this app can configure global settings, and
+enforce use of a specific launcher.
+]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+ <metadata>
+ <status>PUBLISHED</status>
+ <categories>Device Admin</categories>
+ <technologies>Android</technologies>
+ <languages>Java</languages>
+ <solutions>Mobile</solutions>
+ <level>ADVANCED</level>
+ <icon>screenshots/icon-web.png</icon>
+ <screenshots>
+ <img>screenshots/1-main.png</img>
+ </screenshots>
+ <api_refs>
+ <android>android.app.admin.DevicePolicyManager</android>
+ <android>android.provider.Settings</android>
+ </api_refs>
+
+ <description>
+<![CDATA[
+This sample demonstrates how to use some device owner features. As a device owner, you can configure
+global settings such as automatic time and timezone. You can mandate a specific launcher by
+preferred intent handler.
+]]>
+ </description>
+
+ <intro>
+<![CDATA[
+In order to set global settings, use [DevicePolicyManager#setGlobalSetting][1] and specify one of
+the [Settings.Global][2] keys available. Note that you need to specify its value as a String. As
+most of the keys accept boolean values, you will mostly use "1" for true and "0" for false.
+
+You can mandate a specific launcher by adding a persistent preferred activity for an IntentFilter
+with Intent.CATEGORY_HOME category. Call [DevicePolicyManager#addPersistentPreferredActivity][3] to
+register the activity. You can clear the registration with
+[clearPackagePersistentPreferredActivities][4].
+
+As a device owner, you can also use the features available for managed profile owner. See
+[BasicManagedProfile][5].
+
+[1]: http://developer.android.com/reference/android/app/admin/DevicePolicyManager.html#setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String)
+[2]: http://developer.android.com/reference/android/provider/Settings.Global.html
+[3]: http://developer.android.com/reference/android/app/admin/DevicePolicyManager.html#addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName)
+[4]: http://developer.android.com/reference/android/app/admin/DevicePolicyManager.html#clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String)
+[5]: https://developer.android.com/samples/BasicManagedProfile/index.html
+]]>
+ </intro>
+ </metadata>
+</sample>