com.polyvi.xface.extension.inappbrowser.XInAppBrowserExt.java Source code

Java tutorial

Introduction

Here is the source code for com.polyvi.xface.extension.inappbrowser.XInAppBrowserExt.java

Source

/*
 This file was modified from or inspired by Apache Cordova.
    
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements. See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership. The ASF licenses this file
 to you 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.polyvi.xface.extension.inappbrowser;

import java.util.HashMap;
import java.util.StringTokenizer;

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

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.util.Log;

import com.polyvi.xface.app.XWhiteList;
import com.polyvi.xface.extension.XCallbackContext;
import com.polyvi.xface.extension.XExtension;
import com.polyvi.xface.extension.XExtensionResult;
import com.polyvi.xface.extension.XExtensionResult.Status;
import com.polyvi.xface.plugin.api.XIWebContext;
import com.polyvi.xface.util.XConstant;
import com.polyvi.xface.util.XFileUtils;
import com.polyvi.xface.util.XLog;
import com.polyvi.xface.view.XAppWebView;

/**
 * ?WebKit??
 */
public class XInAppBrowserExt extends XExtension implements XIBrowserListener {
    private static final String INAPPBROWSER_EXTENSION_TYPE = "InAppBrowser";
    private static final String NULL = "null";
    private static final String COMMAND_OPEN = "open";
    private static final String COMMAND_CLOSE = "close";
    private static final String COMMAND_INJECT_SCRIPT_CODE = "injectScriptCode";
    private static final String COMMAND_INJECT_SCRIPT_FILE = "injectScriptFile";
    private static final String COMMAND_INJECT_STYLE_CODE = "injectStyleCode";
    private static final String COMMAND_INJECT_STYLE_FILE = "injectStyleFile";

    private static final String BROWSER_TAG = "browser";

    protected static final String CLASS_NAME = XInAppBrowserExt.class.getSimpleName();
    /** _self ?xface? */
    private static final String SELF = "_self";
    /** _system? */
    private static final String SYSTEM = "_system";
    /** ??? */
    private static final String LOCATION = "location";

    private static final String URL_NAME = "url";

    /**  */
    private static final String LOAD_START_EVENT = "loadstart";
    /** ? */
    private static final String LOAD_STOP_EVENT = "loadstop";
    /**  */
    private static final String EXIT_EVENT = "exit";
    /**  */
    private static final String TYPE_NAME = "type";

    /** ??? */
    private boolean mIsShowLocationBar = true;
    private XCallbackContext mCallbackCtx;

    public XInAppBrowserExt() {
    }

    public XExtensionResult exec(String action, JSONArray args, XCallbackContext callbackCtx) throws JSONException {
        Status status = Status.NO_RESULT;
        String result = "";
        try {
            if (action.equals(COMMAND_OPEN)) {
                String url = args.getString(0);
                String target = args.optString(1);
                // ??null? ?nullxface??
                if (target == null || target.equals("") || target.equals(NULL)) {
                    target = SELF;
                }
                HashMap<String, Boolean> features = parseFeature(args.optString(2));
                url = updateUrl(url, mWebContext.getApplication().getBaseUrl());
                if (!checkUrl(url)) {
                    XLog.e(CLASS_NAME, "Malformed url = " + url);
                    return new XExtensionResult(Status.MALFORMED_URL_EXCEPTION);
                }
                if (!isUrlAllowedLoad(url)) {
                    mExtensionContext.getSystemContext().toast("Network is not available for load:" + url);
                    return new XExtensionResult(Status.ERROR);
                }
                // SELF?xface?
                if (SELF.equals(target)) {
                    // ??Url
                    XWhiteList whiteList = this.mWebContext.getApplication().getAppInfo().getWhiteList();
                    if (url.startsWith("file://") || url.startsWith("javascript:")
                            || (null != whiteList && whiteList.isUrlWhiteListed(url))) {
                        loadUrlInAppView(mWebContext.getApplication().getView(), url);
                    }
                }
                // SYSTEM?
                else if (SYSTEM.equals(target)) {
                    loadUrlInSysBrowser(mWebContext.getApplication().getView(), url);
                    result = "";
                }
                // BLANK - or anything else
                else {
                    result = loadUrlInAppBrowser(mWebContext, url, features, callbackCtx);
                }
            } else if (action.equals(COMMAND_CLOSE)) {
                getBrowerOfApp(mWebContext).closeDialog();
            } else if (action.equals(COMMAND_INJECT_SCRIPT_CODE)) {
                injectScriptCode(args.getString(0), args.optBoolean(1), callbackCtx);
            } else if (action.equals(COMMAND_INJECT_SCRIPT_FILE)) {
                injectScriptFile(args.getString(0), args.optBoolean(1), callbackCtx);
            } else if (action.equals(COMMAND_INJECT_STYLE_CODE)) {
                injectStyleCode(args.getString(0), args.optBoolean(1), callbackCtx);
            } else if (action.equals(COMMAND_INJECT_STYLE_FILE)) {
                injectStyleFile(args.getString(0), args.optBoolean(1), callbackCtx);
            } else {
                status = Status.INVALID_ACTION;
            }
            return new XExtensionResult(status, result);
        } catch (JSONException e) {
            return new XExtensionResult(Status.JSON_EXCEPTION);
        }
    }

