Allow intent resolution to be constrained by package name.
diff --git a/api/current.xml b/api/current.xml
index c03526d..7d55a7d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -33321,8 +33321,6 @@
 >
 <parameter name="packageName" type="java.lang.String">
 </parameter>
-<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
-</exception>
 </method>
 <method name="getNameForUid"
  return="java.lang.String"
@@ -33750,6 +33748,23 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<method name="resolveActivity"
+ return="android.content.pm.ResolveInfo"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
 <method name="resolveContentProvider"
  return="android.content.pm.ProviderInfo"
  abstract="true"
@@ -111816,8 +111831,6 @@
 >
 <parameter name="packageName" type="java.lang.String">
 </parameter>
-<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
-</exception>
 </method>
 <method name="getNameForUid"
  return="java.lang.String"
@@ -112227,6 +112240,23 @@
 </parameter>
 <parameter name="flags" type="int">
 </parameter>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
+<method name="resolveActivity"
+ return="android.content.pm.ResolveInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
 </method>
 <method name="resolveContentProvider"
  return="android.content.pm.ProviderInfo"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 81e894f..2c2310a 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -1519,43 +1519,31 @@
             throw new NameNotFoundException(packageName);
         }
 
-        public Intent getLaunchIntentForPackage(String packageName)
-                throws NameNotFoundException {
+        @Override
+        public Intent getLaunchIntentForPackage(String packageName) {
             // First see if the package has an INFO activity; the existence of
             // such an activity is implied to be the desired front-door for the
             // overall package (such as if it has multiple launcher entries).
-            Intent intent = getLaunchIntentForPackageCategory(this, packageName,
-                    Intent.CATEGORY_INFO);
-            if (intent != null) {
-                return intent;
-            }
-            
+            Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+            intentToResolve.addCategory(Intent.CATEGORY_INFO);
+            ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0, packageName);
+
             // Otherwise, try to find a main launcher activity.
-            return getLaunchIntentForPackageCategory(this, packageName,
-                    Intent.CATEGORY_LAUNCHER);
-        }
-        
-        // XXX This should be implemented as a call to the package manager,
-        // to reduce the work needed.
-        static Intent getLaunchIntentForPackageCategory(PackageManager pm,
-                String packageName, String category) {
-            Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            Intent intentToResolve = new Intent(Intent.ACTION_MAIN, null);
-            intentToResolve.addCategory(category);
-            final List<ResolveInfo> apps =
-                    pm.queryIntentActivities(intentToResolve, 0);
-            // I wish there were a way to directly get the "main" activity of a
-            // package but ...
-            for (ResolveInfo app : apps) {
-                if (app.activityInfo.packageName.equals(packageName)) {
-                    intent.setClassName(packageName, app.activityInfo.name);
-                    return intent;
-                }
+            if (resolveInfo == null) {
+                // reuse the intent instance
+                intentToResolve.removeCategory(Intent.CATEGORY_INFO);
+                intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+                resolveInfo = resolveActivity(intentToResolve, 0, packageName);
             }
-            return null;
+            if (resolveInfo == null) {
+                return null;
+            }
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setClassName(packageName, resolveInfo.activityInfo.name);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            return intent;
         }
-        
+
         @Override
         public int[] getPackageGids(String packageName)
             throws NameNotFoundException {
@@ -1793,6 +1781,19 @@
         }
 
         @Override
+        public ResolveInfo resolveActivity(Intent intent, int flags, String packageName) {
+            try {
+                return mPM.resolveIntentForPackage(
+                    intent,
+                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                    flags,
+                    packageName);
+            } catch (RemoteException e) {
+                throw new RuntimeException("Package manager has died", e);
+            }
+        }
+
+        @Override
         public List<ResolveInfo> queryIntentActivities(Intent intent,
                 int flags) {
             try {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c199619..bb913cd 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -81,6 +81,9 @@
     
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags);
 
+    ResolveInfo resolveIntentForPackage(in Intent intent, String resolvedType, int flags,
+            String packageName);
+
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
             String resolvedType, int flags);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3a192f7..eecbce4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -563,9 +563,8 @@
      * launch the main activity in the package, or null if the package does
      * not contain such an activity.
      */
-    public abstract Intent getLaunchIntentForPackage(String packageName)
-            throws NameNotFoundException;
-    
+    public abstract Intent getLaunchIntentForPackage(String packageName);
+
     /**
      * Return an array of all of the secondary group-ids that have been
      * assigned to a package.
@@ -971,6 +970,23 @@
     public abstract ResolveInfo resolveActivity(Intent intent, int flags);
 
     /**
+     * Resolve the intent restricted to a package.
+     * {@see #resolveActivity}
+     *
+     * @param intent An intent containing all of the desired specification
+     *               (action, data, type, category, and/or component).
+     * @param flags Additional option flags.  The most important is
+     *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
+     *                    those activities that support the CATEGORY_DEFAULT.
+     * @param packageName Restrict the intent resolution to this package.
+     *
+     * @return Returns a ResolveInfo containing the final activity intent that
+     *         was determined to be the best action.  Returns null if no
+     *         matching activity was found.
+     */
+    public abstract ResolveInfo resolveActivity(Intent intent, int flags, String packageName);
+
+    /**
      * Retrieve all activities that can be performed for the given intent.
      *
      * @param intent The desired intent as per resolveActivity().
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index 72efca5..53e63c2 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -163,6 +163,23 @@
         return Collections.unmodifiableSet(mFilters);
     }
 
+    public List<R> queryIntentFromList(Intent intent, String resolvedType, 
+            boolean defaultOnly, ArrayList<ArrayList<F>> listCut) {
+        ArrayList<R> resultList = new ArrayList<R>();
+
+        final boolean debug = localLOGV ||
+                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
+
+        final String scheme = intent.getScheme();
+        int N = listCut.size();
+        for (int i = 0; i < N; ++i) {
+            buildResolveList(intent, debug, defaultOnly,
+                             resolvedType, scheme, listCut.get(i), resultList);
+        }
+        sortResults(resultList);
+        return resultList;
+    }
+
     public List<R> queryIntent(ContentResolver resolver, Intent intent,
             String resolvedType, boolean defaultOnly) {
         String scheme = intent.getScheme();
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 079f363..4ce40b6 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -1203,6 +1203,33 @@
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags) {
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags);
+        return chooseBestActivity(intent, resolvedType, flags, query);
+    }
+
+    public ResolveInfo resolveIntentForPackage(Intent intent, String resolvedType,
+                                               int flags, String packageName) {
+        ComponentName comp = intent.getComponent();
+        if (comp != null) {
+            // if this is an explicit intent, it must have the same the packageName
+            if (packageName.equals(comp.getPackageName())) {
+                return resolveIntent(intent, resolvedType, flags);
+            }
+            return null;
+        } else {
+            List<ResolveInfo> query = null;
+            synchronized (mPackages) {
+                PackageParser.Package pkg = mPackages.get(packageName);
+                if (pkg != null) {
+                    query = (List<ResolveInfo>) mActivities.
+                        queryIntentForPackage(intent, resolvedType, flags, pkg.activities);
+                }
+            }
+            return chooseBestActivity(intent, resolvedType, flags, query);
+        }
+    }
+
+    private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
+                                           int flags, List<ResolveInfo> query) {
         if (query != null) {
             final int N = query.size();
             if (N == 1) {
@@ -2853,6 +2880,22 @@
                 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
         }
 
+        public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
+                                          ArrayList<PackageParser.Activity> packageActivities) {
+            if (packageActivities == null) {
+                return null;
+            }
+            mFlags = flags;
+            final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
+            int N = packageActivities.size();
+            ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
+                new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
+            for (int i = 0; i < N; ++i) {
+                listCut.add(packageActivities.get(i).intents);
+            }
+            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
+        }
+
         public final void addActivity(PackageParser.Activity a, String type) {
             mActivities.put(a.component, a);
             if (SHOW_INFO || Config.LOGV) Log.v(
@@ -2860,8 +2903,7 @@
                 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
             if (SHOW_INFO || Config.LOGV) Log.v(TAG, "    Class=" + a.info.name);
             int NI = a.intents.size();
-            int j;
-            for (j=0; j<NI; j++) {
+            for (int j=0; j<NI; j++) {
                 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
                 if (SHOW_INFO || Config.LOGV) {
                     Log.v(TAG, "    IntentFilter:");
@@ -2881,8 +2923,7 @@
                 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
             if (SHOW_INFO || Config.LOGV) Log.v(TAG, "    Class=" + a.info.name);
             int NI = a.intents.size();
-            int j;
-            for (j=0; j<NI; j++) {
+            for (int j=0; j<NI; j++) {
                 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
                 if (SHOW_INFO || Config.LOGV) {
                     Log.v(TAG, "    IntentFilter:");
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index bf1629f..73ae3b9 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -57,11 +57,15 @@
     }
 
     @Override
-    public Intent getLaunchIntentForPackage(String packageName)
-            throws NameNotFoundException {
+    public Intent getLaunchIntentForPackage(String packageName) {
         throw new UnsupportedOperationException();
     }
-    
+
+    @Override
+    public ResolveInfo resolveActivity(Intent intent, int flags, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public int[] getPackageGids(String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException();