chromium/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded_util/WebViewPackageHelper.java

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.android_webview.nonembedded_util;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.webkit.WebView;

import org.chromium.base.ResettersForTesting;

import java.util.Locale;

/** A helper class to get info about WebView package. */
public final class WebViewPackageHelper {
    private static PackageInfo sWebViewCurrentPackageForTesting;

    /** Wrapper to mock WebView.getCurrentWebViewPackage() for testing. */
    public static PackageInfo getCurrentWebViewPackage(Context context) {
        if (sWebViewCurrentPackageForTesting != null) {
            return sWebViewCurrentPackageForTesting;
        }
        return WebView.getCurrentWebViewPackage();
    }

    /**
     * Get {@link PackageInfo} for the given {@link Context}.
     * It uses {@link Context#getPackageName()} to look up the {@link PackageInfo} object.
     */
    public static PackageInfo getContextPackageInfo(Context context) {
        try {
            return context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Check if the given context is a WebView package and if it's currently selected as system's
     * WebView implementation.
     *
     * @param context the {@link Context} to check its package.
     */
    public static boolean isCurrentSystemWebViewImplementation(Context context) {
        PackageInfo systemWebViewPackage = getCurrentWebViewPackage(context);
        if (systemWebViewPackage == null) return false;
        return context.getPackageName().equals(systemWebViewPackage.packageName);
    }

    /** Check if the system currently has a valid WebView implementation. */
    public static boolean hasValidWebViewImplementation(Context context) {
        return getCurrentWebViewPackage(context) != null;
    }

    /**
     * Loads a label for the app specified by {@code mContext}. This is designed to be consistent
     * with how the system's WebView chooser labels WebView packages (see {@code
     * com.android.settings.webview.WebViewAppPicker.WebViewAppInfo#loadLabel()} in the AOSP source
     * code).
     */
    public static CharSequence loadLabel(Context context) {
        ApplicationInfo applicationInfo = context.getApplicationInfo();
        PackageManager pm = context.getPackageManager();
        CharSequence appLabel = applicationInfo.loadLabel(pm);
        try {
            String versionName = pm.getPackageInfo(context.getPackageName(), 0).versionName;
            return String.format(Locale.US, "%s %s", appLabel, versionName);
        } catch (PackageManager.NameNotFoundException e) {
            return appLabel;
        }
    }

    /**
     * Inject a {@link PackageInfo} as the current webview package for testing. This PackageInfo
     * will be returned by {@link #getCurrentWebViewPackage}.
     */
    public static void setCurrentWebViewPackageForTesting(PackageInfo currentWebView) {
        sWebViewCurrentPackageForTesting = currentWebView;
        ResettersForTesting.register(() -> sWebViewCurrentPackageForTesting = null);
    }

    // Do not instantiate this class.
    private WebViewPackageHelper() {}
}