com.gabfiocchi.cordova.plugin.browsertab.BrowserTab.java Source code

Java tutorial

Introduction

Here is the source code for com.gabfiocchi.cordova.plugin.browsertab.BrowserTab.java

Source

/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gabfiocchi.cordova.plugin.browsertab;

import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Color;
import android.net.Uri;
import android.support.customtabs.CustomTabsIntent;
import android.util.Log;

import java.util.Iterator;
import java.util.List;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Cordova plugin which provides the ability to launch a URL in an
 * in-app browser tab. On Android, this means using the custom tabs support
 * library, if a supporting browser (e.g. Chrome) is available on the device.
 */
public class BrowserTab extends CordovaPlugin {

    public static final int RC_OPEN_URL = 101;

    private static final String LOG_TAG = "BrowserTab";

    /**
     * The service we expect to find on a web browser that indicates it supports custom tabs.
     */
    private static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";

    private boolean mFindCalled = false;
    private String mCustomTabsBrowser;
    private String toolbarColor = "#ffffff";

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
        Log.d(LOG_TAG, "executing " + action);
        if ("isAvailable".equals(action)) {
            isAvailable(callbackContext);
        } else if ("openUrl".equals(action)) {
            openUrl(args, callbackContext);
        } else if ("close".equals(action)) {
            // close is a NOP on Android
            return true;
        } else {
            return false;
        }

        return true;
    }

    private void isAvailable(CallbackContext callbackContext) {
        String browserPackage = findCustomTabBrowser();
        Log.d(LOG_TAG, "browser package: " + browserPackage);
        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, browserPackage != null));
    }

    private void openUrl(JSONArray args, CallbackContext callbackContext) {
        if (args.length() < 1) {
            Log.d(LOG_TAG, "openUrl: no url argument received");
            callbackContext.error("URL argument missing");
            return;
        }

        String urlStr;
        try {
            urlStr = args.getString(0);
        } catch (JSONException e) {
            Log.d(LOG_TAG, "openUrl: failed to parse url argument");
            callbackContext.error("URL argument is not a string");
            return;
        }

        JSONObject themeableArgs;
        try {
            themeableArgs = new JSONObject(args.optString(1));
            if (themeableArgs.getString("toolbarColor") != null) {
                Log.d(LOG_TAG, "soy arg " + args.optString(1));
                toolbarColor = themeableArgs.getString("toolbarColor");
            }
        } catch (JSONException e) {
            Log.d(LOG_TAG, "openUrl themeableArgs: failed to parse theme parameters" + args);
        }

        String customTabsBrowser = findCustomTabBrowser();
        if (customTabsBrowser == null) {
            Log.d(LOG_TAG, "openUrl: no in app browser tab available");
            callbackContext.error("no in app browser tab implementation available");
        }

        CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
        builder.setToolbarColor(Color.parseColor(toolbarColor));
        builder.addDefaultShareMenuItem();
        Intent customTabsIntent = builder.build().intent;
        customTabsIntent.setData(Uri.parse(urlStr));
        customTabsIntent.setPackage(mCustomTabsBrowser);
        cordova.getActivity().startActivity(customTabsIntent);

        Log.d(LOG_TAG, "in app browser call dispatched");
        callbackContext.success();
    }

    private String findCustomTabBrowser() {
        if (mFindCalled) {
            return mCustomTabsBrowser;
        }

        PackageManager pm = cordova.getActivity().getPackageManager();
        Intent webIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
        List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(webIntent,
                PackageManager.GET_RESOLVED_FILTER);

        for (ResolveInfo info : resolvedActivityList) {
            if (!isFullBrowser(info)) {
                continue;
            }

            if (hasCustomTabWarmupService(pm, info.activityInfo.packageName)) {
                mCustomTabsBrowser = info.activityInfo.packageName;
                break;
            }
        }

        mFindCalled = true;
        return mCustomTabsBrowser;
    }

    private boolean isFullBrowser(ResolveInfo resolveInfo) {
        // The filter must match ACTION_VIEW, CATEGORY_BROWSEABLE, and at least one scheme,
        if (!resolveInfo.filter.hasAction(Intent.ACTION_VIEW)
                || !resolveInfo.filter.hasCategory(Intent.CATEGORY_BROWSABLE)
                || resolveInfo.filter.schemesIterator() == null) {
            return false;
        }

        // The filter must not be restricted to any particular set of authorities
        if (resolveInfo.filter.authoritiesIterator() != null) {
            return false;
        }

        // The filter must support both HTTP and HTTPS.
        boolean supportsHttp = false;
        boolean supportsHttps = false;
        Iterator<String> schemeIter = resolveInfo.filter.schemesIterator();
        while (schemeIter.hasNext()) {
            String scheme = schemeIter.next();
            supportsHttp |= "http".equals(scheme);
            supportsHttps |= "https".equals(scheme);

            if (supportsHttp && supportsHttps) {
                return true;
            }
        }

        // at least one of HTTP or HTTPS is not supported
        return false;
    }

    private boolean hasCustomTabWarmupService(PackageManager pm, String packageName) {
        Intent serviceIntent = new Intent();
        serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
        serviceIntent.setPackage(packageName);
        return (pm.resolveService(serviceIntent, 0) != null);
    }
}