summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt4
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java43
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl6
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java112
-rw-r--r--core/res/AndroidManifest.xml20
-rw-r--r--core/res/res/drawable-hdpi/personal_icon.pngbin0 -> 1560 bytes
-rw-r--r--core/res/res/drawable-hdpi/work_icon.pngbin0 -> 1153 bytes
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--services/core/java/com/android/server/pm/ForwardingIntentFilter.java102
-rw-r--r--services/core/java/com/android/server/pm/ForwardingIntentResolver.java44
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java125
-rw-r--r--services/core/java/com/android/server/pm/Settings.java59
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java45
14 files changed, 567 insertions, 1 deletions
diff --git a/api/current.txt b/api/current.txt
index 54c9d90..605e786 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4985,8 +4985,10 @@ package android.app.admin {
public class DevicePolicyManager {
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+ method public void clearForwardingIntentFilters(android.content.ComponentName);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public void forwardMatchingIntents(android.content.ComponentName, android.content.IntentFilter, int);
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5046,6 +5048,8 @@ package android.app.admin {
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "defaultManagedProfileName";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "deviceAdminPackageName";
+ field public static int FLAG_TO_MANAGED_PROFILE;
+ field public static int FLAG_TO_PRIMARY_USER;
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 68ab611..73e5b2a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -172,6 +172,16 @@ public class DevicePolicyManager {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SET_NEW_PASSWORD
= "android.app.action.SET_NEW_PASSWORD";
+ /**
+ * Flag for {@link #forwardMatchingIntents}: the intents will forwarded to the primary user.
+ */
+ public static int FLAG_TO_PRIMARY_USER = 0x0001;
+
+ /**
+ * Flag for {@link #forwardMatchingIntents}: the intents will be forwarded to the managed
+ * profile.
+ */
+ public static int FLAG_TO_MANAGED_PROFILE = 0x0002;
/**
* Return true if the given administrator component is currently
@@ -1953,6 +1963,39 @@ public class DevicePolicyManager {
}
/**
+ * Called by a profile owner to forward intents sent from the managed profile to the owner, or
+ * from the owner to the managed profile.
+ * If an intent matches this intent filter, then activities belonging to the other user can
+ * respond to this intent.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param filter if an intent matches this IntentFilter, then it can be forwarded.
+ */
+ public void forwardMatchingIntents(ComponentName admin, IntentFilter filter, int flags) {
+ if (mService != null) {
+ try {
+ mService.forwardMatchingIntents(admin, filter, flags);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Called by a profile owner to remove all the forwarding intent filters from the current user
+ * and from the owner.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ */
+ public void clearForwardingIntentFilters(ComponentName admin) {
+ if (mService != null) {
+ try {
+ mService.clearForwardingIntentFilters(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
* Called by a profile or device owner to get the application restrictions for a given target
* application running in the managed profile.
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 72b3c20..eaf4016 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -121,4 +121,6 @@ interface IDevicePolicyManager {
Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
void setUserRestriction(in ComponentName who, in String key, boolean enable);
+ void forwardMatchingIntents(in ComponentName admin, in IntentFilter filter, int flags);
+ void clearForwardingIntentFilters(in ComponentName admin);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 488e25f..cf9a296 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,6 +111,8 @@ interface IPackageManager {
ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
+ boolean canForwardTo(in Intent intent, String resolvedType, int userIdFrom, int userIdDest);
+
List<ResolveInfo> queryIntentActivities(in Intent intent,
String resolvedType, int flags, int userId);
@@ -245,6 +247,10 @@ interface IPackageManager {
void clearPackagePersistentPreferredActivities(String packageName, int userId);
+ void addForwardingIntentFilter(in IntentFilter filter, int userIdOrig, int userIdDest);
+
+ void clearForwardingIntentFilters(int userIdOrig);
+
/**
* Report the set of 'Home' activity candidates, plus (if any) which of them
* is the current "always use this one" setting.
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
new file mode 100644
index 0000000..2f74372
--- /dev/null
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -0,0 +1,112 @@
+/*
+ * 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.internal.app;
+
+import android.app.Activity;
+import android.app.AppGlobals;
+import android.os.Bundle;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.app.ActivityManagerNative;
+import android.os.RemoteException;
+import android.util.Slog;
+import java.util.List;
+import java.util.Set;
+
+
+
+
+/*
+ * This is used in conjunction with DevicePolicyManager.setForwardingIntents to enable intents to be
+ * passed in and out of a managed profile.
+ */
+
+public class IntentForwarderActivity extends Activity {
+
+ public static String TAG = "IntentForwarderActivity";
+
+ public static String FORWARD_INTENT_TO_USER_OWNER
+ = "com.android.internal.app.ForwardIntentToUserOwner";
+
+ public static String FORWARD_INTENT_TO_MANAGED_PROFILE
+ = "com.android.internal.app.ForwardIntentToManagedProfile";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intentReceived = getIntent();
+
+ String className = intentReceived.getComponent().getClassName();
+ final UserHandle userDest;
+
+ if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
+ userDest = UserHandle.OWNER;
+ } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+ userDest = getManagedProfile();
+ } else {
+ Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
+ userDest = null;
+ }
+ if (userDest == null) { // This covers the case where there is no managed profile.
+ finish();
+ return;
+ }
+ Intent newIntent = new Intent(intentReceived);
+ newIntent.setComponent(null);
+ newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+ int callingUserId = getUserId();
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
+ boolean canForward = false;
+ try {
+ canForward = ipm.canForwardTo(newIntent, resolvedType, callingUserId,
+ userDest.getIdentifier());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "PackageManagerService is dead?");
+ }
+ if (canForward) {
+ startActivityAsUser(newIntent, userDest);
+ } else {
+ Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
+ + callingUserId + " to user " + userDest.getIdentifier());
+ }
+ finish();
+ }
+
+ /**
+ * Returns the managed profile for this device or null if there is no managed
+ * profile.
+ *
+ * TODO: Remove the assumption that there is only one managed profile
+ * on the device.
+ */
+ private UserHandle getManagedProfile() {
+ UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+ List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
+ for (UserInfo userInfo : relatedUsers) {
+ if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id);
+ }
+ Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
+ + " has been called, but there is no managed profile");
+ return null;
+ }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4f093a8..3d3e86f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2681,6 +2681,26 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <activity android:name="com.android.internal.app.IntentForwarderActivity"
+ android:finishOnCloseSystemDialogs="true"
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:label="@string/user_owner_label"
+ android:exported="true"
+ >
+ </activity>
+ <activity-alias android:name="com.android.internal.app.ForwardIntentToUserOwner"
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:icon="@drawable/personal_icon"
+ android:exported="true"
+ android:label="@string/user_owner_label">
+ </activity-alias>
+ <activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:icon="@drawable/work_icon"
+ android:exported="true"
+ android:label="@string/managed_profile_label">
+ </activity-alias>
<activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
android:theme="@style/Theme.Holo.Dialog"
android:label="@string/heavy_weight_switcher_title"
diff --git a/core/res/res/drawable-hdpi/personal_icon.png b/core/res/res/drawable-hdpi/personal_icon.png
new file mode 100644
index 0000000..8d96b5e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/personal_icon.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/work_icon.png b/core/res/res/drawable-hdpi/work_icon.png
new file mode 100644
index 0000000..e90866b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/work_icon.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 57b2c01..97400b2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -454,6 +454,12 @@
<!-- Label for the Android system components when they are shown to the user. -->
<string name="android_system_label">Android System</string>
+ <!-- Label for the user owner in the intent forwarding app. -->
+ <string name="user_owner_label">Personal</string>
+
+ <!-- Label for a corporate profile in the intent forwarding app. -->
+ <string name="managed_profile_label">Work</string>
+
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_costMoney">Services that cost you money</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
new file mode 100644
index 0000000..aba796b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.android.server.pm;
+
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import android.content.IntentFilter;
+import android.util.Log;
+import java.io.IOException;
+import android.os.UserHandle;
+
+/**
+ * The {@link PackageManagerService} maintains some {@link ForwardingIntentFilter}s for every user.
+ * If an {@link Intent} matches the {@link ForwardingIntentFilter}, then it can be forwarded to the
+ * {@link #mUserIdDest}.
+ */
+class ForwardingIntentFilter extends IntentFilter {
+ private static final String ATTR_USER_ID_DEST = "userIdDest";
+ private static final String ATTR_FILTER = "filter";
+
+ private static final String TAG = "ForwardingIntentFilter";
+
+ // If the intent matches the IntentFilter, then it can be forwarded to this userId.
+ final int mUserIdDest;
+
+ ForwardingIntentFilter(IntentFilter filter, int userIdDest) {
+ super(filter);
+ mUserIdDest = userIdDest;
+ }
+
+ public int getUserIdDest() {
+ return mUserIdDest;
+ }
+
+ ForwardingIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String userIdDestString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
+ if (userIdDestString == null) {
+ String msg = "Missing element under " + TAG +": " + ATTR_USER_ID_DEST + " at " +
+ parser.getPositionDescription();
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ mUserIdDest = UserHandle.USER_NULL;
+ } else {
+ mUserIdDest = Integer.parseInt(userIdDestString);
+ }
+ int outerDepth = parser.getDepth();
+ String tagName = parser.getName();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ tagName = parser.getName();
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ } else if (type == XmlPullParser.START_TAG) {
+ if (tagName.equals(ATTR_FILTER)) {
+ break;
+ } else {
+ String msg = "Unknown element under " + Settings.TAG_FORWARDING_INTENT_FILTERS
+ + ": " + tagName + " at " + parser.getPositionDescription();
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+ if (tagName.equals(ATTR_FILTER)) {
+ readFromXml(parser);
+ } else {
+ String msg = "Missing element under " + TAG + ": " + ATTR_FILTER +
+ " at " + parser.getPositionDescription();
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.attribute(null, ATTR_USER_ID_DEST, Integer.toString(mUserIdDest));
+ serializer.startTag(null, ATTR_FILTER);
+ super.writeToXml(serializer);
+ serializer.endTag(null, ATTR_FILTER);
+ }
+
+ @Override
+ public String toString() {
+ return "ForwardingIntentFilter{0x" + Integer.toHexString(System.identityHashCode(this))
+ + " " + Integer.toString(mUserIdDest) + "}";
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentResolver.java b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
new file mode 100644
index 0000000..1616395
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.android.server.pm;
+
+
+import java.io.PrintWriter;
+import com.android.server.IntentResolver;
+import java.util.List;
+
+/**
+ * Used to find a list of {@link ForwardingIntentFilter}s that match an intent.
+ */
+class ForwardingIntentResolver
+ extends IntentResolver<ForwardingIntentFilter, ForwardingIntentFilter> {
+ @Override
+ protected ForwardingIntentFilter[] newArray(int size) {
+ return new ForwardingIntentFilter[size];
+ }
+
+ @Override
+ protected boolean isPackageForFilter(String packageName, ForwardingIntentFilter filter) {
+ return false;
+ }
+
+ @Override
+ protected void sortResults(List<ForwardingIntentFilter> results) {
+ //We don't sort the results
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d0412ef..87c0935 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -28,6 +28,8 @@ import static android.system.OsConstants.S_IRGRP;
import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IROTH;
import static android.system.OsConstants.S_IXOTH;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
@@ -3124,6 +3126,33 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
+ /*
+ * Returns if intent can be forwarded from the userId from to dest
+ */
+ @Override
+ public boolean canForwardTo(Intent intent, String resolvedType, int userIdFrom, int userIdDest) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+ List<ForwardingIntentFilter> matches =
+ getMatchingForwardingIntentFilters(intent, resolvedType, userIdFrom);
+ if (matches != null) {
+ int size = matches.size();
+ for (int i = 0; i < size; i++) {
+ if (matches.get(i).getUserIdDest() == userIdDest) return true;
+ }
+ }
+ return false;
+ }
+
+ private List<ForwardingIntentFilter> getMatchingForwardingIntentFilters(Intent intent,
+ String resolvedType, int userId) {
+ ForwardingIntentResolver fir = mSettings.mForwardingIntentResolvers.get(userId);
+ if (fir != null) {
+ return fir.queryIntent(intent, resolvedType, false, userId);
+ }
+ return null;
+ }
+
@Override
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
@@ -3152,7 +3181,38 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
final String pkgName = intent.getPackage();
if (pkgName == null) {
- return mActivities.queryIntent(intent, resolvedType, flags, userId);
+ List<ResolveInfo> result =
+ mActivities.queryIntent(intent, resolvedType, flags, userId);
+ // Checking if we can forward the intent to another user
+ List<ForwardingIntentFilter> fifs =
+ getMatchingForwardingIntentFilters(intent, resolvedType, userId);
+ if (fifs != null) {
+ ForwardingIntentFilter forwardingIntentFilterWithResult = null;
+ HashSet<Integer> alreadyTriedUserIds = new HashSet<Integer>();
+ for (ForwardingIntentFilter fif : fifs) {
+ int userIdDest = fif.getUserIdDest();
+ // Two {@link ForwardingIntentFilter}s can have the same userIdDest and
+ // match the same an intent. For performance reasons, it is better not to
+ // run queryIntent twice for the same userId
+ if (!alreadyTriedUserIds.contains(userIdDest)) {
+ List<ResolveInfo> resultUser = mActivities.queryIntent(intent,
+ resolvedType, flags, userIdDest);
+ if (resultUser != null) {
+ forwardingIntentFilterWithResult = fif;
+ // As soon as there is a match in another user, we add the
+ // intentForwarderActivity to the list of ResolveInfo.
+ break;
+ }
+ alreadyTriedUserIds.add(userIdDest);
+ }
+ }
+ if (forwardingIntentFilterWithResult != null) {
+ ResolveInfo forwardingResolveInfo = createForwardingResolveInfo(
+ forwardingIntentFilterWithResult, userId);
+ result.add(forwardingResolveInfo);
+ }
+ }
+ return result;
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
@@ -3163,6 +3223,28 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private ResolveInfo createForwardingResolveInfo(ForwardingIntentFilter fif, int userIdFrom) {
+ String className;
+ int userIdDest = fif.getUserIdDest();
+ if (userIdDest == UserHandle.USER_OWNER) {
+ className = FORWARD_INTENT_TO_USER_OWNER;
+ } else {
+ className = FORWARD_INTENT_TO_MANAGED_PROFILE;
+ }
+ ComponentName forwardingActivityComponentName = new ComponentName(
+ mAndroidApplication.packageName, className);
+ ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0,
+ userIdFrom);
+ ResolveInfo forwardingResolveInfo = new ResolveInfo();
+ forwardingResolveInfo.activityInfo = forwardingActivityInfo;
+ forwardingResolveInfo.priority = 0;
+ forwardingResolveInfo.preferredOrder = 0;
+ forwardingResolveInfo.match = 0;
+ forwardingResolveInfo.isDefault = true;
+ forwardingResolveInfo.filter = fif;
+ return forwardingResolveInfo;
+ }
+
@Override
public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
Intent[] specifics, String[] specificTypes, Intent intent,
@@ -10817,6 +10899,47 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ /*
+ * For filters that are added with this method:
+ * if an intent for the user whose id is userIdOrig matches the filter, then this intent can
+ * also be resolved in the user whose id is userIdDest.
+ */
+ @Override
+ public void addForwardingIntentFilter(IntentFilter filter, int userIdOrig, int userIdDest) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "addForwardingIntentFilter can only be run by the system");
+ }
+ if (filter.countActions() == 0) {
+ Slog.w(TAG, "Cannot set a forwarding intent filter with no filter actions");
+ return;
+ }
+ synchronized (mPackages) {
+ mSettings.editForwardingIntentResolverLPw(userIdOrig).addFilter(
+ new ForwardingIntentFilter(filter, userIdDest));
+ mSettings.writePackageRestrictionsLPr(userIdOrig);
+ }
+ }
+
+ @Override
+ public void clearForwardingIntentFilters(int userIdOrig) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "clearForwardingIntentFilter can only be run by the system");
+ }
+ synchronized (mPackages) {
+ ForwardingIntentResolver fir = mSettings.editForwardingIntentResolverLPw(userIdOrig);
+ HashSet<ForwardingIntentFilter> set =
+ new HashSet<ForwardingIntentFilter>(fir.filterSet());
+ for (ForwardingIntentFilter fif : set) {
+ fir.removeFilter(fif);
+ }
+ mSettings.writePackageRestrictionsLPr(userIdOrig);
+ }
+ }
+
@Override
public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
Intent intent = new Intent(Intent.ACTION_MAIN);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e4dd2d4..fca3933 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -130,6 +130,8 @@ final class Settings {
private static final String TAG_PACKAGE = "pkg";
private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
"persistent-preferred-activities";
+ static final String TAG_FORWARDING_INTENT_FILTERS =
+ "forwarding-intent-filters";
private static final String ATTR_NAME = "name";
private static final String ATTR_USER = "user";
@@ -184,6 +186,10 @@ final class Settings {
final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
new SparseArray<PersistentPreferredIntentResolver>();
+ // For every user, it is used to find to which other users the intent can be forwarded.
+ final SparseArray<ForwardingIntentResolver> mForwardingIntentResolvers =
+ new SparseArray<ForwardingIntentResolver>();
+
final HashMap<String, SharedUserSetting> mSharedUsers =
new HashMap<String, SharedUserSetting>();
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -831,6 +837,15 @@ final class Settings {
return ppir;
}
+ ForwardingIntentResolver editForwardingIntentResolverLPw(int userId) {
+ ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
+ if (fir == null) {
+ fir = new ForwardingIntentResolver();
+ mForwardingIntentResolvers.put(userId, fir);
+ }
+ return fir;
+ }
+
private File getUserPackagesStateFile(int userId) {
return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
}
@@ -946,6 +961,28 @@ final class Settings {
}
}
+ private void readForwardingIntentFiltersLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ ForwardingIntentFilter fif = new ForwardingIntentFilter(parser);
+ editForwardingIntentResolverLPw(userId).addFilter(fif);
+ } else {
+ String msg = "Unknown element under " + TAG_FORWARDING_INTENT_FILTERS + ": " +
+ parser.getName();
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
void readPackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -1074,6 +1111,8 @@ final class Settings {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
readPersistentPreferredActivitiesLPw(parser, userId);
+ } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
+ readForwardingIntentFiltersLPw(parser, userId);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
@@ -1151,6 +1190,20 @@ final class Settings {
serializer.endTag(null, TAG_PERSISTENT_PREFERRED_ACTIVITIES);
}
+ void writeForwardingIntentFiltersLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, TAG_FORWARDING_INTENT_FILTERS);
+ ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
+ if (fir != null) {
+ for (final ForwardingIntentFilter fif : fir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ fif.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, TAG_FORWARDING_INTENT_FILTERS);
+ }
+
void writePackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1249,6 +1302,8 @@ final class Settings {
writePersistentPreferredActivitiesLPr(serializer, userId);
+ writeForwardingIntentFiltersLPr(serializer, userId);
+
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
serializer.endDocument();
@@ -1866,6 +1921,10 @@ final class Settings {
// TODO: check whether this is okay! as it is very
// similar to how preferred-activities are treated
readPersistentPreferredActivitiesLPw(parser, 0);
+ } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
+ // TODO: check whether this is okay! as it is very
+ // similar to how preferred-activities are treated
+ readForwardingIntentFiltersLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f1ee280..8e1f82a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3099,6 +3099,51 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ public void forwardMatchingIntents(ComponentName who, IntentFilter filter, int flags) {
+ int callingUserId = UserHandle.getCallingUserId();
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ long id = Binder.clearCallingIdentity();
+ try {
+ if ((flags & DevicePolicyManager.FLAG_TO_PRIMARY_USER) != 0) {
+ pm.addForwardingIntentFilter(filter, callingUserId, UserHandle.USER_OWNER);
+ }
+ if ((flags & DevicePolicyManager.FLAG_TO_MANAGED_PROFILE) != 0) {
+ pm.addForwardingIntentFilter(filter, UserHandle.USER_OWNER, callingUserId);
+ }
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ public void clearForwardingIntentFilters(ComponentName who) {
+ int callingUserId = UserHandle.getCallingUserId();
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ IPackageManager pm = AppGlobals.getPackageManager();
+ long id = Binder.clearCallingIdentity();
+ try {
+ pm.clearForwardingIntentFilters(callingUserId);
+ pm.clearForwardingIntentFilters(UserHandle.USER_OWNER);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
@Override
public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());