Index: chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java |
index 5477da8e5d919194e7702f6de8d1c44b736d213d..ade647d7071acb690a9af43f7001d2414ec7e9f5 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java |
@@ -6,30 +6,78 @@ package org.chromium.chrome.browser; |
import android.content.Context; |
import android.content.Intent; |
+import android.content.pm.ApplicationInfo; |
import android.content.pm.PackageManager; |
import android.content.pm.ResolveInfo; |
import android.net.Uri; |
import android.os.AsyncTask; |
+import android.support.annotation.IntDef; |
+import android.text.TextUtils; |
import org.chromium.base.BuildInfo; |
import org.chromium.base.ContextUtils; |
+import org.chromium.base.library_loader.LibraryProcessType; |
+import org.chromium.base.metrics.RecordHistogram; |
import org.chromium.chrome.R; |
import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
+import org.chromium.content.browser.BrowserStartupController; |
import java.util.ArrayList; |
+import java.util.HashSet; |
+import java.util.List; |
+import java.util.Set; |
import java.util.concurrent.ExecutionException; |
+import java.util.concurrent.RejectedExecutionException; |
/** |
* A utility class for querying information about the default browser setting. |
*/ |
-public class DefaultBrowserInfo { |
+public final class DefaultBrowserInfo { |
private static final String SAMPLE_URL = "https://www.madeupdomainforcheck123.com/"; |
+ /** |
+ * A list of potential default browser states. To add a type to this list please update |
+ * MobileDefaultBrowserState in histograms.xml and make sure to keep this list in sync. |
+ * Additions should be treated as APPEND ONLY to keep the UMA metric semantics the same over |
+ * time. |
+ */ |
+ @IntDef({ |
+ MobileDefaultBrowserState.NO_DEFAULT, |
+ MobileDefaultBrowserState.CHROME_SYSTEM_DEFAULT, |
+ MobileDefaultBrowserState.CHROME_INSTALLED_DEFAULT, |
+ MobileDefaultBrowserState.OTHER_SYSTEM_DEFAULT, |
+ MobileDefaultBrowserState.OTHER_INSTALLED_DEFAULT, |
+ |
+ MobileDefaultBrowserState.BOUNDARY, |
+ }) |
+ private @interface MobileDefaultBrowserState { |
+ int NO_DEFAULT = 0; |
+ int CHROME_SYSTEM_DEFAULT = 1; |
+ int CHROME_INSTALLED_DEFAULT = 2; |
+ int OTHER_SYSTEM_DEFAULT = 3; |
+ int OTHER_INSTALLED_DEFAULT = 4; |
+ int BOUNDARY = 5; |
+ } |
+ |
+ /** |
+ * Helper class for passing information about the system's default browser settings back from a |
+ * worker task. |
+ */ |
+ private static class DefaultInfo { |
+ public boolean isChromeDefault; |
+ public boolean isDefaultSystem; |
+ public boolean hasDefault; |
+ public int browserCount; |
+ } |
+ |
/** A lock to synchronize background tasks to retrieve browser information. */ |
private static final Object sDirCreationLock = new Object(); |
private static AsyncTask<Void, Void, ArrayList<String>> sDefaultBrowserFetcher; |
+ /** Don't instantiate me. */ |
+ private DefaultBrowserInfo() {} |
+ |
/** |
* Initialize an AsyncTask for getting menu title of opening a link in default browser. |
*/ |
@@ -102,4 +150,89 @@ public class DefaultBrowserInfo { |
R.string.menu_open_in_product_default); |
} |
} |
+ |
+ /** |
+ * Log statistics about the current default browser to UMA. |
+ */ |
+ public static void logDefaultBrowserStats() { |
+ assert BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) |
+ .isStartupSuccessfullyCompleted(); |
+ |
+ try { |
+ new AsyncTask<Context, Void, DefaultInfo>() { |
+ @Override |
+ protected DefaultInfo doInBackground(Context... params) { |
+ Context context = params[0]; |
+ |
+ PackageManager pm = context.getPackageManager(); |
+ |
+ Intent intent = new Intent(Intent.ACTION_VIEW); |
+ intent.setData(Uri.parse(SAMPLE_URL)); |
+ |
+ DefaultInfo info = new DefaultInfo(); |
+ |
+ // Query the default handler first. |
+ ResolveInfo defaultRi = pm.resolveActivity(intent, 0); |
+ if (defaultRi != null && defaultRi.match != 0) { |
+ info.hasDefault = true; |
+ info.isChromeDefault = isSamePackage(context, defaultRi); |
+ info.isDefaultSystem = isSystemPackage(defaultRi); |
+ } |
+ |
+ // Query all other intent handlers. |
+ Set<String> uniquePackages = new HashSet<>(); |
+ List<ResolveInfo> ris = |
+ pm.queryIntentActivities(intent, PackageManager.MATCH_ALL); |
+ for (ResolveInfo ri : ris) { |
+ uniquePackages.add(ri.activityInfo.applicationInfo.packageName); |
+ } |
+ |
+ info.browserCount = uniquePackages.size(); |
+ |
+ return info; |
+ } |
+ |
+ @Override |
+ protected void onPostExecute(DefaultInfo info) { |
+ if (info == null) return; |
+ |
+ RecordHistogram.recordCount100Histogram( |
+ getDefaultBrowserCountUmaName(info), info.browserCount); |
+ RecordHistogram.recordEnumeratedHistogram("Mobile.DefaultBrowser.State", |
+ getDefaultBrowserUmaState(info), MobileDefaultBrowserState.BOUNDARY); |
+ } |
+ } |
+ .executeOnExecutor( |
+ AsyncTask.THREAD_POOL_EXECUTOR, ContextUtils.getApplicationContext()); |
+ } catch (RejectedExecutionException ex) { |
+ // Fail silently here since this is not a critical task. |
+ } |
+ } |
+ |
+ private static String getDefaultBrowserCountUmaName(DefaultInfo info) { |
+ if (!info.hasDefault) return "Mobile.DefaultBrowser.BrowserCount.NoDefault"; |
+ if (info.isChromeDefault) return "Mobile.DefaultBrowser.BrowserCount.ChromeDefault"; |
+ return "Mobile.DefaultBrowser.BrowserCount.OtherDefault"; |
+ } |
+ |
+ private static @MobileDefaultBrowserState int getDefaultBrowserUmaState(DefaultInfo info) { |
+ if (!info.hasDefault) return MobileDefaultBrowserState.NO_DEFAULT; |
+ |
+ if (info.isChromeDefault) { |
+ if (info.isDefaultSystem) return MobileDefaultBrowserState.CHROME_SYSTEM_DEFAULT; |
+ return MobileDefaultBrowserState.CHROME_INSTALLED_DEFAULT; |
+ } |
+ |
+ if (info.isDefaultSystem) return MobileDefaultBrowserState.OTHER_SYSTEM_DEFAULT; |
+ return MobileDefaultBrowserState.OTHER_INSTALLED_DEFAULT; |
+ } |
+ |
+ private static boolean isSamePackage(Context context, ResolveInfo info) { |
+ return TextUtils.equals( |
+ context.getPackageName(), info.activityInfo.applicationInfo.packageName); |
+ } |
+ |
+ private static boolean isSystemPackage(ResolveInfo info) { |
+ return (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; |
+ } |
} |