diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 2c2310a030d45..2d6381a632dfe 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -2424,6 +2424,16 @@ class ApplicationContext extends Context { } } + @Override + public void replacePreferredActivity(IntentFilter filter, + int match, ComponentName[] set, ComponentName activity) { + try { + mPM.replacePreferredActivity(filter, match, set, activity); + } catch (RemoteException e) { + // Should never happen! + } + } + @Override public void clearPackagePreferredActivities(String packageName) { try { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index bb913cdca90c1..5f62248bcd146 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -167,7 +167,12 @@ interface IPackageManager { void addPreferredActivity(in IntentFilter filter, int match, in ComponentName[] set, in ComponentName activity); + + void replacePreferredActivity(in IntentFilter filter, int match, + in ComponentName[] set, in ComponentName activity); + void clearPackagePreferredActivities(String packageName); + int getPreferredActivities(out List outFilters, out List outActivities, String packageName); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 238a98afd683e..a2c82e890e41b 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1629,6 +1629,26 @@ public abstract class PackageManager { public abstract void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity); + /** + * Replaces an existing preferred activity mapping to the system, and if that were not present + * adds a new preferred activity. This will be used + * to automatically select the given activity component when + * {@link Context#startActivity(Intent) Context.startActivity()} finds + * multiple matching activities and also matches the given filter. + * + * @param filter The set of intents under which this activity will be + * made preferred. + * @param match The IntentFilter match category that this preference + * applies to. + * @param set The set of activities that the user was picking from when + * this preference was made. + * @param activity The component name of the activity that is to be + * preferred. + * @hide + */ + public abstract void replacePreferredActivity(IntentFilter filter, int match, + ComponentName[] set, ComponentName activity); + /** * Remove all preferred activity mappings, previously added with * {@link #addPreferredActivity}, from the diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index c9bdd3c7ebef1..8da40acf93723 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -19,6 +19,7 @@ package com.android.server; import com.android.internal.app.ResolverActivity; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; +import com.android.server.PackageManagerService.PreferredActivity; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -4507,6 +4508,42 @@ class PackageManagerService extends IPackageManager.Stub { } } + public void replacePreferredActivity(IntentFilter filter, int match, + ComponentName[] set, ComponentName activity) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); + if (filter.countActions() != 1) { + throw new IllegalArgumentException( + "replacePreferredActivity expects filter to have only 1 action."); + } + if (filter.countCategories() != 1) { + throw new IllegalArgumentException( + "replacePreferredActivity expects filter to have only 1 category."); + } + if (filter.countDataAuthorities() != 0 + || filter.countDataPaths() != 0 + || filter.countDataSchemes() != 0 + || filter.countDataTypes() != 0) { + throw new IllegalArgumentException( + "replacePreferredActivity expects filter to have no data authorities, " + + "paths, schemes or types."); + } + synchronized (mPackages) { + Iterator it = mSettings.mPreferredActivities.filterIterator(); + String action = filter.getAction(0); + String category = filter.getCategory(0); + while (it.hasNext()) { + PreferredActivity pa = it.next(); + if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) { + it.remove(); + Log.i(TAG, "Removed preferred activity " + pa.mActivity + ":"); + filter.dump(new LogPrinter(Log.INFO, TAG), " "); + } + } + addPreferredActivity(filter, match, set, activity); + } + } + public void clearPackagePreferredActivities(String packageName) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java index 73ae3b91308ee..6ef5539ad0c8e 100644 --- a/test-runner/android/test/mock/MockPackageManager.java +++ b/test-runner/android/test/mock/MockPackageManager.java @@ -392,6 +392,16 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** + * @hide - to match hiding in superclass + */ + @Override + public void replacePreferredActivity(IntentFilter filter, + int match, ComponentName[] set, ComponentName activity) { + throw new UnsupportedOperationException(); + } + + @Override public void clearPackagePreferredActivities(String packageName) { throw new UnsupportedOperationException();