am f6feac69: API Review: Improvements to RestrictionsManager API
* commit 'f6feac69abe5427e0ee89f2721a4d825e8a84fb0': API Review: Improvements to RestrictionsManager API
This commit is contained in:
@@ -446,6 +446,7 @@ aidl_files := \
|
||||
frameworks/base/core/java/android/os/DropBoxManager.aidl \
|
||||
frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
|
||||
frameworks/base/core/java/android/os/ParcelUuid.aidl \
|
||||
frameworks/base/core/java/android/os/PersistableBundle.aidl \
|
||||
frameworks/base/core/java/android/print/PrinterInfo.aidl \
|
||||
frameworks/base/core/java/android/print/PageRange.aidl \
|
||||
frameworks/base/core/java/android/print/PrintAttributes.aidl \
|
||||
|
||||
@@ -6660,7 +6660,7 @@ package android.content {
|
||||
public abstract class AbstractRestrictionsProvider extends android.content.BroadcastReceiver {
|
||||
ctor public AbstractRestrictionsProvider();
|
||||
method public void onReceive(android.content.Context, android.content.Intent);
|
||||
method public abstract void requestPermission(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle);
|
||||
method public abstract void requestPermission(android.content.Context, java.lang.String, java.lang.String, java.lang.String, android.os.PersistableBundle);
|
||||
}
|
||||
|
||||
public abstract class AbstractThreadedSyncAdapter {
|
||||
@@ -8050,14 +8050,17 @@ package android.content {
|
||||
|
||||
public class RestrictionsManager {
|
||||
method public android.os.Bundle getApplicationRestrictions();
|
||||
method public android.content.Intent getLocalApprovalIntent();
|
||||
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";
|
||||
method public void notifyPermissionResponse(java.lang.String, android.os.PersistableBundle);
|
||||
method public void requestPermission(java.lang.String, java.lang.String, android.os.PersistableBundle);
|
||||
field public static final java.lang.String ACTION_PERMISSION_RESPONSE_RECEIVED = "android.content.action.PERMISSION_RESPONSE_RECEIVED";
|
||||
field public static final java.lang.String ACTION_REQUEST_LOCAL_APPROVAL = "android.content.action.REQUEST_LOCAL_APPROVAL";
|
||||
field public static final java.lang.String ACTION_REQUEST_PERMISSION = "android.content.action.REQUEST_PERMISSION";
|
||||
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
|
||||
field public static final java.lang.String EXTRA_REQUEST_BUNDLE = "android.content.extra.REQUEST_BUNDLE";
|
||||
field public static final java.lang.String EXTRA_REQUEST_ID = "android.content.extra.REQUEST_ID";
|
||||
field public static final java.lang.String EXTRA_REQUEST_TYPE = "android.content.extra.REQUEST_TYPE";
|
||||
field public static final java.lang.String EXTRA_RESPONSE_BUNDLE = "android.content.extra.RESPONSE_BUNDLE";
|
||||
field public static final java.lang.String META_DATA_APP_RESTRICTIONS = "android.content.APP_RESTRICTIONS";
|
||||
@@ -8070,7 +8073,6 @@ package android.content {
|
||||
field public static final java.lang.String REQUEST_KEY_NEW_REQUEST = "android.request.new_request";
|
||||
field public static final java.lang.String REQUEST_KEY_TITLE = "android.request.title";
|
||||
field public static final java.lang.String REQUEST_TYPE_APPROVAL = "android.request.type.approval";
|
||||
field public static final java.lang.String REQUEST_TYPE_LOCAL_APPROVAL = "android.request.type.local_approval";
|
||||
field public static final java.lang.String RESPONSE_KEY_ERROR_CODE = "android.response.errorcode";
|
||||
field public static final java.lang.String RESPONSE_KEY_MESSAGE = "android.response.msg";
|
||||
field public static final java.lang.String RESPONSE_KEY_RESPONSE_TIMESTAMP = "android.response.timestamp";
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
package android.content;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
/**
|
||||
* Abstract implementation of a Restrictions Provider BroadcastReceiver. To implement a
|
||||
@@ -30,7 +30,7 @@ import android.os.IBinder;
|
||||
* The function of a Restrictions Provider is to transport permission requests from apps on this
|
||||
* device to an administrator (most likely on a remote device or computer) and deliver back
|
||||
* responses. The response should be sent back to the app via
|
||||
* {@link RestrictionsManager#notifyPermissionResponse(String, Bundle)}.
|
||||
* {@link RestrictionsManager#notifyPermissionResponse(String, PersistableBundle)}.
|
||||
*
|
||||
* @see RestrictionsManager
|
||||
*/
|
||||
@@ -59,7 +59,7 @@ public abstract class AbstractRestrictionsProvider extends BroadcastReceiver {
|
||||
* @see RestrictionsManager#REQUEST_KEY_ID
|
||||
*/
|
||||
public abstract void requestPermission(Context context,
|
||||
String packageName, String requestType, Bundle request);
|
||||
String packageName, String requestType, String requestId, PersistableBundle request);
|
||||
|
||||
/**
|
||||
* Intercept standard Restrictions Provider broadcasts. Implementations
|
||||
@@ -73,8 +73,10 @@ public abstract class AbstractRestrictionsProvider extends BroadcastReceiver {
|
||||
if (RestrictionsManager.ACTION_REQUEST_PERMISSION.equals(action)) {
|
||||
String packageName = intent.getStringExtra(RestrictionsManager.EXTRA_PACKAGE_NAME);
|
||||
String requestType = intent.getStringExtra(RestrictionsManager.EXTRA_REQUEST_TYPE);
|
||||
Bundle request = intent.getBundleExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE);
|
||||
requestPermission(context, packageName, requestType, request);
|
||||
String requestId = intent.getStringExtra(RestrictionsManager.EXTRA_REQUEST_ID);
|
||||
PersistableBundle request = (PersistableBundle)
|
||||
intent.getParcelableExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE);
|
||||
requestPermission(context, packageName, requestType, requestId, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
/**
|
||||
* Interface used by the RestrictionsManager
|
||||
@@ -25,6 +27,8 @@ import android.os.Bundle;
|
||||
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);
|
||||
void requestPermission(in String packageName, in String requestType, in String requestId,
|
||||
in PersistableBundle requestData);
|
||||
void notifyPermissionResponse(in String packageName, in PersistableBundle response);
|
||||
Intent getLocalApprovalIntent();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -23,6 +24,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
@@ -51,7 +53,7 @@ import java.util.List;
|
||||
* <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
|
||||
* {@link #notifyPermissionResponse(String, PersistableBundle)}, 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}.
|
||||
@@ -126,14 +128,15 @@ public class RestrictionsManager {
|
||||
* {@link #EXTRA_RESPONSE_BUNDLE}.
|
||||
*/
|
||||
public static final String ACTION_PERMISSION_RESPONSE_RECEIVED =
|
||||
"android.intent.action.PERMISSION_RESPONSE_RECEIVED";
|
||||
"android.content.action.PERMISSION_RESPONSE_RECEIVED";
|
||||
|
||||
/**
|
||||
* Broadcast intent sent to the Restrictions Provider to handle a permission request from
|
||||
* an app. It will have the following extras: {@link #EXTRA_PACKAGE_NAME},
|
||||
* {@link #EXTRA_REQUEST_TYPE} and {@link #EXTRA_REQUEST_BUNDLE}. The Restrictions Provider
|
||||
* will handle the request and respond back to the RestrictionsManager, when a response is
|
||||
* available, by calling {@link #notifyPermissionResponse}.
|
||||
* {@link #EXTRA_REQUEST_TYPE}, {@link #EXTRA_REQUEST_ID} and {@link #EXTRA_REQUEST_BUNDLE}.
|
||||
* The Restrictions Provider will handle the request and respond back to the
|
||||
* RestrictionsManager, when a response is available, by calling
|
||||
* {@link #notifyPermissionResponse}.
|
||||
* <p>
|
||||
* The BroadcastReceiver must require the {@link android.Manifest.permission#BIND_DEVICE_ADMIN}
|
||||
* permission to ensure that only the system can send the broadcast.
|
||||
@@ -141,18 +144,46 @@ public class RestrictionsManager {
|
||||
public static final String ACTION_REQUEST_PERMISSION =
|
||||
"android.content.action.REQUEST_PERMISSION";
|
||||
|
||||
/**
|
||||
* Activity intent that is optionally implemented by the Restrictions Provider package
|
||||
* to challenge for an administrator PIN or password locally on the device. Apps will
|
||||
* call this intent using {@link Activity#startActivityForResult}. On a successful
|
||||
* response, {@link Activity#onActivityResult} will return a resultCode of
|
||||
* {@link Activity#RESULT_OK}.
|
||||
* <p>
|
||||
* The intent must contain {@link #EXTRA_REQUEST_BUNDLE} as an extra and the bundle must
|
||||
* contain at least {@link #REQUEST_KEY_MESSAGE} for the activity to display.
|
||||
* <p>
|
||||
* @see #getLocalApprovalIntent()
|
||||
*/
|
||||
public static final String ACTION_REQUEST_LOCAL_APPROVAL =
|
||||
"android.content.action.REQUEST_LOCAL_APPROVAL";
|
||||
|
||||
/**
|
||||
* The package name of the application making the request.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
|
||||
|
||||
/**
|
||||
* The request type passed in the {@link #ACTION_REQUEST_PERMISSION} broadcast.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String EXTRA_REQUEST_TYPE = "android.content.extra.REQUEST_TYPE";
|
||||
|
||||
/**
|
||||
* The request ID passed in the {@link #ACTION_REQUEST_PERMISSION} broadcast.
|
||||
* <p>
|
||||
* Type: String
|
||||
*/
|
||||
public static final String EXTRA_REQUEST_ID = "android.content.extra.REQUEST_ID";
|
||||
|
||||
/**
|
||||
* The request bundle passed in the {@link #ACTION_REQUEST_PERMISSION} broadcast.
|
||||
* <p>
|
||||
* Type: {@link PersistableBundle}
|
||||
*/
|
||||
public static final String EXTRA_REQUEST_BUNDLE = "android.content.extra.REQUEST_BUNDLE";
|
||||
|
||||
@@ -163,14 +194,15 @@ public class RestrictionsManager {
|
||||
* <li>{@link #REQUEST_KEY_ID}: The request ID.</li>
|
||||
* <li>{@link #RESPONSE_KEY_RESULT}: The response result.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Type: {@link PersistableBundle}
|
||||
*/
|
||||
public static final String EXTRA_RESPONSE_BUNDLE = "android.content.extra.RESPONSE_BUNDLE";
|
||||
|
||||
/**
|
||||
* Request type for a simple question, with a possible title and icon.
|
||||
* <p>
|
||||
* Required keys are
|
||||
* {@link #REQUEST_KEY_ID} and {@link #REQUEST_KEY_MESSAGE}.
|
||||
* Required keys are: {@link #REQUEST_KEY_MESSAGE}
|
||||
* <p>
|
||||
* Optional keys are
|
||||
* {@link #REQUEST_KEY_DATA}, {@link #REQUEST_KEY_ICON}, {@link #REQUEST_KEY_TITLE},
|
||||
@@ -178,22 +210,6 @@ public class RestrictionsManager {
|
||||
*/
|
||||
public static final String REQUEST_TYPE_APPROVAL = "android.request.type.approval";
|
||||
|
||||
/**
|
||||
* Request type for a local password challenge. This is a way for an app to ask
|
||||
* the administrator to override an operation that is restricted on the device, such
|
||||
* as configuring Wi-Fi access points. It is most useful for situations where there
|
||||
* is no network connectivity for a remote administrator's response. The normal user of the
|
||||
* device is not expected to know the password. The challenge is meant for the administrator.
|
||||
* <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_TYPE_LOCAL_APPROVAL = "android.request.type.local_approval";
|
||||
|
||||
/**
|
||||
* Key for request ID contained in the request bundle.
|
||||
* <p>
|
||||
@@ -240,9 +256,10 @@ public class RestrictionsManager {
|
||||
* Key for request icon contained in the request bundle.
|
||||
* <p>
|
||||
* Optional, shown alongside the request message presented to the administrator
|
||||
* who approves the request.
|
||||
* who approves the request. The content must be a compressed image such as a
|
||||
* PNG or JPEG, as a byte array.
|
||||
* <p>
|
||||
* Type: Bitmap
|
||||
* Type: byte[]
|
||||
*/
|
||||
public static final String REQUEST_KEY_ICON = "android.request.icon";
|
||||
|
||||
@@ -403,7 +420,7 @@ public class RestrictionsManager {
|
||||
|
||||
/**
|
||||
* Called by an application to check if there is an active Restrictions Provider. If
|
||||
* there isn't, {@link #requestPermission(String, Bundle)} is not available.
|
||||
* there isn't, {@link #requestPermission(String, String, PersistableBundle)} is not available.
|
||||
*
|
||||
* @return whether there is an active Restrictions Provider.
|
||||
*/
|
||||
@@ -428,40 +445,54 @@ public class RestrictionsManager {
|
||||
* Restrictions Provider might understand. For custom types, the type name should be
|
||||
* namespaced to avoid collisions with predefined types and types specified by
|
||||
* other Restrictions Providers.
|
||||
* @param request A Bundle containing the data corresponding to the specified request
|
||||
* @param requestId A unique id generated by the app that contains sufficient information
|
||||
* to identify the parameters of the request when it receives the id in the response.
|
||||
* @param request A PersistableBundle containing the data corresponding to the specified request
|
||||
* type. The keys for the data in the bundle depend on the request type.
|
||||
*
|
||||
* @throws IllegalArgumentException if any of the required parameters are missing.
|
||||
*/
|
||||
public void requestPermission(String requestType, Bundle request) {
|
||||
public void requestPermission(String requestType, String requestId, PersistableBundle request) {
|
||||
if (requestType == null) {
|
||||
throw new NullPointerException("requestType cannot be null");
|
||||
}
|
||||
if (requestId == null) {
|
||||
throw new NullPointerException("requestId cannot be null");
|
||||
}
|
||||
if (request == null) {
|
||||
throw new NullPointerException("request cannot be null");
|
||||
}
|
||||
if (!request.containsKey(REQUEST_KEY_ID)) {
|
||||
throw new IllegalArgumentException("REQUEST_KEY_ID must be specified");
|
||||
}
|
||||
try {
|
||||
if (mService != null) {
|
||||
mService.requestPermission(mContext.getPackageName(), requestType, request);
|
||||
mService.requestPermission(mContext.getPackageName(), requestType, requestId,
|
||||
request);
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Couldn't reach service");
|
||||
}
|
||||
}
|
||||
|
||||
public Intent getLocalApprovalIntent() {
|
||||
try {
|
||||
if (mService != null) {
|
||||
return mService.getLocalApprovalIntent();
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Couldn't reach service");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the Restrictions Provider to deliver a response to an application.
|
||||
*
|
||||
* @param packageName the application to deliver the response to. Cannot be null.
|
||||
* @param response the Bundle containing the response status, request ID and other information.
|
||||
* @param response the bundle containing the response status, request ID and other information.
|
||||
* Cannot be null.
|
||||
*
|
||||
* @throws IllegalArgumentException if any of the required parameters are missing.
|
||||
*/
|
||||
public void notifyPermissionResponse(String packageName, Bundle response) {
|
||||
public void notifyPermissionResponse(String packageName, PersistableBundle response) {
|
||||
if (packageName == null) {
|
||||
throw new NullPointerException("packageName cannot be null");
|
||||
}
|
||||
|
||||
20
core/java/android/os/PersistableBundle.aidl
Normal file
20
core/java/android/os/PersistableBundle.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright 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.os;
|
||||
|
||||
parcelable PersistableBundle;
|
||||
@@ -40,6 +40,7 @@ import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.IUserManager;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
@@ -103,7 +104,8 @@ public final class RestrictionsManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void requestPermission(final String packageName, final String requestType,
|
||||
final Bundle requestData) throws RemoteException {
|
||||
final String requestId,
|
||||
final PersistableBundle requestData) throws RemoteException {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "requestPermission");
|
||||
}
|
||||
@@ -127,6 +129,7 @@ public final class RestrictionsManagerService extends SystemService {
|
||||
intent.setComponent(restrictionsProvider);
|
||||
intent.putExtra(RestrictionsManager.EXTRA_PACKAGE_NAME, packageName);
|
||||
intent.putExtra(RestrictionsManager.EXTRA_REQUEST_TYPE, requestType);
|
||||
intent.putExtra(RestrictionsManager.EXTRA_REQUEST_ID, requestId);
|
||||
intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, requestData);
|
||||
mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
|
||||
} finally {
|
||||
@@ -136,7 +139,40 @@ public final class RestrictionsManagerService extends SystemService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPermissionResponse(String packageName, Bundle response)
|
||||
public Intent getLocalApprovalIntent() throws RemoteException {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "requestPermission");
|
||||
}
|
||||
final int userHandle = UserHandle.getCallingUserId();
|
||||
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");
|
||||
}
|
||||
String providerPackageName = restrictionsProvider.getPackageName();
|
||||
Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_LOCAL_APPROVAL);
|
||||
intent.setPackage(providerPackageName);
|
||||
ResolveInfo ri = AppGlobals.getPackageManager().resolveIntent(intent,
|
||||
null /* resolvedType */, 0 /* flags */, userHandle);
|
||||
if (ri != null && ri.activityInfo != null && ri.activityInfo.exported) {
|
||||
intent.setComponent(new ComponentName(ri.activityInfo.packageName,
|
||||
ri.activityInfo.name));
|
||||
return intent;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPermissionResponse(String packageName, PersistableBundle response)
|
||||
throws RemoteException {
|
||||
// Check caller
|
||||
int callingUid = Binder.getCallingUid();
|
||||
|
||||
Reference in New Issue
Block a user