Restrictions Manager
Mechanism to register a provider for requesting an administrator to respond to permission requests. Request format and response format constants. Description of manifest template for static restrictions. Int type introduced in RestrictionEntry. Needs more javadoc and better description of manifest templates, including specifying the XML attributes. Change-Id: I5a654d364e98379fc60f73db2e06bf9a8310263d
This commit is contained in:
@ -118,6 +118,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/content/IIntentReceiver.aidl \
|
||||
core/java/android/content/IIntentSender.aidl \
|
||||
core/java/android/content/IOnPrimaryClipChangedListener.aidl \
|
||||
core/java/android/content/IRestrictionsManager.aidl \
|
||||
core/java/android/content/ISyncAdapter.aidl \
|
||||
core/java/android/content/ISyncContext.aidl \
|
||||
core/java/android/content/ISyncServiceAdapter.aidl \
|
||||
|
@ -5229,6 +5229,7 @@ package android.app.admin {
|
||||
method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
|
||||
method public void setPasswordQuality(android.content.ComponentName, int);
|
||||
method public void setProfileEnabled(android.content.ComponentName);
|
||||
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
|
||||
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
|
||||
method public int setStorageEncryption(android.content.ComponentName, boolean);
|
||||
method public void wipeData(int);
|
||||
@ -7024,6 +7025,7 @@ package android.content {
|
||||
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
|
||||
field public static final java.lang.String POWER_SERVICE = "power";
|
||||
field public static final java.lang.String PRINT_SERVICE = "print";
|
||||
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
|
||||
field public static final java.lang.String SEARCH_SERVICE = "search";
|
||||
field public static final java.lang.String SENSOR_SERVICE = "sensor";
|
||||
field public static final java.lang.String STORAGE_SERVICE = "storage";
|
||||
@ -7780,12 +7782,14 @@ package android.content {
|
||||
ctor public RestrictionEntry(java.lang.String, java.lang.String);
|
||||
ctor public RestrictionEntry(java.lang.String, boolean);
|
||||
ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
|
||||
ctor public RestrictionEntry(java.lang.String, int);
|
||||
ctor public RestrictionEntry(android.os.Parcel);
|
||||
method public int describeContents();
|
||||
method public java.lang.String[] getAllSelectedStrings();
|
||||
method public java.lang.String[] getChoiceEntries();
|
||||
method public java.lang.String[] getChoiceValues();
|
||||
method public java.lang.String getDescription();
|
||||
method public int getIntValue();
|
||||
method public java.lang.String getKey();
|
||||
method public boolean getSelectedState();
|
||||
method public java.lang.String getSelectedString();
|
||||
@ -7797,6 +7801,7 @@ package android.content {
|
||||
method public void setChoiceValues(java.lang.String[]);
|
||||
method public void setChoiceValues(android.content.Context, int);
|
||||
method public void setDescription(java.lang.String);
|
||||
method public void setIntValue(int);
|
||||
method public void setSelectedState(boolean);
|
||||
method public void setSelectedString(java.lang.String);
|
||||
method public void setTitle(java.lang.String);
|
||||
@ -7805,10 +7810,36 @@ package android.content {
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public static final int TYPE_BOOLEAN = 1; // 0x1
|
||||
field public static final int TYPE_CHOICE = 2; // 0x2
|
||||
field public static final int TYPE_INTEGER = 5; // 0x5
|
||||
field public static final int TYPE_MULTI_SELECT = 4; // 0x4
|
||||
field public static final int TYPE_NULL = 0; // 0x0
|
||||
}
|
||||
|
||||
public class RestrictionsManager {
|
||||
method public android.os.Bundle getApplicationRestrictions();
|
||||
method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
|
||||
method public boolean hasRestrictionsProvider();
|
||||
method public void notifyPermissionResponse(java.lang.String, android.os.Bundle);
|
||||
method public void requestPermission(java.lang.String, android.os.Bundle);
|
||||
field public static final java.lang.String ACTION_PERMISSION_RESPONSE_RECEIVED = "android.intent.action.PERMISSION_RESPONSE_RECEIVED";
|
||||
field public static final java.lang.String ACTION_REQUEST_PERMISSION = "android.intent.action.REQUEST_PERMISSION";
|
||||
field public static final java.lang.String EXTRA_PACKAGE_NAME = "package_name";
|
||||
field public static final java.lang.String EXTRA_REQUEST_BUNDLE = "request_bundle";
|
||||
field public static final java.lang.String EXTRA_RESPONSE_BUNDLE = "response_bundle";
|
||||
field public static final java.lang.String EXTRA_TEMPLATE_ID = "template_id";
|
||||
field public static final java.lang.String REQUEST_KEY_APPROVE_LABEL = "android.req_template.accept";
|
||||
field public static final java.lang.String REQUEST_KEY_DATA = "android.req_template.data";
|
||||
field public static final java.lang.String REQUEST_KEY_DENY_LABEL = "android.req_template.reject";
|
||||
field public static final java.lang.String REQUEST_KEY_DEVICE_NAME = "android.req_template.device";
|
||||
field public static final java.lang.String REQUEST_KEY_ICON = "android.req_template.icon";
|
||||
field public static final java.lang.String REQUEST_KEY_ID = "android.req_template.req_id";
|
||||
field public static final java.lang.String REQUEST_KEY_MESSAGE = "android.req_template.mesg";
|
||||
field public static final java.lang.String REQUEST_KEY_REQUESTOR_NAME = "android.req_template.requestor";
|
||||
field public static final java.lang.String REQUEST_KEY_TITLE = "android.req_template.title";
|
||||
field public static final java.lang.String REQUEST_TEMPLATE_QUESTION = "android.req_template.type.simple";
|
||||
field public static final java.lang.String RESPONSE_KEY_BOOLEAN = "android.req_template.response";
|
||||
}
|
||||
|
||||
public class SearchRecentSuggestionsProvider extends android.content.ContentProvider {
|
||||
ctor public SearchRecentSuggestionsProvider();
|
||||
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
|
||||
|
@ -35,7 +35,9 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.IIntentReceiver;
|
||||
import android.content.IntentSender;
|
||||
import android.content.IRestrictionsManager;
|
||||
import android.content.ReceiverCallNotAllowedException;
|
||||
import android.content.RestrictionsManager;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@ -662,6 +664,13 @@ class ContextImpl extends Context {
|
||||
}
|
||||
});
|
||||
|
||||
registerService(RESTRICTIONS_SERVICE, new ServiceFetcher() {
|
||||
public Object createService(ContextImpl ctx) {
|
||||
IBinder b = ServiceManager.getService(RESTRICTIONS_SERVICE);
|
||||
IRestrictionsManager service = IRestrictionsManager.Stub.asInterface(b);
|
||||
return new RestrictionsManager(ctx, service);
|
||||
}
|
||||
});
|
||||
registerService(PRINT_SERVICE, new ServiceFetcher() {
|
||||
public Object createService(ContextImpl ctx) {
|
||||
IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
|
||||
|
@ -25,6 +25,7 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.RestrictionsManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
@ -2320,4 +2321,23 @@ public class DevicePolicyManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Designates a specific broadcast receiver component as the provider for
|
||||
* making permission requests of a local or remote administrator of the user.
|
||||
* <p/>
|
||||
* Only a profile owner can designate the restrictions provider.
|
||||
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
|
||||
* @param receiver The component name of a BroadcastReceiver that handles the
|
||||
* {@link RestrictionsManager#ACTION_REQUEST_PERMISSION} intent. If this param is null,
|
||||
* it removes the restrictions provider previously assigned.
|
||||
*/
|
||||
public void setRestrictionsProvider(ComponentName admin, ComponentName receiver) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.setRestrictionsProvider(admin, receiver);
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Failed to set permission provider on device policy service");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +121,9 @@ interface IDevicePolicyManager {
|
||||
void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings);
|
||||
Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
|
||||
|
||||
void setRestrictionsProvider(in ComponentName who, in ComponentName provider);
|
||||
ComponentName getRestrictionsProvider(int userHandle);
|
||||
|
||||
void setUserRestriction(in ComponentName who, in String key, boolean enable);
|
||||
void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
|
||||
void clearCrossProfileIntentFilters(in ComponentName admin);
|
||||
|
@ -2693,6 +2693,15 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String LAUNCHER_APPS_SERVICE = "launcherapps";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.content.RestrictionsManager} for retrieving application restrictions
|
||||
* and requesting permissions for restricted operations.
|
||||
* @see #getSystemService
|
||||
* @see android.content.RestrictionsManager
|
||||
*/
|
||||
public static final String RESTRICTIONS_SERVICE = "restrictions";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.app.AppOpsManager} for tracking application operations
|
||||
|
30
core/java/android/content/IRestrictionsManager.aidl
Normal file
30
core/java/android/content/IRestrictionsManager.aidl
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 android.content;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* Interface used by the RestrictionsManager
|
||||
* @hide
|
||||
*/
|
||||
interface IRestrictionsManager {
|
||||
Bundle getApplicationRestrictions(in String packageName);
|
||||
boolean hasRestrictionsProvider();
|
||||
void requestPermission(in String packageName, in String requestTemplate, in Bundle requestData);
|
||||
void notifyPermissionResponse(in String packageName, in Bundle response);
|
||||
}
|
@ -73,32 +73,38 @@ public class RestrictionEntry implements Parcelable {
|
||||
*/
|
||||
public static final int TYPE_MULTI_SELECT = 4;
|
||||
|
||||
/**
|
||||
* A type of restriction. Use this for storing an integer value. The range of values
|
||||
* is from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}.
|
||||
*/
|
||||
public static final int TYPE_INTEGER = 5;
|
||||
|
||||
/** The type of restriction. */
|
||||
private int type;
|
||||
private int mType;
|
||||
|
||||
/** The unique key that identifies the restriction. */
|
||||
private String key;
|
||||
private String mKey;
|
||||
|
||||
/** The user-visible title of the restriction. */
|
||||
private String title;
|
||||
private String mTitle;
|
||||
|
||||
/** The user-visible secondary description of the restriction. */
|
||||
private String description;
|
||||
private String mDescription;
|
||||
|
||||
/** The user-visible set of choices used for single-select and multi-select lists. */
|
||||
private String [] choices;
|
||||
private String [] mChoiceEntries;
|
||||
|
||||
/** The values corresponding to the user-visible choices. The value(s) of this entry will
|
||||
* one or more of these, returned by {@link #getAllSelectedStrings()} and
|
||||
* {@link #getSelectedString()}.
|
||||
*/
|
||||
private String [] values;
|
||||
private String [] mChoiceValues;
|
||||
|
||||
/* The chosen value, whose content depends on the type of the restriction. */
|
||||
private String currentValue;
|
||||
private String mCurrentValue;
|
||||
|
||||
/* List of selected choices in the multi-select case. */
|
||||
private String[] currentValues;
|
||||
private String[] mCurrentValues;
|
||||
|
||||
/**
|
||||
* Constructor for {@link #TYPE_CHOICE} type.
|
||||
@ -106,9 +112,9 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param selectedString the current value
|
||||
*/
|
||||
public RestrictionEntry(String key, String selectedString) {
|
||||
this.key = key;
|
||||
this.type = TYPE_CHOICE;
|
||||
this.currentValue = selectedString;
|
||||
this.mKey = key;
|
||||
this.mType = TYPE_CHOICE;
|
||||
this.mCurrentValue = selectedString;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,8 +123,8 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param selectedState whether this restriction is selected or not
|
||||
*/
|
||||
public RestrictionEntry(String key, boolean selectedState) {
|
||||
this.key = key;
|
||||
this.type = TYPE_BOOLEAN;
|
||||
this.mKey = key;
|
||||
this.mType = TYPE_BOOLEAN;
|
||||
setSelectedState(selectedState);
|
||||
}
|
||||
|
||||
@ -128,9 +134,20 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param selectedStrings the list of values that are currently selected
|
||||
*/
|
||||
public RestrictionEntry(String key, String[] selectedStrings) {
|
||||
this.key = key;
|
||||
this.type = TYPE_MULTI_SELECT;
|
||||
this.currentValues = selectedStrings;
|
||||
this.mKey = key;
|
||||
this.mType = TYPE_MULTI_SELECT;
|
||||
this.mCurrentValues = selectedStrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for {@link #TYPE_INTEGER} type.
|
||||
* @param key the unique key for this restriction
|
||||
* @param selectedInt the integer value of the restriction
|
||||
*/
|
||||
public RestrictionEntry(String key, int selectedInt) {
|
||||
mKey = key;
|
||||
mType = TYPE_INTEGER;
|
||||
setIntValue(selectedInt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,7 +155,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param type the type for this restriction.
|
||||
*/
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
this.mType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,7 +163,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @return the type for this restriction
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,7 +172,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* single string values.
|
||||
*/
|
||||
public String getSelectedString() {
|
||||
return currentValue;
|
||||
return mCurrentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,7 +181,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* null otherwise.
|
||||
*/
|
||||
public String[] getAllSelectedStrings() {
|
||||
return currentValues;
|
||||
return mCurrentValues;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,7 +189,23 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @return the current selected state of the entry.
|
||||
*/
|
||||
public boolean getSelectedState() {
|
||||
return Boolean.parseBoolean(currentValue);
|
||||
return Boolean.parseBoolean(mCurrentValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the entry as an integer when the type is {@link #TYPE_INTEGER}.
|
||||
* @return the integer value of the entry.
|
||||
*/
|
||||
public int getIntValue() {
|
||||
return Integer.parseInt(mCurrentValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the integer value of the entry when the type is {@link #TYPE_INTEGER}.
|
||||
* @param value the integer value to set.
|
||||
*/
|
||||
public void setIntValue(int value) {
|
||||
mCurrentValue = Integer.toString(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,7 +214,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param selectedString the string value to select.
|
||||
*/
|
||||
public void setSelectedString(String selectedString) {
|
||||
currentValue = selectedString;
|
||||
mCurrentValue = selectedString;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -190,7 +223,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param state the current selected state
|
||||
*/
|
||||
public void setSelectedState(boolean state) {
|
||||
currentValue = Boolean.toString(state);
|
||||
mCurrentValue = Boolean.toString(state);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,7 +232,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param allSelectedStrings the current list of selected values.
|
||||
*/
|
||||
public void setAllSelectedStrings(String[] allSelectedStrings) {
|
||||
currentValues = allSelectedStrings;
|
||||
mCurrentValues = allSelectedStrings;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,7 +249,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @see #getAllSelectedStrings()
|
||||
*/
|
||||
public void setChoiceValues(String[] choiceValues) {
|
||||
values = choiceValues;
|
||||
mChoiceValues = choiceValues;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -227,7 +260,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @see #setChoiceValues(String[])
|
||||
*/
|
||||
public void setChoiceValues(Context context, int stringArrayResId) {
|
||||
values = context.getResources().getStringArray(stringArrayResId);
|
||||
mChoiceValues = context.getResources().getStringArray(stringArrayResId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,7 +268,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @return the list of possible values.
|
||||
*/
|
||||
public String[] getChoiceValues() {
|
||||
return values;
|
||||
return mChoiceValues;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,7 +281,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @see #setChoiceValues(String[])
|
||||
*/
|
||||
public void setChoiceEntries(String[] choiceEntries) {
|
||||
choices = choiceEntries;
|
||||
mChoiceEntries = choiceEntries;
|
||||
}
|
||||
|
||||
/** Sets a list of strings that will be presented as choices to the user. This is similar to
|
||||
@ -257,7 +290,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param stringArrayResId the resource id of a string array containing the possible entries.
|
||||
*/
|
||||
public void setChoiceEntries(Context context, int stringArrayResId) {
|
||||
choices = context.getResources().getStringArray(stringArrayResId);
|
||||
mChoiceEntries = context.getResources().getStringArray(stringArrayResId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,7 +298,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @return the list of choices presented to the user.
|
||||
*/
|
||||
public String[] getChoiceEntries() {
|
||||
return choices;
|
||||
return mChoiceEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -273,7 +306,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @return the user-visible description, null if none was set earlier.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,7 +316,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param description the user-visible description string.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
this.mDescription = description;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -291,7 +324,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @return the key for the restriction.
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
return mKey;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -299,7 +332,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @return the user-visible title for the entry, null if none was set earlier.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -307,7 +340,7 @@ public class RestrictionEntry implements Parcelable {
|
||||
* @param title the user-visible title for the entry.
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
this.mTitle = title;
|
||||
}
|
||||
|
||||
private boolean equalArrays(String[] one, String[] other) {
|
||||
@ -324,23 +357,23 @@ public class RestrictionEntry implements Parcelable {
|
||||
if (!(o instanceof RestrictionEntry)) return false;
|
||||
final RestrictionEntry other = (RestrictionEntry) o;
|
||||
// Make sure that either currentValue matches or currentValues matches.
|
||||
return type == other.type && key.equals(other.key)
|
||||
return mType == other.mType && mKey.equals(other.mKey)
|
||||
&&
|
||||
((currentValues == null && other.currentValues == null
|
||||
&& currentValue != null && currentValue.equals(other.currentValue))
|
||||
((mCurrentValues == null && other.mCurrentValues == null
|
||||
&& mCurrentValue != null && mCurrentValue.equals(other.mCurrentValue))
|
||||
||
|
||||
(currentValue == null && other.currentValue == null
|
||||
&& currentValues != null && equalArrays(currentValues, other.currentValues)));
|
||||
(mCurrentValue == null && other.mCurrentValue == null
|
||||
&& mCurrentValues != null && equalArrays(mCurrentValues, other.mCurrentValues)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + key.hashCode();
|
||||
if (currentValue != null) {
|
||||
result = 31 * result + currentValue.hashCode();
|
||||
} else if (currentValues != null) {
|
||||
for (String value : currentValues) {
|
||||
result = 31 * result + mKey.hashCode();
|
||||
if (mCurrentValue != null) {
|
||||
result = 31 * result + mCurrentValue.hashCode();
|
||||
} else if (mCurrentValues != null) {
|
||||
for (String value : mCurrentValues) {
|
||||
if (value != null) {
|
||||
result = 31 * result + value.hashCode();
|
||||
}
|
||||
@ -359,14 +392,14 @@ public class RestrictionEntry implements Parcelable {
|
||||
}
|
||||
|
||||
public RestrictionEntry(Parcel in) {
|
||||
type = in.readInt();
|
||||
key = in.readString();
|
||||
title = in.readString();
|
||||
description = in.readString();
|
||||
choices = readArray(in);
|
||||
values = readArray(in);
|
||||
currentValue = in.readString();
|
||||
currentValues = readArray(in);
|
||||
mType = in.readInt();
|
||||
mKey = in.readString();
|
||||
mTitle = in.readString();
|
||||
mDescription = in.readString();
|
||||
mChoiceEntries = readArray(in);
|
||||
mChoiceValues = readArray(in);
|
||||
mCurrentValue = in.readString();
|
||||
mCurrentValues = readArray(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -387,14 +420,14 @@ public class RestrictionEntry implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(type);
|
||||
dest.writeString(key);
|
||||
dest.writeString(title);
|
||||
dest.writeString(description);
|
||||
writeArray(dest, choices);
|
||||
writeArray(dest, values);
|
||||
dest.writeString(currentValue);
|
||||
writeArray(dest, currentValues);
|
||||
dest.writeInt(mType);
|
||||
dest.writeString(mKey);
|
||||
dest.writeString(mTitle);
|
||||
dest.writeString(mDescription);
|
||||
writeArray(dest, mChoiceEntries);
|
||||
writeArray(dest, mChoiceValues);
|
||||
dest.writeString(mCurrentValue);
|
||||
writeArray(dest, mCurrentValues);
|
||||
}
|
||||
|
||||
public static final Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() {
|
||||
@ -409,6 +442,6 @@ public class RestrictionEntry implements Parcelable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestrictionsEntry {type=" + type + ", key=" + key + ", value=" + currentValue + "}";
|
||||
return "RestrictionsEntry {type=" + mType + ", key=" + mKey + ", value=" + mCurrentValue + "}";
|
||||
}
|
||||
}
|
||||
|
344
core/java/android/content/RestrictionsManager.java
Normal file
344
core/java/android/content/RestrictionsManager.java
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* 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 android.content;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides a mechanism for apps to query restrictions imposed by an entity that
|
||||
* manages the user. Apps can also send permission requests to a local or remote
|
||||
* device administrator to override default app-specific restrictions or any other
|
||||
* operation that needs explicit authorization from the administrator.
|
||||
* <p>
|
||||
* Apps can expose a set of restrictions via a runtime receiver mechanism or via
|
||||
* static meta data in the manifest.
|
||||
* <p>
|
||||
* If the user has an active restrictions provider, dynamic requests can be made in
|
||||
* addition to the statically imposed restrictions. Dynamic requests are app-specific
|
||||
* and can be expressed via a predefined set of templates.
|
||||
* <p>
|
||||
* The RestrictionsManager forwards the dynamic requests to the active
|
||||
* restrictions provider. The restrictions provider can respond back to requests by calling
|
||||
* {@link #notifyPermissionResponse(String, Bundle)}, when
|
||||
* a response is received from the administrator of the device or user
|
||||
* The response is relayed back to the application via a protected broadcast,
|
||||
* {@link #ACTION_PERMISSION_RESPONSE_RECEIVED}.
|
||||
* <p>
|
||||
* Static restrictions are specified by an XML file referenced by a meta-data attribute
|
||||
* in the manifest. This enables applications as well as any web administration consoles
|
||||
* to be able to read the template from the apk.
|
||||
* <p>
|
||||
* The syntax of the XML format is as follows:
|
||||
* <pre>
|
||||
* <restrictions>
|
||||
* <restriction
|
||||
* android:key="<key>"
|
||||
* android:restrictionType="boolean|string|integer|multi-select|null"
|
||||
* ... />
|
||||
* <restriction ... />
|
||||
* </restrictions>
|
||||
* </pre>
|
||||
* <p>
|
||||
* The attributes for each restriction depend on the restriction type.
|
||||
*
|
||||
* @see RestrictionEntry
|
||||
*/
|
||||
public class RestrictionsManager {
|
||||
|
||||
/**
|
||||
* Broadcast intent delivered when a response is received for a permission
|
||||
* request. The response is not available for later query, so the receiver
|
||||
* must persist and/or immediately act upon the response. The application
|
||||
* should not interrupt the user by coming to the foreground if it isn't
|
||||
* currently in the foreground. It can post a notification instead, informing
|
||||
* the user of a change in state.
|
||||
* <p>
|
||||
* For instance, if the user requested permission to make an in-app purchase,
|
||||
* the app can post a notification that the request had been granted or denied,
|
||||
* and allow the purchase to go through.
|
||||
* <p>
|
||||
* The broadcast Intent carries the following extra:
|
||||
* {@link #EXTRA_RESPONSE_BUNDLE}.
|
||||
*/
|
||||
public static final String ACTION_PERMISSION_RESPONSE_RECEIVED =
|
||||
"android.intent.action.PERMISSION_RESPONSE_RECEIVED";
|
||||
|
||||
/**
|
||||
* Protected broadcast intent sent to the active restrictions provider. The intent
|
||||
* contains the following extras:<p>
|
||||
* <ul>
|
||||
* <li>{@link #EXTRA_PACKAGE_NAME} : String; the package name of the application requesting
|
||||
* permission.</li>
|
||||
* <li>{@link #EXTRA_TEMPLATE_ID} : String; the template of the request.</li>
|
||||
* <li>{@link #EXTRA_REQUEST_BUNDLE} : Bundle; contains the template-specific keys and values
|
||||
* for the request.
|
||||
* </ul>
|
||||
* @see DevicePolicyManager#setRestrictionsProvider(ComponentName, ComponentName)
|
||||
* @see #requestPermission(String, String, Bundle)
|
||||
*/
|
||||
public static final String ACTION_REQUEST_PERMISSION =
|
||||
"android.intent.action.REQUEST_PERMISSION";
|
||||
|
||||
/**
|
||||
* The package name of the application making the request.
|
||||
*/
|
||||
public static final String EXTRA_PACKAGE_NAME = "package_name";
|
||||
|
||||
/**
|
||||
* The template id that specifies what kind of a request it is and may indicate
|
||||
* how the request is to be presented to the administrator. Must be either one of
|
||||
* the predefined templates or a custom one specified by the application that the
|
||||
* restrictions provider is familiar with.
|
||||
*/
|
||||
public static final String EXTRA_TEMPLATE_ID = "template_id";
|
||||
|
||||
/**
|
||||
* A bundle containing the details about the request. The contents depend on the
|
||||
* template id.
|
||||
* @see #EXTRA_TEMPLATE_ID
|
||||
*/
|
||||
public static final String EXTRA_REQUEST_BUNDLE = "request_bundle";
|
||||
|
||||
/**
|
||||
* Contains a response from the administrator for specific request.
|
||||
* The bundle contains the following information, at least:
|
||||
* <ul>
|
||||
* <li>{@link #REQUEST_KEY_ID}: The request id.</li>
|
||||
* <li>{@link #REQUEST_KEY_DATA}: The request reference data.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* And depending on what the request template was, the bundle will contain the actual
|
||||
* result of the request. For {@link #REQUEST_TEMPLATE_QUESTION}, the result will be in
|
||||
* {@link #RESPONSE_KEY_BOOLEAN}, which is of type boolean; true if the administrator
|
||||
* approved the request, false otherwise.
|
||||
*/
|
||||
public static final String EXTRA_RESPONSE_BUNDLE = "response_bundle";
|
||||
|
||||
|
||||
/**
|
||||
* Request template that presents a simple question, with a possible title and icon.
|
||||
* <p>
|
||||
* Required keys are
|
||||
* {@link #REQUEST_KEY_ID} and {@link #REQUEST_KEY_MESSAGE}.
|
||||
* <p>
|
||||
* Optional keys are
|
||||
* {@link #REQUEST_KEY_DATA}, {@link #REQUEST_KEY_ICON}, {@link #REQUEST_KEY_TITLE},
|
||||
* {@link #REQUEST_KEY_APPROVE_LABEL} and {@link #REQUEST_KEY_DENY_LABEL}.
|
||||
*/
|
||||
public static final String REQUEST_TEMPLATE_QUESTION = "android.req_template.type.simple";
|
||||
|
||||
/**
|
||||
* Key for request ID contained in the request bundle.
|
||||
* <p>
|
||||
* App-generated request id to identify the specific request when receiving
|
||||
* a response. This value is returned in the {@link #EXTRA_RESPONSE_BUNDLE}.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_ID = "android.req_template.req_id";
|
||||
|
||||
/**
|
||||
* Key for request data contained in the request bundle.
|
||||
* <p>
|
||||
* Optional, typically used to identify the specific data that is being referred to,
|
||||
* such as the unique identifier for a movie or book. This is not used for display
|
||||
* purposes and is more like a cookie. This value is returned in the
|
||||
* {@link #EXTRA_RESPONSE_BUNDLE}.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_DATA = "android.req_template.data";
|
||||
|
||||
/**
|
||||
* Key for request title contained in the request bundle.
|
||||
* <p>
|
||||
* Optional, typically used as the title of any notification or dialog presented
|
||||
* to the administrator who approves the request.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_TITLE = "android.req_template.title";
|
||||
|
||||
/**
|
||||
* Key for request message contained in the request bundle.
|
||||
* <p>
|
||||
* Required, shown as the actual message in a notification or dialog presented
|
||||
* to the administrator who approves the request.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_MESSAGE = "android.req_template.mesg";
|
||||
|
||||
/**
|
||||
* Key for request icon contained in the request bundle.
|
||||
* <p>
|
||||
* Optional, shown alongside the request message presented to the administrator
|
||||
* who approves the request.
|
||||
* <p>
|
||||
* Type: Bitmap
|
||||
*/
|
||||
public static final String REQUEST_KEY_ICON = "android.req_template.icon";
|
||||
|
||||
/**
|
||||
* Key for request approval button label contained in the request bundle.
|
||||
* <p>
|
||||
* Optional, may be shown as a label on the positive button in a dialog or
|
||||
* notification presented to the administrator who approves the request.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_APPROVE_LABEL = "android.req_template.accept";
|
||||
|
||||
/**
|
||||
* Key for request rejection button label contained in the request bundle.
|
||||
* <p>
|
||||
* Optional, may be shown as a label on the negative button in a dialog or
|
||||
* notification presented to the administrator who approves the request.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_DENY_LABEL = "android.req_template.reject";
|
||||
|
||||
/**
|
||||
* Key for requestor's name contained in the request bundle. This value is not specified by
|
||||
* the application. It is automatically inserted into the Bundle by the Restrictions Provider
|
||||
* before it is sent to the administrator.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_REQUESTOR_NAME = "android.req_template.requestor";
|
||||
|
||||
/**
|
||||
* Key for requestor's device name contained in the request bundle. This value is not specified
|
||||
* by the application. It is automatically inserted into the Bundle by the Restrictions Provider
|
||||
* before it is sent to the administrator.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String REQUEST_KEY_DEVICE_NAME = "android.req_template.device";
|
||||
|
||||
/**
|
||||
* Key for the response in the response bundle sent to the application, for a permission
|
||||
* request.
|
||||
* <p>
|
||||
* Type: boolean
|
||||
*/
|
||||
public static final String RESPONSE_KEY_BOOLEAN = "android.req_template.response";
|
||||
|
||||
private static final String TAG = "RestrictionsManager";
|
||||
|
||||
private final Context mContext;
|
||||
private final IRestrictionsManager mService;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public RestrictionsManager(Context context, IRestrictionsManager service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any available set of application-specific restrictions applicable
|
||||
* to this application.
|
||||
* @return
|
||||
*/
|
||||
public Bundle getApplicationRestrictions() {
|
||||
try {
|
||||
if (mService != null) {
|
||||
return mService.getApplicationRestrictions(mContext.getPackageName());
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Couldn't reach service");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by an application to check if permission requests can be made. If false,
|
||||
* there is no need to request permission for an operation, unless a static
|
||||
* restriction applies to that operation.
|
||||
* @return
|
||||
*/
|
||||
public boolean hasRestrictionsProvider() {
|
||||
try {
|
||||
if (mService != null) {
|
||||
return mService.hasRestrictionsProvider();
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Couldn't reach service");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by an application to request permission for an operation. The contents of the
|
||||
* request are passed in a Bundle that contains several pieces of data depending on the
|
||||
* chosen request template.
|
||||
*
|
||||
* @param requestTemplate The request template to use. The template could be one of the
|
||||
* predefined templates specified in this class or a custom template that the specific
|
||||
* Restrictions Provider might understand. For custom templates, the template name should be
|
||||
* namespaced to avoid collisions with predefined templates and templates specified by
|
||||
* other Restrictions Provider vendors.
|
||||
* @param requestData A Bundle containing the data corresponding to the specified request
|
||||
* template. The keys for the data in the bundle depend on the kind of template chosen.
|
||||
*/
|
||||
public void requestPermission(String requestTemplate, Bundle requestData) {
|
||||
try {
|
||||
if (mService != null) {
|
||||
mService.requestPermission(mContext.getPackageName(), requestTemplate, requestData);
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Couldn't reach service");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the Restrictions Provider when a response is available to be
|
||||
* delivered to an application.
|
||||
* @param packageName
|
||||
* @param response
|
||||
*/
|
||||
public void notifyPermissionResponse(String packageName, Bundle response) {
|
||||
try {
|
||||
if (mService != null) {
|
||||
mService.notifyPermissionResponse(packageName, response);
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Couldn't reach service");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and return the list of restrictions defined in the manifest for the specified
|
||||
* package, if any.
|
||||
* @param packageName The application for which to fetch the restrictions list.
|
||||
* @return The list of RestrictionEntry objects created from the XML file specified
|
||||
* in the manifest, or null if none was specified.
|
||||
*/
|
||||
public List<RestrictionEntry> getManifestRestrictions(String packageName) {
|
||||
// TODO:
|
||||
return null;
|
||||
}
|
||||
}
|
@ -258,6 +258,12 @@
|
||||
<protected-broadcast
|
||||
android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
|
||||
|
||||
<!-- Defined in RestrictionsManager -->
|
||||
<protected-broadcast
|
||||
android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
|
||||
<!-- Defined in RestrictionsManager -->
|
||||
<protected-broadcast android:name="android.intent.action.REQUEST_PERMISSION" />
|
||||
|
||||
<!-- ====================================== -->
|
||||
<!-- Permissions for things that cost money -->
|
||||
<!-- ====================================== -->
|
||||
|
@ -25,6 +25,7 @@ services := \
|
||||
backup \
|
||||
devicepolicy \
|
||||
print \
|
||||
restrictions \
|
||||
usb \
|
||||
voiceinteraction
|
||||
|
||||
|
@ -130,6 +130,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
|
||||
|
||||
final Context mContext;
|
||||
final UserManager mUserManager;
|
||||
final PowerManager.WakeLock mWakeLock;
|
||||
@ -190,6 +192,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
// This is the list of component allowed to start lock task mode.
|
||||
final List<ComponentName> mLockTaskComponents = new ArrayList<ComponentName>();
|
||||
|
||||
ComponentName mRestrictionsProvider;
|
||||
|
||||
public DevicePolicyData(int userHandle) {
|
||||
mUserHandle = userHandle;
|
||||
}
|
||||
@ -944,6 +948,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
out.startDocument(null, true);
|
||||
|
||||
out.startTag(null, "policies");
|
||||
if (policy.mRestrictionsProvider != null) {
|
||||
out.attribute(null, ATTR_PERMISSION_PROVIDER,
|
||||
policy.mRestrictionsProvider.flattenToString());
|
||||
}
|
||||
|
||||
final int N = policy.mAdminList.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
@ -1039,6 +1047,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
throw new XmlPullParserException(
|
||||
"Settings do not start with policies tag: found " + tag);
|
||||
}
|
||||
|
||||
// Extract the permission provider component name if available
|
||||
String permissionProvider = parser.getAttributeValue(null, ATTR_PERMISSION_PROVIDER);
|
||||
if (permissionProvider != null) {
|
||||
policy.mRestrictionsProvider = ComponentName.unflattenFromString(permissionProvider);
|
||||
}
|
||||
|
||||
type = parser.next();
|
||||
int outerDepth = parser.getDepth();
|
||||
policy.mLockTaskComponents.clear();
|
||||
@ -3303,6 +3318,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) {
|
||||
synchronized (this) {
|
||||
if (who == null) {
|
||||
throw new NullPointerException("ComponentName is null");
|
||||
}
|
||||
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
|
||||
|
||||
int userHandle = UserHandle.getCallingUserId();
|
||||
DevicePolicyData userData = getUserData(userHandle);
|
||||
userData.mRestrictionsProvider = permissionProvider;
|
||||
saveSettingsLocked(userHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentName getRestrictionsProvider(int userHandle) {
|
||||
synchronized (this) {
|
||||
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
|
||||
throw new SecurityException("Only the system can query the permission provider");
|
||||
}
|
||||
DevicePolicyData userData = getUserData(userHandle);
|
||||
return userData != null ? userData.mRestrictionsProvider : null;
|
||||
}
|
||||
}
|
||||
|
||||
public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
|
||||
int callingUserId = UserHandle.getCallingUserId();
|
||||
synchronized (this) {
|
||||
|
@ -80,6 +80,7 @@ import com.android.server.pm.PackageManagerService;
|
||||
import com.android.server.pm.UserManagerService;
|
||||
import com.android.server.power.PowerManagerService;
|
||||
import com.android.server.power.ShutdownThread;
|
||||
import com.android.server.restrictions.RestrictionsManagerService;
|
||||
import com.android.server.search.SearchManagerService;
|
||||
import com.android.server.statusbar.StatusBarManagerService;
|
||||
import com.android.server.storage.DeviceStorageMonitorService;
|
||||
@ -940,6 +941,12 @@ public final class SystemServer {
|
||||
reportWtf("starting Print Service", e);
|
||||
}
|
||||
|
||||
try {
|
||||
mSystemServiceManager.startService(RestrictionsManagerService.class);
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting RestrictionsManagerService", e);
|
||||
}
|
||||
|
||||
try {
|
||||
mSystemServiceManager.startService(MediaSessionService.class);
|
||||
} catch (Throwable e) {
|
||||
|
10
services/restrictions/Android.mk
Normal file
10
services/restrictions/Android.mk
Normal file
@ -0,0 +1,10 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := services.restrictions
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
$(call all-java-files-under,java)
|
||||
|
||||
include $(BUILD_STATIC_JAVA_LIBRARY)
|
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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.restrictions;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.admin.IDevicePolicyManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.IRestrictionsManager;
|
||||
import android.content.RestrictionsManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IUserManager;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
/**
|
||||
* SystemService wrapper for the RestrictionsManager implementation. Publishes the
|
||||
* Context.RESTRICTIONS_SERVICE.
|
||||
*/
|
||||
|
||||
public final class RestrictionsManagerService extends SystemService {
|
||||
private final RestrictionsManagerImpl mRestrictionsManagerImpl;
|
||||
|
||||
public RestrictionsManagerService(Context context) {
|
||||
super(context);
|
||||
mRestrictionsManagerImpl = new RestrictionsManagerImpl(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(Context.RESTRICTIONS_SERVICE, mRestrictionsManagerImpl);
|
||||
}
|
||||
|
||||
class RestrictionsManagerImpl extends IRestrictionsManager.Stub {
|
||||
private final Context mContext;
|
||||
private final IUserManager mUm;
|
||||
private final IDevicePolicyManager mDpm;
|
||||
|
||||
public RestrictionsManagerImpl(Context context) {
|
||||
mContext = context;
|
||||
mUm = (IUserManager) getBinderService(Context.USER_SERVICE);
|
||||
mDpm = (IDevicePolicyManager) getBinderService(Context.DEVICE_POLICY_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle getApplicationRestrictions(String packageName) throws RemoteException {
|
||||
return mUm.getApplicationRestrictions(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRestrictionsProvider() throws RemoteException {
|
||||
int userHandle = UserHandle.getCallingUserId();
|
||||
if (mDpm != null) {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mDpm.getRestrictionsProvider(userHandle) != null;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestPermission(String packageName, String requestTemplate,
|
||||
Bundle requestData) throws RemoteException {
|
||||
int callingUid = Binder.getCallingUid();
|
||||
int userHandle = UserHandle.getUserId(callingUid);
|
||||
if (mDpm != null) {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
ComponentName restrictionsProvider =
|
||||
mDpm.getRestrictionsProvider(userHandle);
|
||||
// Check if there is a restrictions provider
|
||||
if (restrictionsProvider == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot request permission without a restrictions provider registered");
|
||||
}
|
||||
// Check that the packageName matches the caller.
|
||||
enforceCallerMatchesPackage(callingUid, packageName, "Package name does not" +
|
||||
" match caller ");
|
||||
// Prepare and broadcast the intent to the provider
|
||||
Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_PERMISSION);
|
||||
intent.setComponent(restrictionsProvider);
|
||||
intent.putExtra(RestrictionsManager.EXTRA_PACKAGE_NAME, packageName);
|
||||
intent.putExtra(RestrictionsManager.EXTRA_TEMPLATE_ID, requestTemplate);
|
||||
intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, requestData);
|
||||
mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceCallerMatchesPackage(int callingUid, String packageName,
|
||||
String message) {
|
||||
try {
|
||||
String[] pkgs = AppGlobals.getPackageManager().getPackagesForUid(callingUid);
|
||||
if (pkgs != null) {
|
||||
if (!ArrayUtils.contains(pkgs, packageName)) {
|
||||
throw new SecurityException(message + callingUid);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
// Shouldn't happen
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPermissionResponse(String packageName, Bundle response)
|
||||
throws RemoteException {
|
||||
// Check caller
|
||||
int callingUid = Binder.getCallingUid();
|
||||
int userHandle = UserHandle.getUserId(callingUid);
|
||||
if (mDpm != null) {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
ComponentName permProvider = mDpm.getRestrictionsProvider(userHandle);
|
||||
if (permProvider == null) {
|
||||
throw new SecurityException("No restrictions provider registered for user");
|
||||
}
|
||||
enforceCallerMatchesPackage(callingUid, permProvider.getPackageName(),
|
||||
"Restrictions provider does not match caller ");
|
||||
|
||||
// Post the response to target package
|
||||
Intent responseIntent = new Intent(
|
||||
RestrictionsManager.ACTION_PERMISSION_RESPONSE_RECEIVED);
|
||||
responseIntent.setPackage(packageName);
|
||||
responseIntent.putExtra(RestrictionsManager.EXTRA_RESPONSE_BUNDLE, response);
|
||||
mContext.sendBroadcastAsUser(responseIntent, new UserHandle(userHandle));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user