Merge "Add Default Browser App support and relax Hosts validation for AppLinks"
diff --git a/api/current.txt b/api/current.txt
index 0d6c7b6..fcbfa04 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30711,6 +30711,7 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method public java.lang.String getDefaultBrowserPackageName(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
@@ -30758,6 +30759,7 @@
     method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
+    method public boolean setDefaultBrowserPackageName(java.lang.String, int);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
     method public void verifyPendingInstall(int, int);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index ff8c50f..5351778 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -33322,6 +33322,7 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method public java.lang.String getDefaultBrowserPackageName(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
@@ -33371,6 +33372,7 @@
     method public void revokePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
+    method public boolean setDefaultBrowserPackageName(java.lang.String, int);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
     method public void verifyPendingInstall(int, int);
   }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index ffdc81d..9ddfd88 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1359,6 +1359,26 @@
     }
 
     @Override
+    public String getDefaultBrowserPackageName(int userId) {
+        try {
+            return mPM.getDefaultBrowserPackageName(userId);
+        } catch (RemoteException e) {
+            // Should never happen!
+            return null;
+        }
+    }
+
+    @Override
+    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+        try {
+            return mPM.setDefaultBrowserPackageName(packageName, userId);
+        } catch (RemoteException e) {
+            // Should never happen!
+            return false;
+        }
+    }
+
+    @Override
     public void setInstallerPackageName(String targetPackage,
             String installerPackageName) {
         try {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 55c990f..c2580c0 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -450,6 +450,9 @@
     List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName);
     List<IntentFilter> getAllIntentFilters(String packageName);
 
+    boolean setDefaultBrowserPackageName(String packageName, int userId);
+    String getDefaultBrowserPackageName(int userId);
+
     VerifierDeviceIdentity getVerifierDeviceIdentity();
 
     boolean isFirstBoot();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d5461eba..0396660 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3667,6 +3667,32 @@
     public abstract List<IntentFilter> getAllIntentFilters(String packageName);
 
     /**
+     * Get the default Browser package name for a specific user.
+     *
+     * @param userId The user id.
+     *
+     * @return the package name of the default Browser for the specified user. If the user id passed
+     *         is -1 (all users) it will return a null value.
+     *
+     * @hide
+     */
+    public abstract String getDefaultBrowserPackageName(int userId);
+
+    /**
+     * Set the default Browser package name for a specific user.
+     *
+     * @param packageName The package name of the default Browser.
+     * @param userId The user id.
+     *
+     * @return true if the default Browser for the specified user has been set,
+     *         otherwise return false. If the user id passed is -1 (all users) this call will not
+     *         do anything and just return false.
+     *
+     * @hide
+     */
+    public abstract boolean setDefaultBrowserPackageName(String packageName, int userId);
+
+    /**
      * Change the installer associated with a given package.  There are limitations
      * on how the installer package can be changed; in particular:
      * <ul>
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 11e1ccf..a0313e7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -729,37 +729,6 @@
             }
             return false;
         }
-        ArrayList<String> hosts = filter.getHostsList();
-        if (hosts.size() == 0) {
-            if (logging) {
-                Slog.d(TAG, "IntentFilter does not contain any data hosts");
-            }
-            // We still return true as this is the case of any Browser
-            return true;
-        }
-        String hostEndBase = null;
-        for (String host : hosts) {
-            String[] hostParts = host.split("\\.");
-            // Should be at minimum a host like "example.com"
-            if (hostParts.length < 2) {
-                if (logging) {
-                    Slog.d(TAG, "IntentFilter does not contain a valid data host name: " + host);
-                }
-                return false;
-            }
-            // Verify that we have the same ending domain
-            int length = hostParts.length;
-            String hostEnd = hostParts[length - 1] + hostParts[length - 2];
-            if (hostEndBase == null) {
-                hostEndBase = hostEnd;
-            }
-            if (!hostEnd.equalsIgnoreCase(hostEndBase)) {
-                if (logging) {
-                    Slog.d(TAG, "IntentFilter does not contain the same data domains");
-                }
-                return false;
-            }
-        }
         return true;
     }
 
@@ -9096,6 +9065,20 @@
         }
     }
 
+    @Override
+    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+        synchronized (mPackages) {
+            return mSettings.setDefaultBrowserPackageNameLPr(packageName, userId);
+        }
+    }
+
+    @Override
+    public String getDefaultBrowserPackageName(int userId) {
+        synchronized (mPackages) {
+            return mSettings.getDefaultBrowserPackageNameLPw(userId);
+        }
+    }
+
     /**
      * Get the "allow unknown sources" setting.
      *
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index f294b32..5429517 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageUserState;
 import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.SparseArray;
 
@@ -435,23 +436,23 @@
         userState.delete(userId);
     }
 
-    public IntentFilterVerificationInfo getIntentFilterVerificationInfo() {
+    IntentFilterVerificationInfo getIntentFilterVerificationInfo() {
         return verificationInfo;
     }
 
-    public void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
+    void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
         verificationInfo = info;
     }
 
-    public int getDomainVerificationStatusForUser(int userId) {
+    int getDomainVerificationStatusForUser(int userId) {
         return readUserState(userId).domainVerificationStatus;
     }
 
-    public void setDomainVerificationStatusForUser(int status, int userId) {
+    void setDomainVerificationStatusForUser(int status, int userId) {
         modifyUserState(userId).domainVerificationStatus = status;
     }
 
-    public void clearDomainVerificationStatusForUser(int userId) {
+    void clearDomainVerificationStatusForUser(int userId) {
         modifyUserState(userId).domainVerificationStatus =
                 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bfcc3db..45bfba1 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -170,6 +170,8 @@
     static final String TAG_CROSS_PROFILE_INTENT_FILTERS =
             "crossProfile-intent-filters";
     public static final String TAG_DOMAIN_VERIFICATION = "domain-verification";
+    public static final String TAG_DEFAULT_APPS= "default-apps";
+    public static final String TAG_DEFAULT_BROWSER= "default-browser";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_USER = "user";
@@ -185,6 +187,7 @@
     private static final String ATTR_INSTALLED = "inst";
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
     private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
+    private static final String ATTR_PACKAGE_NAME= "packageName";
 
     private final Object mLock;
 
@@ -272,7 +275,10 @@
     // names.  The packages appear everwhere else under their original
     // names.
     final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
-    
+
+    // For every user, it is used to find the package name of the default Browser App.
+    final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>();
+
     final StringBuilder mReadMessages = new StringBuilder();
 
     /**
@@ -1067,6 +1073,19 @@
         }
     }
 
+    boolean setDefaultBrowserPackageNameLPr(String packageName, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            return false;
+        }
+        mDefaultBrowserApp.put(userId, packageName);
+        writePackageRestrictionsLPr(userId);
+        return true;
+    }
+
+    String getDefaultBrowserPackageNameLPw(int userId) {
+        return (userId == UserHandle.USER_ALL) ? null : mDefaultBrowserApp.get(userId);
+    }
+
     private File getUserPackagesStateFile(int userId) {
         // TODO: Implement a cleaner solution when adding tests.
         // This instead of Environment.getUserSystemDirectory(userId) to support testing.
@@ -1232,15 +1251,25 @@
         Log.d(TAG, "Read domain verification for package:" + ivi.getPackageName());
     }
 
-    void writeDomainVerificationsLPr(XmlSerializer serializer, String packageName,
-                                     IntentFilterVerificationInfo verificationInfo)
-            throws IllegalArgumentException, IllegalStateException, IOException {
-        if (verificationInfo != null && verificationInfo.getPackageName() != null) {
-            serializer.startTag(null, TAG_DOMAIN_VERIFICATION);
-            verificationInfo.writeToXml(serializer);
-            Log.d(TAG, "Wrote domain verification for package: "
-                    + verificationInfo.getPackageName());
-            serializer.endTag(null, TAG_DOMAIN_VERIFICATION);
+    private void readDefaultAppsLPw(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_DEFAULT_BROWSER)) {
+                String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                mDefaultBrowserApp.put(userId, packageName);
+            } else {
+                String msg = "Unknown element under " +  TAG_DEFAULT_APPS + ": " +
+                        parser.getName();
+                PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                XmlUtils.skipCurrentTag(parser);
+            }
         }
     }
 
@@ -1392,6 +1421,8 @@
                     readPersistentPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
                     readCrossProfileIntentFiltersLPw(parser, userId);
+                } else if (tagName.equals(TAG_DEFAULT_APPS)) {
+                    readDefaultAppsLPw(parser, userId);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -1490,6 +1521,30 @@
         serializer.endTag(null, TAG_CROSS_PROFILE_INTENT_FILTERS);
     }
 
+    void writeDomainVerificationsLPr(XmlSerializer serializer,
+                                     IntentFilterVerificationInfo verificationInfo)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        if (verificationInfo != null && verificationInfo.getPackageName() != null) {
+            serializer.startTag(null, TAG_DOMAIN_VERIFICATION);
+            verificationInfo.writeToXml(serializer);
+            Log.d(TAG, "Wrote domain verification for package: "
+                    + verificationInfo.getPackageName());
+            serializer.endTag(null, TAG_DOMAIN_VERIFICATION);
+        }
+    }
+
+    void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        serializer.startTag(null, TAG_DEFAULT_APPS);
+        String packageName = mDefaultBrowserApp.get(userId);
+        if (!TextUtils.isEmpty(packageName)) {
+            serializer.startTag(null, TAG_DEFAULT_BROWSER);
+            serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
+            serializer.endTag(null, TAG_DEFAULT_BROWSER);
+        }
+        serializer.endTag(null, TAG_DEFAULT_APPS);
+    }
+
     void writePackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1600,6 +1655,7 @@
             writePreferredActivitiesLPr(serializer, userId, true);
             writePersistentPreferredActivitiesLPr(serializer, userId);
             writeCrossProfileIntentFiltersLPr(serializer, userId);
+            writeDefaultAppsLPr(serializer, userId);
 
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
@@ -2114,7 +2170,7 @@
         writeSigningKeySetLPr(serializer, pkg.keySetData);
         writeUpgradeKeySetsLPr(serializer, pkg.keySetData);
         writeKeySetAliasesLPr(serializer, pkg.keySetData);
-        writeDomainVerificationsLPr(serializer, pkg.name, pkg.verificationInfo);
+        writeDomainVerificationsLPr(serializer, pkg.verificationInfo);
 
         serializer.endTag(null, "package");
     }
@@ -2283,8 +2339,9 @@
                     // TODO: check whether this is okay! as it is very
                     // similar to how preferred-activities are treated
                     readCrossProfileIntentFiltersLPw(parser, 0);
-                }
-                else if (tagName.equals("updated-package")) {
+                } else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
+                    readDefaultAppsLPw(parser, 0);
+                } else if (tagName.equals("updated-package")) {
                     readDisabledSysPackageLPw(parser);
                 } else if (tagName.equals("cleaning-package")) {
                     String name = parser.getAttributeValue(null, ATTR_NAME);
@@ -4044,7 +4101,8 @@
 
     void dumpGidsLPr(PrintWriter pw, String prefix, int[] gids) {
         if (!ArrayUtils.isEmpty(gids)) {
-            pw.print(prefix); pw.print("gids="); pw.println(
+            pw.print(prefix);
+            pw.print("gids="); pw.println(
                     PackageManagerService.arrayToString(gids));
         }
     }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 79510d0..e78750c 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -764,6 +764,16 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public String getDefaultBrowserPackageName(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * @hide
      */