    private boolean checkUrl(String url) {
        //file?
        if (url.startsWith(XConstant.FILE_SCHEME)) {
            return XFileUtils.fileExists(getContext(), url);
        }

        //?file??
        return true;
    }

    /**
     * ?htpp???
     * @param url ??url
     * @return ?true?false
     */
    private boolean isUrlAllowedLoad(String url) {
        //http??
        if (url.startsWith(XConstant.HTTP_SCHEME) || url.startsWith(XConstant.HTTPS_SCHEME)) {
            ConnectivityManager mConnectivityManager = (ConnectivityManager) getContext()
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null) {
                return mNetworkInfo.isAvailable();
            } else {
                return false;
            }
        }
        return true;
    }

    private XInAppBrowser getBrowerOfApp(XIWebContext webContext) {
        return (XInAppBrowser) webContext.getApplication().getData(BROWSER_TAG);
    }

    /**
     * AppViewUrl
     *
     * @param appView
     * @param url
     */
    private void loadUrlInAppView(XAppWebView appView, String url) {
        appView.loadUrl(url, false, false, getContext());
    }

    /**
     * ?Url
     *
     * @param appView
     * @param url
     */
    private void loadUrlInSysBrowser(XAppWebView appView, String url) {
        appView.loadUrl(url, true, false, getContext());
    }

    public String getName() {
        return INAPPBROWSER_EXTENSION_TYPE;
    }

    /**
     * ?
     *
     * @param optString
     *            ?
     * @return
     */
    private HashMap<String, Boolean> parseFeature(String optString) {
        if (optString.equals(NULL)) {
            return null;
        } else {
            HashMap<String, Boolean> map = new HashMap<String, Boolean>();
            StringTokenizer features = new StringTokenizer(optString, ",");
            StringTokenizer option;
            while (features.hasMoreElements()) {
                option = new StringTokenizer(features.nextToken(), "=");
                if (option.hasMoreElements()) {
                    String key = option.nextToken();
                    Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
                    map.put(key, value);
                }
            }
            return map;
        }
    }

    /**
     * Url?
     *
     * @param url
     * @return
     */
    private String updateUrl(String url, String baseUrl) {
        Uri newUrl = Uri.parse(url);
        if (newUrl.isRelative()) {
            url = baseUrl.substring(0, baseUrl.lastIndexOf("/") + 1) + url;
        }
        return url;
    }

    /**
     * ?URL
     *
     * @param webContext
     *            ???View
     * @param url
     *            ?URL
     * @param features
     *            
     * @param isCustomed
     *            ?InAppBrowser
     * @return
     */
    private String loadUrlInAppBrowser(final XIWebContext webContext, final String url,
            HashMap<String, Boolean> features, XCallbackContext callbackCtx) {
        mCallbackCtx = callbackCtx;
        // ??
        mIsShowLocationBar = true;
        if (features != null) {
            mIsShowLocationBar = features.get(LOCATION).booleanValue();
        }
        // InAppBrowserView
        Runnable runnable = new Runnable() {
            public void run() {
                XIBrowserBuilder browserBuilder = createBrowserBuilder(url, webContext);
                XInAppBrowser browser = browserBuilder.buildBrowser();
                webContext.getApplication().setData("browser", browser);
                browser.show();
            }
        };
        mExtensionContext.getSystemContext().runOnUiThread(runnable);
        return "";
    }

    private XIBrowserBuilder createBrowserBuilder(String url, XIWebContext webContext) {
        return new XInAppBrowser(getContext(), this, url, webContext, mIsShowLocationBar);
    }

    @Override
    public void onLoadFinished(String url, XIWebContext webContext) {
        JSONObject obj = new JSONObject();
        try {
            obj.put(TYPE_NAME, LOAD_STOP_EVENT);
            obj.put(URL_NAME, url);
            sendUpdate(obj, true, webContext);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onLoadStart(String url, XIWebContext webContext) {
        JSONObject obj = new JSONObject();
        try {
            obj.put(TYPE_NAME, LOAD_START_EVENT);
            obj.put(URL_NAME, url);
            sendUpdate(obj, true, webContext);
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onDismiss(XIWebContext webContext) {
        try {
            JSONObject obj = new JSONObject();
            obj.put(TYPE_NAME, EXIT_EVENT);
            sendUpdate(obj, false, webContext);
            mCallbackCtx = null;
            webContext.getApplication().removeData(BROWSER_TAG);
        } catch (JSONException e) {
            Log.d(CLASS_NAME, e.getMessage());
        }
    }

    @Override
    public void onPageStarted() {
        mCallbackCtx = null;
    }

    /**
     * js
     *
     * @param obj
     *            json
     */
    private void sendUpdate(JSONObject obj, boolean keepCallback, XIWebContext webContext) {
        XExtensionResult result = new XExtensionResult(Status.OK, obj);
        result.setKeepCallback(keepCallback);
        if (null != mCallbackCtx) {
            mCallbackCtx.sendExtensionResult(result);
        }
    }

    public void sendAsyncResult(String result) {
    }

    /**
     * ?
     *
     * @param action
     *            ?
     * @return  true ? false
     */
    public boolean isAsync(String action) {
        return true;
    }

    /**
     * JS?
     * @param source:??
     * @param isCallbackExist??
     * @param callbackCtx
     */
    private void injectScriptCode(String source, boolean isCallbackExist, XCallbackContext callbackCtx) {
        String jsWrapper = null;
        if (isCallbackExist) {
            jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'xface-iab://%s')",
                    callbackCtx.getCallbackId());
        }
        injectSource(source, jsWrapper, callbackCtx);
    }

    /**
     * JS
     * @param source:??
     * @param isCallbackExist??
     * @param callbackCtx
     */
    private void injectScriptFile(String source, boolean isCallbackExist, XCallbackContext callbackCtx) {
        String jsWrapper;
        if (isCallbackExist) {
            jsWrapper = String.format(
                    "(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'xface-iab://%s'); }; d.body.appendChild(c); })(document)",
                    callbackCtx.getCallbackId());
        } else {
            jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
        }
        injectSource(source, jsWrapper, callbackCtx);
    }

    /**
     * CSS?
     * @param source:??
     * @param isCallbackExist??
     * @param callbackCtx
     */
    private void injectStyleCode(String source, boolean isCallbackExist, XCallbackContext callbackCtx) {
        String jsWrapper;
        if (isCallbackExist) {
            jsWrapper = String.format(
                    "(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'xface-iab://%s');})(document)",
                    callbackCtx.getCallbackId());
        } else {
            jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
        }
        injectSource(source, jsWrapper, callbackCtx);
    }

    /**
     * CSS
     * @param source:??
     * @param isCallbackExist??
     * @param callbackCtx
     */
    private void injectStyleFile(String source, boolean isCallbackExist, XCallbackContext callbackCtx) {
        String jsWrapper;
        if (isCallbackExist) {
            jsWrapper = String.format(
                    "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'xface-iab://%s');})(document)",
                    callbackCtx.getCallbackId());
        } else {
            jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
        }
        injectSource(source, jsWrapper, callbackCtx);
    }

    /**
     * scriptcss
     * @param source: ??
     * @param jsWrapper: ???
     * @param callbackCtx 
     */
    private void injectSource(String source, String jsWrapper, XCallbackContext callbackCtx) {
        XInAppBrowser InAppBrowser = getBrowerOfApp(mWebContext);
        InAppBrowser.setInjectCallbackContext(callbackCtx);
        InAppBrowser.injectDeferredObject(source, jsWrapper);
    }
}