Handle saving and restoring ints in application restrictions
Unit tests for restrictions types and proper escaping.
Change-Id: Iac35521faf5798398a89fecbad82fcdd256a4146
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1bf40e0..7162683 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -107,6 +107,7 @@
private static final String ATTR_TYPE_STRING_ARRAY = "sa";
private static final String ATTR_TYPE_STRING = "s";
private static final String ATTR_TYPE_BOOLEAN = "b";
+ private static final String ATTR_TYPE_INTEGER = "i";
private static final String USER_INFO_DIR = "system" + File.separator + "users";
private static final String USER_LIST_FILENAME = "userlist.xml";
@@ -1532,16 +1533,18 @@
String [] valueStrings = new String[values.size()];
values.toArray(valueStrings);
restrictions.putStringArray(key, valueStrings);
- } else if (ATTR_TYPE_BOOLEAN.equals(valType)) {
- restrictions.putBoolean(key, Boolean.parseBoolean(
- parser.nextText().trim()));
} else {
String value = parser.nextText().trim();
- restrictions.putString(key, value);
+ if (ATTR_TYPE_BOOLEAN.equals(valType)) {
+ restrictions.putBoolean(key, Boolean.parseBoolean(value));
+ } else if (ATTR_TYPE_INTEGER.equals(valType)) {
+ restrictions.putInt(key, Integer.parseInt(value));
+ } else {
+ restrictions.putString(key, value);
+ }
}
}
}
-
} catch (IOException ioe) {
} catch (XmlPullParserException pe) {
} finally {
@@ -1581,6 +1584,9 @@
if (value instanceof Boolean) {
serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
serializer.text(value.toString());
+ } else if (value instanceof Integer) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_INTEGER);
+ serializer.text(value.toString());
} else if (value == null || value instanceof String) {
serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
serializer.text(value != null ? (String) value : "");
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 7848b1d..636dd4d 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -35,7 +35,8 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+
<application>
<uses-library android:name="android.test.runner" />
@@ -53,6 +54,15 @@
</intent-filter>
</service>
+ <receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_sample" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
</application>
<instrumentation
diff --git a/services/tests/servicestests/res/xml/device_admin_sample.xml b/services/tests/servicestests/res/xml/device_admin_sample.xml
new file mode 100644
index 0000000..032debb
--- /dev/null
+++ b/services/tests/servicestests/res/xml/device_admin_sample.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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 xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-policies>
+ <limit-password />
+ <watch-login />
+ <reset-password />
+ <force-lock />
+ <wipe-data />
+ <expire-password />
+ <encrypted-storage />
+ <disable-camera />
+ <disable-keyguard-features />
+ </uses-policies>
+</device-admin>
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
new file mode 100644
index 0000000..8e8e4e6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 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.android.server.devicepolicy;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Tests for application restrictions persisting via profile owner:
+ * make -j FrameworksServicesTests
+ * runtest --path frameworks/base/services/tests/servicestests/ \
+ * src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
+ */
+public class ApplicationRestrictionsTest extends AndroidTestCase {
+
+ static DevicePolicyManager sDpm;
+ static ComponentName sAdminReceiver;
+ private static final String RESTRICTED_APP = "com.example.restrictedApp";
+ static boolean sAddBack = false;
+
+ public static class AdminReceiver extends DeviceAdminReceiver {
+
+ @Override
+ public void onDisabled(Context context, Intent intent) {
+ if (sAddBack) {
+ sDpm.setActiveAdmin(sAdminReceiver, false);
+ sAddBack = false;
+ }
+
+ super.onDisabled(context, intent);
+ }
+ }
+
+ @Override
+ public void setUp() {
+ final Context context = getContext();
+ sAdminReceiver = new ComponentName(mContext.getPackageName(),
+ AdminReceiver.class.getName());
+ sDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ Settings.Secure.putInt(context.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0);
+ sDpm.setProfileOwner(context.getPackageName(), "Test", UserHandle.myUserId());
+ Settings.Secure.putInt(context.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 1);
+ // Remove the admin if already registered. It's async, so add it back
+ // when the admin gets a broadcast. Otherwise add it back right away.
+ if (sDpm.isAdminActive(sAdminReceiver)) {
+ sAddBack = true;
+ sDpm.removeActiveAdmin(sAdminReceiver);
+ } else {
+ sDpm.setActiveAdmin(sAdminReceiver, false);
+ }
+ }
+
+ @Override
+ public void tearDown() {
+ Settings.Secure.putInt(getContext().getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0);
+ sDpm.removeActiveAdmin(sAdminReceiver);
+ Settings.Secure.putInt(getContext().getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 1);
+ }
+
+ public void testSettingRestrictions() {
+ Bundle restrictions = new Bundle();
+ restrictions.putString("KEY_STRING", "Foo");
+ assertNotNull(sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP));
+ sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
+ Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
+ assertNotNull(returned);
+ assertEquals(returned.size(), 1);
+ assertEquals(returned.get("KEY_STRING"), "Foo");
+ sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
+ returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
+ assertEquals(returned.size(), 0);
+ }
+
+ public void testRestrictionTypes() {
+ Bundle restrictions = new Bundle();
+ restrictions.putString("KEY_STRING", "Foo");
+ restrictions.putInt("KEY_INT", 7);
+ restrictions.putBoolean("KEY_BOOLEAN", true);
+ restrictions.putBoolean("KEY_BOOLEAN_2", false);
+ restrictions.putString("KEY_STRING_2", "Bar");
+ restrictions.putStringArray("KEY_STR_ARRAY", new String[] { "Foo", "Bar" });
+ sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
+ Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
+ assertTrue(returned.getBoolean("KEY_BOOLEAN"));
+ assertFalse(returned.getBoolean("KEY_BOOLEAN_2"));
+ assertFalse(returned.getBoolean("KEY_BOOLEAN_3"));
+ assertEquals(returned.getInt("KEY_INT"), 7);
+ assertTrue(returned.get("KEY_BOOLEAN") instanceof Boolean);
+ assertTrue(returned.get("KEY_INT") instanceof Integer);
+ assertEquals(returned.get("KEY_STRING"), "Foo");
+ assertEquals(returned.get("KEY_STRING_2"), "Bar");
+ assertTrue(returned.getStringArray("KEY_STR_ARRAY") instanceof String[]);
+ sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
+ }
+
+ public void testTextEscaping() {
+ String fancyText = "<This contains XML/> <JSON> "
+ + "{ \"One\": { \"OneOne\": \"11\", \"OneTwo\": \"12\" }, \"Two\": \"2\" } <JSON/>";
+ Bundle restrictions = new Bundle();
+ restrictions.putString("KEY_FANCY_TEXT", fancyText);
+ sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
+ Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
+ assertEquals(returned.getString("KEY_FANCY_TEXT"), fancyText);
+ }
+}
\ No newline at end of file