앱케이크_appcake_하이브리드앱제작_Admin.png

/*
1."yellowin camera-chooser" 라는 주석을 찾아서 모두적용.
2.cordova-plugin-camera 설치.
3.AndroidManist.xml 아래 추가(없는경우)

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    <uses-feature android:name="android.hardware.camera.front" android:required="false" />
    
4.res/xml/camera_provider_paths.xml 아래로 수정

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="<http://schemas.android.com/apk/res/android>">
    <cache-path name="cache" path="/" />
</paths>

5.기타
- 웹소스의 input file태그에 아래처럼 capture 속성이 꼭 있어야함. 없다면 기존 일반첨부기능으로 동작함.
<input type="file" capture="image">
*/

package org.apache.cordova.inappbrowser;

import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Looper;
import android.os.Parcelable;
import android.provider.Browser;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.Color;
import android.net.http.SslError;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.InputType;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.webkit.CookieManager;
import android.webkit.HttpAuthHandler;
import android.webkit.JavascriptInterface;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.DownloadListener;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.Config;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaHttpAuthHandler;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginManager;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import org.json.JSONObject;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.cordova.inappbrowser.InAppBrowserDialog;

//yellowin yellowin videoview 풀스크린 처리 관련 라이브러리
import android.widget.FrameLayout;
import android.content.pm.ActivityInfo;
import android.util.Log;

// yellowin yellowin 파일 다중 선택 (selectMultiple)
import android.app.Activity;

import com.amospro.app.R;

import android.annotation.SuppressLint;
import android.view.View;

//yellowin yellowin bottomnavigationviewex 추가 라이브러리 start
import com.ittianyu.bottomnavigationviewex.BottomNavigationViewEx;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
//yellowin yellowin bottomnavigationviewex 추가 라이브러리 end

import android.view.Menu; // yellowin toolbar menu 선택 
import android.view.MenuItem; // yellowin toolbar
import android.view.MotionEvent; //yellowin toolbar

// //yellowin yellowin 배지 연동 - start
// import q.rorbin.badgeview.Badge;
// import q.rorbin.badgeview.QBadgeView;
// //yellowin yellowin 배지 연동 - end

//yellowin yellowin swipeRefreshLayout
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import android.content.DialogInterface; // yellowin yellowin window.open
import android.os.Handler;
import android.app.AlertDialog;
import android.webkit.JsResult;
import static android.os.Looper.getMainLooper;
import android.webkit.WebResourceError;

//yellowin new 새창처리 - start
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
//yellowin new 새창처리 - end

import java.io.UnsupportedEncodingException; //yellowin url decoding 추가
import java.net.URLDecoder;
import java.net.URLEncoder;

**//yellowin camera-chooser 추가 - start**
import android.Manifest;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import static android.app.Activity.RESULT_OK;
import static android.graphics.ImageFormat.JPEG;
import android.media.MediaScannerConnection;
import android.provider.MediaStore;
import org.apache.cordova.BuildHelper;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
**//yellowin camera-chooser 추가 - end**

//yellowin yellowin 보안처리 - start
import android.os.Debug;
import android.content.pm.ApplicationInfo;

import com.amospro.app.MainActivity;
import com.amospro.app.R;
import com.amospro.app.RootUtil;
import android.app.AlertDialog;
import android.content.DialogInterface;
import com.initialxy.cordova.themeablebrowser.ThemeableBrowser;
//yellowin yellowin 보안처리 - end

@SuppressLint("SetJavaScriptEnabled")
public class InAppBrowser extends CordovaPlugin {

    private static final String NULL = "null";
    protected static final String LOG_TAG = "InAppBrowser";
    private static final String SELF = "_self";
    private static final String SYSTEM = "_system";
    private static final String EXIT_EVENT = "exit";
    private static final String LOCATION = "location";
    private static final String ZOOM = "zoom";
    private static final String HIDDEN = "hidden";
    private static final String LOAD_START_EVENT = "loadstart";
    private static final String LOAD_STOP_EVENT = "loadstop";
    private static final String LOAD_ERROR_EVENT = "loaderror";
    private static final String DOWNLOAD_EVENT = "download";
    private static final String MESSAGE_EVENT = "message";
    private static final String CLEAR_ALL_CACHE = "clearcache";
    private static final String CLEAR_SESSION_CACHE = "clearsessioncache";
    private static final String HARDWARE_BACK_BUTTON = "hardwareback";
    private static final String MEDIA_PLAYBACK_REQUIRES_USER_ACTION = "mediaPlaybackRequiresUserAction";
    private static final String SHOULD_PAUSE = "shouldPauseOnSuspend";
    private static final Boolean DEFAULT_HARDWARE_BACK = true;
    private static final String USER_WIDE_VIEW_PORT = "useWideViewPort";
    private static final String TOOLBAR_COLOR = "toolbarcolor";
    private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
    private static final String CLOSE_BUTTON_COLOR = "closebuttoncolor";
    private static final String LEFT_TO_RIGHT = "lefttoright";
    private static final String HIDE_NAVIGATION = "hidenavigationbuttons";
    private static final String NAVIGATION_COLOR = "navigationbuttoncolor";
    private static final String HIDE_URL = "hideurlbar";
    private static final String FOOTER = "footer";
    private static final String FOOTER_COLOR = "footercolor";
    private static final String BEFORELOAD = "beforeload";
    private static final String FULLSCREEN = "fullscreen";

    private static final int TOOLBAR_HEIGHT = 48;

    private static final List customizableOptions = Arrays.asList(CLOSE_BUTTON_CAPTION, TOOLBAR_COLOR, NAVIGATION_COLOR, CLOSE_BUTTON_COLOR, FOOTER_COLOR);

    private InAppBrowserDialog dialog;
    private WebView inAppWebView;

    private WebView newWebView;
    private EditText edittext;
    private CallbackContext callbackContext;
    private boolean showLocationBar = true;
    private boolean showZoomControls = true;
    private boolean openWindowHidden = false;
    private boolean clearAllCache = false;
    private boolean clearSessionCache = false;
    private boolean hadwareBackButton = true;
    private boolean mediaPlaybackRequiresUserGesture = false;
    private boolean shouldPauseInAppBrowser = false;
    private boolean useWideViewPort = true;
    private ValueCallback<Uri[]> mUploadCallback;
    private final static int FILECHOOSER_REQUESTCODE = 1;
    private String closeButtonCaption = "";
    private String closeButtonColor = "";
    private boolean leftToRight = false;
    private int toolbarColor = android.graphics.Color.LTGRAY;
    private boolean hideNavigationButtons = false;
    private String navigationButtonColor = "";
    private boolean hideUrlBar = false;
    private boolean showFooter = false;
    private String footerColor = "";
    private String beforeload = "";
    private boolean fullscreen = true;
    private String[] allowedSchemes;
    private InAppBrowserClient currentClient;

    // yellowin yellowin videoview 풀스크린 - 비디오 풀스크린 레이아웃변수
    private FrameLayout mVideoview;

    private BottomNavigationViewEx bnve; // 하단툴바메뉴
    // yellowin yellowin toolbar start
    // private BottomBar bottomBar;
    private View tabView1;
    private View tabView2;

    private int tabView1_flag = 1;
    private int tabView2_flag = 1;

    private String cur_url = "first";
    private String prv_url = "";
    // yellowin yellowin toolbar end

    // // yellowin yellowin toolbar 배지 연동 - start
    // Badge mBadge1;
    // Badge mBadge2;
    // Badge mBadge3;
    // Badge mBadge4;
    // Badge mBadge5;
    // // yellowin yellowin toolbar 배지 연동 - end

    // yellowin yellowin window.open - yellowin add2
    private boolean isFullscreen = false;
    private InAppBrowserDialog dialog_child;

    // yellowin new 새창처리 - start
    private Window window_child;
    // yellowin new 새창처리 - end

    //yellowin yellowin swipeRefreshLayout
    private SwipeRefreshLayout swipeRefreshLayout;

    **// yellowin camera-chooser 추가 - start**
    private Uri cameraImageUri = null;
    public ValueCallback<Uri> filePathCallbackNormal;
    public ValueCallback<Uri[]> filePathCallbackLollipop;
    public final static int FILECHOOSER_NORMAL_REQ_CODE = 2001;
    public final static int FILECHOOSER_LOLLIPOP_REQ_CODE = 2002;

    private static final int JPEG = 0; // Take a picture of type JPEG
    private static final int PNG = 1; // Take a picture of type PNG
    private static final String JPEG_TYPE = "jpg";
    private static final String PNG_TYPE = "png";
    private static final String JPEG_EXTENSION = "." + JPEG_TYPE;
    private static final String PNG_EXTENSION = "." + PNG_TYPE;
    private static final String PNG_MIME_TYPE = "image/png";
    private static final String JPEG_MIME_TYPE = "image/jpeg";
    private static final String HEIC_MIME_TYPE = "image/heic";
    private static final String GET_PICTURE = "Get Picture";
    private static final String GET_VIDEO = "Get Video";
    private static final String GET_All = "Get All";
    private static final String CROPPED_URI_KEY = "croppedUri";
    private static final String IMAGE_URI_KEY = "imageUri";
    private static final String IMAGE_FILE_PATH_KEY = "imageFilePath";

    private static final String TAKE_PICTURE_ACTION = "takePicture";

    public static final int PERMISSION_DENIED_ERROR = 20;
    public static final int TAKE_PIC_SEC = 0;
    public static final int SAVE_TO_ALBUM_SEC = 1;

    private static final String TIME_FORMAT = "yyyyMMdd_HHmmss";

    private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression,
                          // 100=compress of max quality)
    private int targetWidth; // desired width of the image
    private int targetHeight; // desired height of the image
    private Uri imageUri; // Uri of captured image
    private String imageFilePath; // File where the image is stored
    private int encodingType; // Type of encoding to use
    private int mediaType; // What type of media to retrieve
    private int destType; // Source type (needs to be saved for the permission handling)
    private int srcType; // Destination type (needs to be saved for permission handling)
    private boolean saveToPhotoAlbum; // Should the picture be saved to the device's photo album
    private boolean correctOrientation; // Should the pictures orientation be corrected
    private boolean orientationCorrected; // Has the picture's orientation been corrected
    private boolean allowEdit; // Should we allow the user to crop the image.

    private int numPics;

    private MediaScannerConnection conn; // Used to update gallery app with newly-written files
    private Uri scanMe; // Uri of image to be added to content store
    private Uri croppedUri;
    private String croppedFilePath;
    // private ExifHelper exifData; // Exif data from source
    private String applicationId;

    private static final int CAMERA_PERMISSION_REQUEST_CODE = 1001;
    **// yellowin camera-chooser 추가 - end**

    //yellowin yellowin 보안처리 - start

    private String detectDebugger_val = "false";
    private String detect_threadCpuTimeNanos_val = "false";

    // ThemeableBrowser 인스턴스를 저장하기 위한 정적 참조 변수
    private static InAppBrowser instance;

    //임시URL인경우 2, 실url이면 1
    private String service_flag = "1";

    // 생성자 또는 초기화 블록에서 인스턴스를 할당
    public InAppBrowser() {
        instance = this;
    }

    // 전역적으로 ThemeableBrowser 인스턴스에 접근하여 닫는 메소드
    public static void closeGlobalInstance() {
//        if (instance != null && instance.webView != null) {
//            instance.closeDialog(); // closeDialog()는 ThemeableBrowser 내에서 대화 상자를 닫는 기존 메소드라고 가정
//        }
        if (instance != null && instance.webView != null) {
            Activity activity = instance.cordova.getActivity();

            // UI 스레드에서 대화 상자 닫기
            if (activity != null) {
                activity.runOnUiThread(() -> {
                    if (!activity.isFinishing() && !activity.isDestroyed()) {
                        instance.closeDialog();  // closeDialog를 안전하게 실행
                    }
                });
            }
        }
    }

    //- debugbble 속성 탐지
    public static boolean isDebuggable(Context context){
        //디버그모드로 빌드된 앱을 실행했는지 체크
        Log.d("","yellowin Security This device isDebuggable() : " + ((context.getApplicationContext().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0));
        return ((context.getApplicationContext().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
//        return false;
    }

    //- 디버거 연결 여부 탐지
    public static boolean detectDebugger() {

        Log.d("","yellowin Security This device detectDebugger() : " + Debug.isDebuggerConnected() + " | " + Debug.waitingForDebugger());

        if(Debug.isDebuggerConnected() || Debug.waitingForDebugger()){
            return true;
        }else{
            return false;
        }
//        return Debug.isDebuggerConnected() || Debug.waitingForDebugger();
//        return Debug.isDebuggerConnected();
    }

    //- 디버깅(시간에 따른) 감지
    static boolean detect_threadCpuTimeNanos(){
        long start = Debug.threadCpuTimeNanos();

        for(int i=0; i<10000000; ++i)
            continue;

        long stop = Debug.threadCpuTimeNanos();

        if(stop - start < 100000000) {
            Log.d("","yellowin Security This device detect_threadCpuTimeNanos() : false");
            return false;
        }
        else {

            Log.d("","yellowin Security This device detect_threadCpuTimeNanos() : true");

            return true;
        }
    }

    //yellowin yellowin 보안처리 - end

    /**
     * Executes the request and returns PluginResult.
     *
     * @param action the action to execute.
     * @param args JSONArry of arguments for the plugin.
     * @param callbackContext the callbackContext used when calling back into JavaScript.
     * @return A PluginResult object with a status and message.
     */
    public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
        if (action.equals("open")) {
            this.callbackContext = callbackContext;
            final String url = args.getString(0);
            String t = args.optString(1);
            if (t == null || t.equals("") || t.equals(NULL)) {
                t = SELF;
            }
            final String target = t;
            final HashMap<String, String> features = parseFeature(args.optString(2));

            LOG.d(LOG_TAG, "target = " + target);

            this.cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    String result = "";
                    // SELF
                    if (SELF.equals(target)) {
                        LOG.d(LOG_TAG, "in self");
                        /* This code exists for compatibility between 3.x and 4.x versions of Cordova.
                         * Previously the Config class had a static method, isUrlWhitelisted(). That
                         * responsibility has been moved to the plugins, with an aggregating method in
                         * PluginManager.
                         */
                        Boolean shouldAllowNavigation = null;
                        if (url.startsWith("javascript:")) {
                            shouldAllowNavigation = true;
                        }
                        if (shouldAllowNavigation == null) {
                            try {
                                Method iuw = Config.class.getMethod("isUrlWhiteListed", String.class);
                                shouldAllowNavigation = (Boolean)iuw.invoke(null, url);
                            } catch (NoSuchMethodException e) {
                                LOG.d(LOG_TAG, e.getLocalizedMessage());
                            } catch (IllegalAccessException e) {
                                LOG.d(LOG_TAG, e.getLocalizedMessage());
                            } catch (InvocationTargetException e) {
                                LOG.d(LOG_TAG, e.getLocalizedMessage());
                            }
                        }
                        if (shouldAllowNavigation == null) {
                            try {
                                Method gpm = webView.getClass().getMethod("getPluginManager");
                                PluginManager pm = (PluginManager)gpm.invoke(webView);
                                Method san = pm.getClass().getMethod("shouldAllowNavigation", String.class);
                                shouldAllowNavigation = (Boolean)san.invoke(pm, url);
                            } catch (NoSuchMethodException e) {
                                LOG.d(LOG_TAG, e.getLocalizedMessage());
                            } catch (IllegalAccessException e) {
                                LOG.d(LOG_TAG, e.getLocalizedMessage());
                            } catch (InvocationTargetException e) {
                                LOG.d(LOG_TAG, e.getLocalizedMessage());
                            }
                        }
                        // load in webview
                        if (Boolean.TRUE.equals(shouldAllowNavigation)) {
                            LOG.d(LOG_TAG, "loading in webview");
                            webView.loadUrl(url);
                        }
                        //Load the dialer
                        else if (url.startsWith(WebView.SCHEME_TEL))
                        {
                            try {
                                LOG.d(LOG_TAG, "loading in dialer");
                                Intent intent = new Intent(Intent.ACTION_DIAL);
                                intent.setData(Uri.parse(url));
                                cordova.getActivity().startActivity(intent);
                            } catch (android.content.ActivityNotFoundException e) {
                                LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
                            }
                        }
                        // load in InAppBrowser
                        else {
                            LOG.d(LOG_TAG, "loading in InAppBrowser");
                            result = showWebPage(url, features);
                        }
                    }
                    // SYSTEM
                    else if (SYSTEM.equals(target)) {
                        LOG.d(LOG_TAG, "in system");
                        result = openExternal(url);
                    }
                    // BLANK - or anything else
                    else {
                        LOG.d(LOG_TAG, "in blank");
                        result = showWebPage(url, features);
                    }

                    PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
                    pluginResult.setKeepCallback(true);
                    callbackContext.sendPluginResult(pluginResult);
                }
            });
        }
        else if (action.equals("close")) {
            closeDialog();
        }
        else if (action.equals("loadAfterBeforeload")) {
            if (beforeload == null) {
                LOG.e(LOG_TAG, "unexpected loadAfterBeforeload called without feature beforeload=yes");
            }
            final String url = args.getString(0);
            this.cordova.getActivity().runOnUiThread(new Runnable() {
                @SuppressLint("NewApi")
                @Override
                public void run() {
                    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
                        currentClient.waitForBeforeload = false;
                        inAppWebView.setWebViewClient(currentClient);
                    } else {
                        ((InAppBrowserClient)inAppWebView.getWebViewClient()).waitForBeforeload = false;
                    }
                    inAppWebView.loadUrl(url);

                }
            });
        }
        else if (action.equals("injectScriptCode")) {
            String jsWrapper = null;
            if (args.getBoolean(1)) {
                jsWrapper = String.format("(function(){prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')})()", callbackContext.getCallbackId());
            }
            injectDeferredObject(args.getString(0), jsWrapper);
        }
        else if (action.equals("injectScriptFile")) {
            String jsWrapper;
            if (args.getBoolean(1)) {
                jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
            } else {
                jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
            }
            injectDeferredObject(args.getString(0), jsWrapper);
        }
        else if (action.equals("injectStyleCode")) {
            String jsWrapper;
            if (args.getBoolean(1)) {
                jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
            } else {
                jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
            }
            injectDeferredObject(args.getString(0), jsWrapper);
        }
        else if (action.equals("injectStyleFile")) {
            String jsWrapper;
            if (args.getBoolean(1)) {
                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('', 'gap-iab://%s');})(document)", callbackContext.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)";
            }
            injectDeferredObject(args.getString(0), jsWrapper);
        }
        else if (action.equals("show")) {
            this.cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (dialog != null && !cordova.getActivity().isFinishing()) {
                        dialog.show();
                    }
                }
            });
            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
            pluginResult.setKeepCallback(true);
            this.callbackContext.sendPluginResult(pluginResult);
        }
        else if (action.equals("hide")) {
            this.cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (dialog != null && !cordova.getActivity().isFinishing()) {
                        dialog.hide();
                    }
                }
            });
            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
            pluginResult.setKeepCallback(true);
            this.callbackContext.sendPluginResult(pluginResult);
        }
        else {
            return false;
        }
        return true;
    }

    /**
     * Called when the view navigates.
     */
    @Override
    public void onReset() {
        closeDialog();
    }

    /**
     * Called when the system is about to start resuming a previous activity.
     */
    @Override
    public void onPause(boolean multitasking) {
        if (shouldPauseInAppBrowser) {
            inAppWebView.onPause();
        }
    }

    /**
     * Called when the activity will start interacting with the user.
     */
    @Override
    public void onResume(boolean multitasking) {
        if (shouldPauseInAppBrowser) {
            inAppWebView.onResume();
        }
    }

    /**
     * Called by AccelBroker when listener is to be shut down.
     * Stop listener.
     */
    public void onDestroy() {
        closeDialog();
    }

    /**
     * Inject an object (script or style) into the InAppBrowser WebView.
     *
     * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
     * provides a consistent method for injecting JavaScript code into the document.
     *
     * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
     * quotes) and wrapped using string formatting. (The wrapper string should have a single
     * '%s' marker)
     *
     * @param source      The source object (filename or script/style text) to inject into
     *                    the document.
     * @param jsWrapper   A JavaScript string to wrap the source string in, so that the object
     *                    is properly injected, or null if the source string is JavaScript text
     *                    which should be executed directly.
     */
    private void injectDeferredObject(String source, String jsWrapper) {
        if (inAppWebView!=null) {
            String scriptToInject;
            if (jsWrapper != null) {
                org.json.JSONArray jsonEsc = new org.json.JSONArray();
                jsonEsc.put(source);
                String jsonRepr = jsonEsc.toString();
                String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
                scriptToInject = String.format(jsWrapper, jsonSourceString);
            } else {
                scriptToInject = source;
            }
            final String finalScriptToInject = scriptToInject;
            this.cordova.getActivity().runOnUiThread(new Runnable() {
                @SuppressLint("NewApi")
                @Override
                public void run() {
                    inAppWebView.evaluateJavascript(finalScriptToInject, null);
                }
            });
        } else {
            LOG.d(LOG_TAG, "Can't inject code into the system browser");
        }
    }

    /**
     * Put the list of features into a hash map
     *
     * @param optString
     * @return
     */
    private HashMap<String, String> parseFeature(String optString) {
        if (optString.equals(NULL)) {
            return null;
        } else {
            HashMap<String, String> map = new HashMap<String, String>();
            StringTokenizer features = new StringTokenizer(optString, ",");
            StringTokenizer option;
            while(features.hasMoreElements()) {
                option = new StringTokenizer(features.nextToken(), "=");
                if (option.hasMoreElements()) {
                    String key = option.nextToken();
                    String value = option.nextToken();
                    if (!customizableOptions.contains(key)) {
                        value = value.equals("yes") || value.equals("no") ? value : "yes";
                    }
                    map.put(key, value);
                }
            }
            return map;
        }
    }

    /**
     * Display a new browser with the specified URL.
     *
     * @param url the url to load.
     * @return "" if ok, or error message.
     */
    public String openExternal(String url) {
        try {
            Intent intent = null;
            intent = new Intent(Intent.ACTION_VIEW);
            // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
            // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
            Uri uri = Uri.parse(url);
            if ("file".equals(uri.getScheme())) {
                intent.setDataAndType(uri, webView.getResourceApi().getMimeType(uri));
            } else {
                intent.setData(uri);
            }
            intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName());
            // CB-10795: Avoid circular loops by preventing it from opening in the current app
            this.openExternalExcludeCurrentApp(intent);
            return "";
            // not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
        } catch (java.lang.RuntimeException e) {
            LOG.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString());
            return e.toString();
        }
    }

    /**
     * Opens the intent, providing a chooser that excludes the current app to avoid
     * circular loops.
     */
    private void openExternalExcludeCurrentApp(Intent intent) {
        String currentPackage = cordova.getActivity().getPackageName();
        boolean hasCurrentPackage = false;

        PackageManager pm = cordova.getActivity().getPackageManager();
        List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
        ArrayList<Intent> targetIntents = new ArrayList<Intent>();

        for (ResolveInfo ri : activities) {
            if (!currentPackage.equals(ri.activityInfo.packageName)) {
                Intent targetIntent = (Intent)intent.clone();
                targetIntent.setPackage(ri.activityInfo.packageName);
                targetIntents.add(targetIntent);
            }
            else {
                hasCurrentPackage = true;
            }
        }

        // If the current app package isn't a target for this URL, then use
        // the normal launch behavior
        if (hasCurrentPackage == false || targetIntents.size() == 0) {
            this.cordova.getActivity().startActivity(intent);
        }
        // If there's only one possible intent, launch it directly
        else if (targetIntents.size() == 1) {
            this.cordova.getActivity().startActivity(targetIntents.get(0));
        }
        // Otherwise, show a custom chooser without the current app listed
        else if (targetIntents.size() > 0) {
            Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size()-1), null);
            chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[] {}));
            this.cordova.getActivity().startActivity(chooser);
        }
    }

    /**
     * Closes the dialog
     */
    public void closeDialog() {

        //yellowin yellowin 보안처리 - start
        if (dialog != null && dialog.isShowing()) {  // Dialog가 열려 있을 때만 닫기
            dialog.dismiss();
            // Clean up.
            dialog = null;
        }
        //yellowin yellowin 보안처리 - end
        this.cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                final WebView childView = inAppWebView;
                // The JS protects against multiple calls, so this should happen only when
                // closeDialog() is called by other native code.
                if (childView == null) {
                    return;
                }

                childView.setWebViewClient(new WebViewClient() {
                    // NB: wait for about:blank before dismissing
                    public void onPageFinished(WebView view, String url) {
                        if (dialog != null && !cordova.getActivity().isFinishing()) {
                            dialog.dismiss();
                            dialog = null;
                        }
                    }
                });
                // NB: From SDK 19: "If you call methods on WebView from any thread
                // other than your app's UI thread, it can cause unexpected results."
                // <http://developer.android.com/guide/webapps/migrating.html#Threads>
                childView.loadUrl("about:blank");

                try {
                    JSONObject obj = new JSONObject();
                    obj.put("type", EXIT_EVENT);
                    sendUpdate(obj, false);
                } catch (JSONException ex) {
                    LOG.d(LOG_TAG, "Should never happen");
                }
            }
        });
    }

    /**
     * Checks to see if it is possible to go back one page in history, then does so.
     */
    public void goBack() {
         if (this.inAppWebView.canGoBack()) {
             //this.inAppWebView.goBack();
             this.inAppWebView.loadUrl("javascript:gfn_historyBack();");
             webView.loadUrl("javascript:onBackKeyDown_new();");
         }else{
             webView.loadUrl("javascript:exitApp();");
         }
//        // if (inAppWebView.canGoBack()) {
//            LOG.d(LOG_TAG, "yellowin yellowin inappbrowser  >>>>>>>>>  onBackKeyDown()");
//            webView.loadUrl("javascript:onBackKeyDown();");
//        // } else {
//        //     LOG.d(LOG_TAG, "yellowin yellowin inappbrowser  >>>>>>>>>  exitApp()");
//        //     webView.loadUrl("javascript:exitApp();");
//        // }
    }

    /**
     * Can the web browser go back?
     * @return boolean
     */
    public boolean canGoBack() {
        return this.inAppWebView.canGoBack();
    }

    /**
     * Has the user set the hardware back button to go back
     * @return boolean
     */
    public boolean hardwareBack() {
        return hadwareBackButton;
    }

    /**
     * Checks to see if it is possible to go forward one page in history, then does so.
     */
    private void goForward() {
        if (this.inAppWebView.canGoForward()) {
            this.inAppWebView.goForward();
        }
    }

    /**
     * Navigate to the new page
     *
     * @param url to load
     */
    private void navigate(String url) {
        InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);

        if (!url.startsWith("http") && !url.startsWith("file:")) {
            this.inAppWebView.loadUrl("http://" + url);
        } else {
            this.inAppWebView.loadUrl(url);
        }
        this.inAppWebView.requestFocus();
    }

    /**
     * Should we show the location bar?
     *
     * @return boolean
     */
    private boolean getShowLocationBar() {
        return this.showLocationBar;
    }

    private InAppBrowser getInAppBrowser() {
        return this;
    }

    /**
     * Display a new browser with the specified URL.
     *
     * @param url the url to load.
     * @param features jsonObject
     */
    public String showWebPage(final String url, HashMap<String, String> features) {
        // Determine if we should hide the location bar.
        showLocationBar = true;
        showZoomControls = true;
        openWindowHidden = false;
        mediaPlaybackRequiresUserGesture = false;

        if (features != null) {
            String show = features.get(LOCATION);
            if (show != null) {
                showLocationBar = show.equals("yes") ? true : false;
            }
            if(showLocationBar) {
                String hideNavigation = features.get(HIDE_NAVIGATION);
                String hideUrl = features.get(HIDE_URL);
                if(hideNavigation != null) hideNavigationButtons = hideNavigation.equals("yes") ? true : false;
                if(hideUrl != null) hideUrlBar = hideUrl.equals("yes") ? true : false;
            }
            String zoom = features.get(ZOOM);
            if (zoom != null) {
                showZoomControls = zoom.equals("yes") ? true : false;
            }
            String hidden = features.get(HIDDEN);
            if (hidden != null) {
                openWindowHidden = hidden.equals("yes") ? true : false;
            }
            String hardwareBack = features.get(HARDWARE_BACK_BUTTON);
            if (hardwareBack != null) {
                hadwareBackButton = hardwareBack.equals("yes") ? true : false;
            } else {
                hadwareBackButton = DEFAULT_HARDWARE_BACK;
            }
            String mediaPlayback = features.get(MEDIA_PLAYBACK_REQUIRES_USER_ACTION);
            if (mediaPlayback != null) {
                mediaPlaybackRequiresUserGesture = mediaPlayback.equals("yes") ? true : false;
            }
            String cache = features.get(CLEAR_ALL_CACHE);
            if (cache != null) {
                clearAllCache = cache.equals("yes") ? true : false;
            } else {
                cache = features.get(CLEAR_SESSION_CACHE);
                if (cache != null) {
                    clearSessionCache = cache.equals("yes") ? true : false;
                }
            }
            String shouldPause = features.get(SHOULD_PAUSE);
            if (shouldPause != null) {
                shouldPauseInAppBrowser = shouldPause.equals("yes") ? true : false;
            }
            String wideViewPort = features.get(USER_WIDE_VIEW_PORT);
            if (wideViewPort != null ) {
                useWideViewPort = wideViewPort.equals("yes") ? true : false;
            }
            String closeButtonCaptionSet = features.get(CLOSE_BUTTON_CAPTION);
            if (closeButtonCaptionSet != null) {
                closeButtonCaption = closeButtonCaptionSet;
            }
            String closeButtonColorSet = features.get(CLOSE_BUTTON_COLOR);
            if (closeButtonColorSet != null) {
                closeButtonColor = closeButtonColorSet;
            }
            String leftToRightSet = features.get(LEFT_TO_RIGHT);
            leftToRight = leftToRightSet != null && leftToRightSet.equals("yes");

            String toolbarColorSet = features.get(TOOLBAR_COLOR);
            if (toolbarColorSet != null) {
                toolbarColor = android.graphics.Color.parseColor(toolbarColorSet);
            }
            String navigationButtonColorSet = features.get(NAVIGATION_COLOR);
            if (navigationButtonColorSet != null) {
                navigationButtonColor = navigationButtonColorSet;
            }
            String showFooterSet = features.get(FOOTER);
            if (showFooterSet != null) {
                showFooter = showFooterSet.equals("yes") ? true : false;
            }
            String footerColorSet = features.get(FOOTER_COLOR);
            if (footerColorSet != null) {
                footerColor = footerColorSet;
            }
            if (features.get(BEFORELOAD) != null) {
                beforeload = features.get(BEFORELOAD);
            }
            String fullscreenSet = features.get(FULLSCREEN);
            if (fullscreenSet != null) {
                fullscreen = fullscreenSet.equals("yes") ? true : false;
            }
        }

        final CordovaWebView thatWebView = this.webView;

        // Create dialog in new thread
        Runnable runnable = new Runnable() {
             // yellowin yellowin videoview 풀스크린
             private void enableFullScreen(Activity activity, Window window) {
                // inFullScreen = true; // yellowin yellowin window.open
                WindowManager.LayoutParams attrs = window.getAttributes();
                attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
                attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                window.setAttributes(attrs);
                if (android.os.Build.VERSION.SDK_INT >= 14) {
                    // noinspection all
                    int flags = View.SYSTEM_UI_FLAG_LOW_PROFILE;
                    if (android.os.Build.VERSION.SDK_INT >= 16) {
                        flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                                | View.SYSTEM_UI_FLAG_IMMERSIVE;
                    }
                    window.getDecorView().setSystemUiVisibility(flags);
                }

            }

            // yellowin yellowin videoview 풀스크린
            private void disableFullScreen(Activity activity, Window window) {
                // inFullScreen = false; // yellowin yellowin window.open
                WindowManager.LayoutParams attrs = window.getAttributes();
                attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
                attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                window.setAttributes(attrs);
                if (android.os.Build.VERSION.SDK_INT >= 14) {
                    // noinspection all
                    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
                }

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
                dialog.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

            }

            /**
             * Convert our DIP units to Pixels
             *
             * @return int
             */
            private int dpToPixels(int dipValue) {
                int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,
                        (float) dipValue,
                        cordova.getActivity().getResources().getDisplayMetrics()
                );

                return value;
            }

            private View createCloseButton(int id) {
                View _close;
                Resources activityRes = cordova.getActivity().getResources();

                if (closeButtonCaption != "") {
                    // Use TextView for text
                    TextView close = new TextView(cordova.getActivity());
                    close.setText(closeButtonCaption);
                    close.setTextSize(20);
                    if (closeButtonColor != "") close.setTextColor(android.graphics.Color.parseColor(closeButtonColor));
                    close.setGravity(android.view.Gravity.CENTER_VERTICAL);
                    close.setPadding(this.dpToPixels(10), 0, this.dpToPixels(10), 0);
                    _close = close;
                }
                else {
                    ImageButton close = new ImageButton(cordova.getActivity());
                    int closeResId = activityRes.getIdentifier("ic_action_remove", "drawable", cordova.getActivity().getPackageName());
                    Drawable closeIcon = activityRes.getDrawable(closeResId);
                    if (closeButtonColor != "") close.setColorFilter(android.graphics.Color.parseColor(closeButtonColor));
                    close.setImageDrawable(closeIcon);
                    close.setScaleType(ImageView.ScaleType.FIT_CENTER);
                    close.getAdjustViewBounds();

                    _close = close;
                }

                RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
                if (leftToRight) closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
                else closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                _close.setLayoutParams(closeLayoutParams);
                _close.setBackground(null);

                _close.setContentDescription("Close Button");
                _close.setId(Integer.valueOf(id));
                _close.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        closeDialog();
                    }
                });

                return _close;
            }

            @SuppressLint("NewApi")
            public void run() {

                // CB-6702 InAppBrowser hangs when opening more than one instance
                if (dialog != null) {
                    dialog.dismiss();
                };

                // Let's create the main dialog
                dialog = new InAppBrowserDialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar);
                dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                if (fullscreen) {
                    dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
                }
                dialog.setCancelable(true);
                dialog.setInAppBroswer(getInAppBrowser());

                // yellowin 추가
                dialog.setContentView(R.layout.activity_main); /* 레이아웃 로드 */

                // yellowin yellowin 인앱브라우져 상단 상태바 컬러 변경하기 - start
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                    dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                    dialog.getWindow().setStatusBarColor(Color.parseColor("#ffffff"));
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
                        dialog.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                }
                // yellowin yellowin 인앱브라우져 상단 상태바 컬러 변경하기 - end

                // // Main container layout
                // LinearLayout main = new LinearLayout(cordova.getActivity());
                // main.setOrientation(LinearLayout.VERTICAL);

                // yellowin Main container layout
                RelativeLayout main = new RelativeLayout(cordova.getActivity());

                RelativeLayout fullScreenMain = new RelativeLayout(cordova.getActivity());
                fullScreenMain.setLayoutParams(
                        new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                LinearLayout browserMain = new LinearLayout(cordova.getActivity());
                browserMain.setOrientation(LinearLayout.VERTICAL);
                browserMain.setLayoutParams(
                        new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                // yellowin Main container layout

                // Toolbar layout
                RelativeLayout toolbar = new RelativeLayout(cordova.getActivity());
                //Please, no more black!
                toolbar.setBackgroundColor(toolbarColor);
                toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(TOOLBAR_HEIGHT)));
                toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
                if (leftToRight) {
                    toolbar.setHorizontalGravity(Gravity.LEFT);
                } else {
                    toolbar.setHorizontalGravity(Gravity.RIGHT);
                }
                toolbar.setVerticalGravity(Gravity.TOP);

                // Action Button Container layout
                RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity());
                RelativeLayout.LayoutParams actionButtonLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
                if (leftToRight) actionButtonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                else actionButtonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
                actionButtonContainer.setLayoutParams(actionButtonLayoutParams);
                actionButtonContainer.setHorizontalGravity(Gravity.LEFT);
                actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
                actionButtonContainer.setId(leftToRight ? Integer.valueOf(5) : Integer.valueOf(1));

                // Back button
                ImageButton back = new ImageButton(cordova.getActivity());
                RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
                backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
                back.setLayoutParams(backLayoutParams);
                back.setContentDescription("Back Button");
                back.setId(Integer.valueOf(2));
                Resources activityRes = cordova.getActivity().getResources();
                int backResId = activityRes.getIdentifier("ic_action_previous_item", "drawable", cordova.getActivity().getPackageName());
                Drawable backIcon = activityRes.getDrawable(backResId);
                if (navigationButtonColor != "") back.setColorFilter(android.graphics.Color.parseColor(navigationButtonColor));
                back.setBackground(null);
                back.setImageDrawable(backIcon);
                back.setScaleType(ImageView.ScaleType.FIT_CENTER);
                back.setPadding(0, this.dpToPixels(10), 0, this.dpToPixels(10));
                back.getAdjustViewBounds();

                back.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        goBack();
                    }
                });

                // Forward button
                ImageButton forward = new ImageButton(cordova.getActivity());
                RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
                forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
                forward.setLayoutParams(forwardLayoutParams);
                forward.setContentDescription("Forward Button");
                forward.setId(Integer.valueOf(3));
                int fwdResId = activityRes.getIdentifier("ic_action_next_item", "drawable", cordova.getActivity().getPackageName());
                Drawable fwdIcon = activityRes.getDrawable(fwdResId);
                if (navigationButtonColor != "") forward.setColorFilter(android.graphics.Color.parseColor(navigationButtonColor));
                forward.setBackground(null);
                forward.setImageDrawable(fwdIcon);
                forward.setScaleType(ImageView.ScaleType.FIT_CENTER);
                forward.setPadding(0, this.dpToPixels(10), 0, this.dpToPixels(10));
                forward.getAdjustViewBounds();

                forward.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        goForward();
                    }
                });

                // Edit Text Box
                edittext = new EditText(cordova.getActivity());
                RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
                textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
                edittext.setLayoutParams(textLayoutParams);
                edittext.setId(Integer.valueOf(4));
                edittext.setSingleLine(true);
                edittext.setText(url);
                edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
                edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
                edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
                edittext.setOnKeyListener(new View.OnKeyListener() {
                    public boolean onKey(View v, int keyCode, KeyEvent event) {
                        // If the event is a key-down event on the "enter" button
                        if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
                            navigate(edittext.getText().toString());
                            return true;
                        }
                        return false;
                    }
                });

                // Header Close/Done button
                int closeButtonId = leftToRight ? 1 : 5;
                View close = createCloseButton(closeButtonId);
                toolbar.addView(close);

                // Footer
                RelativeLayout footer = new RelativeLayout(cordova.getActivity());
                int _footerColor;
                if(footerColor != "") {
                    _footerColor = Color.parseColor(footerColor);
                } else {
                    _footerColor = android.graphics.Color.LTGRAY;
                }
                footer.setBackgroundColor(_footerColor);
                RelativeLayout.LayoutParams footerLayout = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(TOOLBAR_HEIGHT));
                footerLayout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
                footer.setLayoutParams(footerLayout);
                if (closeButtonCaption != "") footer.setPadding(this.dpToPixels(8), this.dpToPixels(8), this.dpToPixels(8), this.dpToPixels(8));
                footer.setHorizontalGravity(Gravity.LEFT);
                footer.setVerticalGravity(Gravity.BOTTOM);

                View footerClose = createCloseButton(7);
                footer.addView(footerClose);

                // yellowin WebView
                inAppWebView = (WebView) dialog.findViewById(R.id.webView); /* 인앱브라우져 /layout/active_main.xml 로드/연결 */

                //yellowin yellowin swipeRefreshLayout
                swipeRefreshLayout = dialog.findViewById(R.id.swipeRefreshLayout);

                //// yellowin yellowin videoview 풀스크린 - 비디오 풀스크린 뷰
                mVideoview = dialog.findViewById(R.id.videoview);

                //yellowin yellowin swipeRefreshLayout
                swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                    @Override
                    public void onRefresh() {
                        // Implement your refresh logic here

                        // For example, reload the current URL in the WebView
                        inAppWebView.reload();

                    }
                });

                // // WebView
                // inAppWebView = new WebView(cordova.getActivity());
                // inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                // inAppWebView.setId(Integer.valueOf(6));
                // File Chooser Implemented ChromeClient
                inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView) {
                    // yellowin yellowin videoview 풀스크린
                    @Override
                    public void onHideCustomView() {

                        Activity activity = cordova.getActivity();
                        Window window = dialog.getWindow();
                        Log.d("yellowin", "yellowin mVideoview disableFullScreen~~ onHideCustomView 1111");

                        disableFullScreen(activity, window);

                        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
                        }

                        mVideoview.setVisibility(View.GONE);
                        // 하단툴바 메뉴 표시
                        // bnve.setVisibility(View.VISIBLE);

                    }

                    // yellowin yellowin videoview 풀스크린
                    @Override
                    public void onShowCustomView(View view, CustomViewCallback callback) {
                        // Enter fullscreen mode
                        // super.onShowCustomView(view, callback);
                        // You may need to handle the view and callback to exit fullscreen later

                        // 하단툴바 메뉴 숨김 (bnve 객체명으로 하단툴바가 있는경우에만 사용)
                        // bnve.setVisibility(View.GONE);

                        mVideoview.addView(view);
                        mVideoview.setVisibility(View.VISIBLE);
                        mVideoview.bringToFront();

                        Activity activity = cordova.getActivity();
                        Window window = dialog.getWindow();

                        Log.d("yellowin", "yellowin mVideoview enableFullScreen~~ onShowCustomView 1111");
                        enableFullScreen(activity, window);
                        // activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
                        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
                        }

                    }

                    public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
                    {
                        LOG.d(LOG_TAG, "File Chooser 5.0+");
                        // Callback 초기화 (중요!)   //input file태그를 다시 눌렀을때 정상 작동되도록 함.
                        // If callback exists, finish it.
                        if (filePathCallbackLollipop != null) {
                            filePathCallbackLollipop.onReceiveValue(null);
                            filePathCallbackLollipop = null;
                        }
                        filePathCallbackLollipop = filePathCallback;

                        boolean isCapture = fileChooserParams.isCaptureEnabled();
                        String acceptType = Arrays.toString(fileChooserParams.getAcceptTypes());

                        Log.i("---", "---");
                        Log.w("//===========//", "================================================");
                        Log.i("", "\\n" + "[A_Main >> onShowFileChooser() :: 웹 브라우저 갤러리 호출 수행 실시]");

                        Log.i("", "\\n" + "[filePathCallback :: " + String.valueOf(filePathCallback.toString()) + "]");
                        Log.i("", "\\n" + "[fileChooserParams :: " + Arrays.toString(fileChooserParams.getAcceptTypes())
                                + "]");
                        Log.w("//===========//", "================================================");
                        Log.i("---", "---");

                        // 카메라만 호출여부 체크
                        // 아래 Input 태그의 속성중 capture란 속성이 들어가있다면 isCapture=true 임.
                        // <input type="file" name="upfile_1" id="upfile_1" accept="image/jpeg,
                        // image/png, image/jpg;" capture="image">
                        Log.d("onShowFileChooser", "yellowin yellowin onShowFileChooser inapp view :  000000");
                        Log.d("onShowFileChooser", "yellowin yellowin onShowFileChooser 1111 : " + String.valueOf(isCapture));
                        Log.d("onShowFileChooser", "yellowin yellowin onShowFileChooser 2222 : " + String.valueOf(acceptType));

                        // yellowin multi
                        //////////// yellowin yellowin 멀티 업로드 추가 수정 시작 11
                        Boolean selectMultiple = false;
                        if (fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE) {
                            selectMultiple = true;
                        }

                        if (isCapture) {
                            // (isCapture = true인경우 카메라만 띄울수 있음)
                            yellowinChooser(isCapture, selectMultiple, acceptType);
                        } else if (!acceptType.contains("*/*")) {
                            Log.d("yellowin : ", "yellowin 카메라,갤러리 호출");
                            // 카메라 및 갤러리 선택 호출
                            yellowinChooser(false, selectMultiple, acceptType);
                        } else {
                            Log.d("yellowin : ", "yellowin 갤러리 일반 호출");
                            // 갤러리만 호출 일반파일 선택 호출(기존소스임)
                            // Create File Chooser Intent
                            Intent content = new Intent(Intent.ACTION_GET_CONTENT);
                            content.addCategory(Intent.CATEGORY_OPENABLE);
                            content.setType("*/*");

                            content.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, selectMultiple);
                            //////////// yellowin multi upload 추가 수정 끝 11

                            // Run cordova startActivityForResult
                            cordova.startActivityForResult(InAppBrowser.this,
                                    Intent.createChooser(content, "Select File"), FILECHOOSER_REQUESTCODE);
                            // }
                        }

                        return true;
                    }

                    // yellowin yellowin window.open 사용시 앱내에서 새로운 자식팝업뷰로 뜨게 처리함. - start
                    public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture,
                            android.os.Message resultMsg) {
                        newWebView = new WebView(view.getContext());
                        // WebView newWebView = new VideoEnabledWebView(cordova.getActivity());

                        Log.d("yellowin", "onCreateWindow yellowin window.open ~~~~~");

                        newWebView.setLayoutParams(
                                new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                        newWebView.setId(Integer.valueOf(6));

                        WebSettings settings = newWebView.getSettings();

                        settings.setJavaScriptEnabled(true);
                        settings.setJavaScriptCanOpenWindowsAutomatically(true);
                        settings.setSupportMultipleWindows(true);

                        // bnve.setVisibility(View.GONE);
                        // Log.d("yellowin","yellowin bnve bnve.setVisibility(View.GONE) 1111");

                        // yellowin 상단 기본 인앱코드 카피 - start
                        // yellowin yellowin window.open 글자크기 고정
                        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH)
                            settings.setTextZoom(100);

                        // yellowin mixed content errors 방지
                        // settings.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
                        }
                        // // yellowin yellowin net::ERR_CACHE_MISS
                        // settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

                        settings.setJavaScriptEnabled(true);
                        settings.setJavaScriptCanOpenWindowsAutomatically(true);
                        settings.setBuiltInZoomControls(showZoomControls);
                        // yellowin //줌 컨트롤을 숨김
                        settings.setDisplayZoomControls(false);

                        settings.setPluginState(android.webkit.WebSettings.PluginState.ON);
                        // yellowin yellowin window.open 세로 scroll 제거
                        newWebView.setHorizontalScrollBarEnabled(false);
                        // yellowin yellowin window.open 가로 scroll 제거
                        newWebView.setVerticalScrollBarEnabled(false);
                        // yellwoin 웹뷰 배경 흰색
                        newWebView.setBackgroundColor(Color.parseColor("#ffffff"));

                        // Add postMessage interface
                        class JsObject {
                            @JavascriptInterface
//                            public void postMessage(String data) {
//                                try {
//                                    JSONObject obj = new JSONObject();
//                                    obj.put("type", MESSAGE_EVENT);
//                                    obj.put("data", new JSONObject(data));
//                                    sendUpdate(obj, true);
//                                } catch (JSONException ex) {
//                                    LOG.e(LOG_TAG, "data object passed to postMessage has caused a JSON error.");
//                                }
//                            }

                            public void postMessage(String data) {
                                try {
                                    JSONObject obj = new JSONObject();
                                    obj.put("type", MESSAGE_EVENT);

                                    // 데이터가 JSON 문자열인지 확인
                                    if (isJSONValid(data)) {
                                        obj.put("data", new JSONObject(data)); // JSON 문자열 처리
                                    } else {
                                        throw new IllegalArgumentException("Invalid JSON data received: " + data);
                                    }

                                    sendUpdate(obj, true);
                                } catch (JSONException ex) {
                                    LOG.e(LOG_TAG, "JSON parsing error in postMessage: " + ex.getMessage());
                                } catch (Exception ex) {
                                    LOG.e(LOG_TAG, "Unexpected error in postMessage: " + ex.getMessage());
                                }
                            }

                            /**
                             * Helper method to validate if a string is a valid JSON.
                             */
                            private boolean isJSONValid(String data) {
                                try {
                                    new JSONObject(data); // JSON으로 변환 시도
                                    return true;
                                } catch (JSONException ex) {
                                    return false;
                                }
                            }

                        }

                        settings.setMediaPlaybackRequiresUserGesture(mediaPlaybackRequiresUserGesture);
                        newWebView.addJavascriptInterface(new JsObject(), "firebase");
                        newWebView.addJavascriptInterface(new JsObject(), "cordova_iab");

                        String overrideUserAgent = preferences.getString("OverrideUserAgent", null);
                        String appendUserAgent = preferences.getString("AppendUserAgent", null);

                        if (overrideUserAgent != null) {
                            settings.setUserAgentString(overrideUserAgent);
                        }
                        if (appendUserAgent != null) {
                            settings.setUserAgentString(settings.getUserAgentString() + appendUserAgent);
                        }
//
//
//                        // 기존 User-Agent 가져오기
//                        String defaultUserAgent = settings.getUserAgentString();
//
//                        // 새로운 User-Agent 추가 (Yellowin 추가 : /APTRACK_ANDROID => GA팀에서 추가요청으로 추가)
//                        String customUserAgent = defaultUserAgent + " mobileapp androidapp amospro/APTRACK_ANDROID";
//                        settings.setUserAgentString(customUserAgent);

                        // Toggle whether this is enabled or not!
                        Bundle appSettings = cordova.getActivity().getIntent().getExtras();
                        boolean enableDatabase = appSettings == null ? true
                                : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
                        if (enableDatabase) {
                            String databasePath = cordova.getActivity().getApplicationContext()
                                    .getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
                            settings.setDatabasePath(databasePath);
                            settings.setDatabaseEnabled(true);
                        }
                        settings.setDomStorageEnabled(true);

                        if (clearAllCache) {
                            CookieManager.getInstance().removeAllCookie();
                        } else if (clearSessionCache) {
                            CookieManager.getInstance().removeSessionCookie();
                        }

                        // Enable Thirdparty Cookies
                        CookieManager.getInstance().setAcceptThirdPartyCookies(newWebView, true);
                        // yellowin 상단 기본 인앱코드 카피 - end

                        if (dialog_child != null) {
                            dialog_child.dismiss();
                        }
                        ;

                        // yellowin new 새창처리 - start

                        // 새 창의 전체 레이아웃을 위한 RelativeLayout 생성
                        RelativeLayout fullScreenLayout = new RelativeLayout(cordova.getContext());
                        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                        fullScreenLayout.setLayoutParams(layoutParams);
                        // fullScreenLayout.setBackgroundColor(Color.WHITE); // 전체 배경을 흰색으로 설정
                        fullScreenLayout.setBackgroundColor(Color.TRANSPARENT); // 전체 배경을 투명으로 설정

                        // "닫기" 이미지 버튼 생성 및 설정
                        ImageButton closeButton = new ImageButton(cordova.getContext());
                        closeButton.setId(View.generateViewId()); // 닫기 버튼에 고유 ID 할당
                        closeButton.setImageResource(R.drawable.ic_close); // 이미지 리소스 설정

                        closeButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); // 이미지가 버튼 중앙에 위치하도록 설정

                        // 동그란 모양의 배경을 설정하기 위한 ShapeDrawable
                        ShapeDrawable circleDrawable = new ShapeDrawable(new OvalShape());
                        circleDrawable.getPaint().setColor(Color.WHITE); // 동그란 배경의 색상을 흰색으로 설정
                        circleDrawable.getPaint().setAntiAlias(true); // 안티알리아싱 적용

                        // 이미지 버튼에 동그란 배경 설정
                        closeButton.setBackground(circleDrawable);

                        // closeButton.setBackgroundColor(Color.TRANSPARENT); // 배경색을 투명으로 설정
                        // closeButton.setOnClickListener(v -> dialog_child.dismiss());
                        closeButton.setColorFilter(Color.BLACK); // 이미지 색상을 검은색으로 변경
                        closeButton.setScaleType(ImageView.ScaleType.FIT_CENTER); // 이미지를 버튼 크기에 맞게 조정
                        closeButton.setPadding(15, 15, 15, 15); // x이미지 여백

                        // 이미지 버튼 크기 조정
                        int buttonSize = 35; // 버튼 크기를 80dp로 설정
                        float scale = cordova.getContext().getResources().getDisplayMetrics().density;
                        int dpAsPixels = (int) (buttonSize * scale + 0.5f);

                        RelativeLayout.LayoutParams buttonParams = new RelativeLayout.LayoutParams(dpAsPixels,
                                dpAsPixels);
                        // RelativeLayout.LayoutParams buttonParams = new
                        // RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                        // LayoutParams.WRAP_CONTENT);
                        buttonParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                        buttonParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);

                        // 닫기 버튼에 마진을 추가하여 상단에 여백을 만듦
                        buttonParams.setMargins(0, 25, 30, 25); // 마진 추가로 상단에 여백을 만듦
                        closeButton.setLayoutParams(buttonParams);

                        // RelativeLayout에 "닫기" 이미지 버튼 추가
                        fullScreenLayout.addView(closeButton);

                        // WebView 설정 및 추가
                        RelativeLayout.LayoutParams webViewParams = new RelativeLayout.LayoutParams(
                                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                        webViewParams.addRule(RelativeLayout.BELOW, closeButton.getId()); // WebView가 닫기 버튼 아래에 위치하도록 설정
                        fullScreenLayout.addView(newWebView, webViewParams);

                        // 대화 상자(dialog) 설정 및 표시
                        if (dialog_child != null) {
                            dialog_child.dismiss();
                        }

                        dialog_child = new InAppBrowserDialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar);

                        // 대화 상자의 윈도우 배경을 투명하게 설정
                        window_child = dialog_child.getWindow();
                        if (window_child != null) {
                            // window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); // 윈도우
                            // 배경을 투명하게
                            window_child.setBackgroundDrawable(new ColorDrawable(Color.argb(128, 0, 0, 0))); // 50% 투명도의
                                                                                                             // 검은색

                            // 슬라이드 애니메이션 설정 (res/anim/slide_in_bottom.xml, res/anim/slide_out_bottom.xml,
                            // stay_in_place.xml 파일이 있어야함. res/values/styles.xml 파일에 DialogSlideAnim,
                            // DialogSlideAnimClose style이 정의되어 있어야함.)
                            window_child.setWindowAnimations(R.style.DialogSlideAnim);

                            window_child.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                            window_child.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                            window_child.setStatusBarColor(Color.TRANSPARENT);
                            // 상태바 아이콘과 텍스트 색상을 검정색으로 설정 (API 23+)
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                window_child.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                            }
                        }

                        // "닫기" 버튼 클릭 이벤트 설정
                        closeButton.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                // 애니메이션으로 닫기 (res/anim/slide_in_bottom.xml, res/anim/slide_out_bottom.xml,
                                // stay_in_place.xml 파일이 있어야함. res/values/styles.xml 파일에 DialogSlideAnim,
                                // DialogSlideAnimClose style이 정의되어 있어야함.)
                                window_child.setWindowAnimations(R.style.DialogSlideAnimClose); // 슬라이드 아웃 애니메이션 설정

                                // Handler를 사용하여 애니메이션의 지속 시간 후에 dialog_child.dismiss()를 호출
                                new Handler().postDelayed(new Runnable() {
                                    @Override
                                    public void run() {
                                        newWebView.destroy();
                                        dialog_child.dismiss();
                                    }
                                }, 100); // 여기서 300은 애니메이션의 duration과 일치해야 합니다.
                            }
                        });

                        dialog_child.setContentView(fullScreenLayout);

                        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
                        lp.copyFrom(dialog_child.getWindow().getAttributes());
                        lp.width = LayoutParams.MATCH_PARENT;
                        lp.height = LayoutParams.MATCH_PARENT;
                        window_child.setAttributes(lp);
                        dialog_child.show();
                        // yellowin new 새창처리 - end

                        dialog_child.setOnKeyListener(new DialogInterface.OnKeyListener() {
                            @Override
                            public boolean onKey(DialogInterface dialog_ch, int keyCode, KeyEvent event) {

                                LOG.d("yellowin", "yellowin dialog_child back~~~~!!!!!! ");

                                if (keyCode == KeyEvent.KEYCODE_BACK) {

                                    // yellowin yellowin window.open - video 풀스크린 화면에서 백버튼을 눌렀을때의 처리(풀스크린 해제된 화면으로
                                    // 표시)
                                    if (isFullscreen) {
                                        Activity activity = cordova.getActivity();
                                        Window window = dialog_child.getWindow();

                                        // if (!fullScreenFeature) {
                                        disableFullScreen(activity, window);
                                        // }
                                        Log.d("yellowin", "yellowin bnve disableFullScreen~~ 0000");

                                        // //1초후에 실행되도록 지연시간을 주어야 함.
                                        new Handler(getMainLooper()).postDelayed(new Runnable() {
                                            @Override
                                            public void run() {
                                                isFullscreen = false;
                                                // newWebView.loadUrl("javascript:document.exitFullscreen();");
                                            }
                                        }, 1000);

                                        // activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
                                        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

                                        // newWebView.setVisibility(View.GONE);

                                        isFullscreen = false;
                                        return true;
                                    } else {

                                        if (newWebView.canGoBack()) {
                                            newWebView.goBack();
                                        } else {

                                            // yellowin new 새창처리 - start
                                            // 애니메이션으로 닫기 (res/anim/slide_in_bottom.xml, res/anim/slide_out_bottom.xml,
                                            // stay_in_place.xml 파일이 있어야함. res/values/styles.xml 파일에 DialogSlideAnim,
                                            // DialogSlideAnimClose style이 정의되어 있어야함.)
                                            window_child.setWindowAnimations(R.style.DialogSlideAnimClose); // 슬라이드 아웃
                                                                                                            // 애니메이션 설정

                                            // Handler를 사용하여 애니메이션의 지속 시간 후에 dialog_child.dismiss()를 호출
                                            new Handler().postDelayed(new Runnable() {
                                                @Override
                                                public void run() {

                                                    newWebView.destroy();
                                                    dialog_child.dismiss();
                                                }
                                            }, 100); // 여기서 300은 애니메이션의 duration과 일치해야 합니다.

                                            // yellowin new 새창처리 - end

                                            // yellowin new 새창처리 - start
                                            // 아래는 기존 코드로 주석처리 해야함.
                                            // newWebView.destroy();
                                            // dialog_ch.dismiss();
                                            // yellowin new 새창처리 - end

                                        }
                                        return true;
                                    }
                                } else {
                                    return false;
                                }

                            }
                        });

                        newWebView.setWebChromeClient(new InAppChromeClient(thatWebView) {

                            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
                                    WebChromeClient.FileChooserParams fileChooserParams) {
                                LOG.d(LOG_TAG, "yellowin yellowin newWebview File Chooser 5.0+");
                                // If callback exists, finish it.
                                if (mUploadCallback != null) {
                                    mUploadCallback.onReceiveValue(null);
                                }
                                mUploadCallback = filePathCallback;

                                // Create File Chooser Intent
                                Intent content = new Intent(Intent.ACTION_GET_CONTENT);
                                content.addCategory(Intent.CATEGORY_OPENABLE);
                                content.setType("*/*");

                                // yellowin multi upload 추가 start
                                Boolean selectMultiple = false;
                                if (fileChooserParams
                                        .getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE) {
                                    selectMultiple = true;
                                }
                                // yellowin multi upload 추가 end

                                // Run cordova startActivityForResult
                                cordova.startActivityForResult(InAppBrowser.this,
                                        Intent.createChooser(content, "Select File"),
                                        FILECHOOSER_REQUESTCODE);
                                return true;
                            }

                            @Override
                            public void onCloseWindow(WebView window) {

                                // bnve.setVisibility(View.VISIBLE);
                                Log.d("yellowin", "yellowin bnve onCloseWindow bnve.setVisibility(View.VISIBLE) 1111");
                                newWebView.destroy();
                                dialog_child.dismiss();
                            }

                            @Override
                            public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                                final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext(),
                                        AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);

                                // builder.setTitle("alert title - inAppChromeClient.JAVA");
                                builder.setMessage(message);
                                builder.setPositiveButton(android.R.string.ok, null);

                                // Do not need to bind the key events
                                // Mask keycode is equal to 84 and the like button
                                builder.setOnKeyListener(new DialogInterface.OnKeyListener() {
                                    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                                        // Log.v ("onJsAlert", "keyCode ==" + keyCode + "event =" + event);
                                        return true;
                                    }
                                });

                                // Disable response back key event
                                builder.setCancelable(false);
                                AlertDialog dialog = builder.create();
                                dialog.show();
                                result.confirm(); // bind the event because there is no need to force confirm, otherwise
                                                  // the page will turn black can not display content.
                                return true;
                            }

                            @Override
                            public boolean onJsConfirm(WebView view, String url, String message,
                                    final JsResult result) {

                                final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext(),
                                        AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);

                                // builder.setTitle("confirm title - inAppChromeClient.JAVA");
                                builder.setMessage(message);
                                // builder.setPositiveButton("ok", null);

                                builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        result.confirm();

                                    }
                                });

                                builder.setNegativeButton(android.R.string.cancel,
                                        new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                result.cancel();
                                            }
                                        });

                                // Disable response back key event
                                builder.setCancelable(false);
                                AlertDialog dialog = builder.create();

                                dialog.show();
                                return true;

                            }

                        });

                        WebViewClient client_child = new InAppBrowserClient(thatWebView, edittext, beforeload);
                        // newWebView.setWebViewClient(client_child);
                        newWebView.setWebViewClient(new MyWebViewClient(view.getContext()));

                        WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
                        transport.setWebView(newWebView);
                        resultMsg.sendToTarget();
                        return true;

                    }

                    @Override
                    public void onCloseWindow(WebView window) {
                        Log.d("yellowin", "yellowin bnve onCloseWindow bnve.setVisibility(View.VISIBLE) 000");
                        Log.e(getClass().getName(), "onCloseWindow");
                        window.setVisibility(View.GONE);
                        window.destroy();
                        super.onCloseWindow(window);
                    }
                    // yellowin yellowin window.open 사용시 앱내에서 새로운 자식팝업뷰로 뜨게 처리함. - end
                    
                });
                // currentClient = new InAppBrowserClient(thatWebView, edittext, beforeload);
                // inAppWebView.setWebViewClient(currentClient);

                // yellowin yellowin edit
                WebViewClient client = new InAppBrowserClient(thatWebView, edittext, beforeload);
                inAppWebView.setWebViewClient(client);

                WebSettings settings = inAppWebView.getSettings();
                // yellowin 글자크기 고정
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH)
                    settings.setTextZoom(100);

                // yellowin mixed content errors 방지
                // settings.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
                }

//                 // yellowin yellowin net::ERR_CACHE_MISS
//                 settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

                settings.setJavaScriptEnabled(true);
                settings.setJavaScriptCanOpenWindowsAutomatically(true);
                settings.setBuiltInZoomControls(showZoomControls);
                // yellowin //줌 컨트롤을 숨김
                settings.setDisplayZoomControls(false);
                settings.setPluginState(android.webkit.WebSettings.PluginState.ON);
                // yellowin 세로 scroll 제거
                inAppWebView.setHorizontalScrollBarEnabled(false);
                // yellowin 가로 scroll 제거
                inAppWebView.setVerticalScrollBarEnabled(false);
                // yellwoin 웹뷰 배경 흰색
                inAppWebView.setBackgroundColor(Color.parseColor("#ffffff"));
                
                // download event
                
                inAppWebView.setDownloadListener(
                    new DownloadListener(){
                        public void onDownloadStart(
                                String url, String userAgent, String contentDisposition, String mimetype, long contentLength
                        ){
                            try{
                                JSONObject succObj = new JSONObject();
                                succObj.put("type", DOWNLOAD_EVENT);
                                succObj.put("url",url);
                                succObj.put("userAgent",userAgent);
                                succObj.put("contentDisposition",contentDisposition);
                                succObj.put("mimetype",mimetype);
                                succObj.put("contentLength",contentLength);
                                sendUpdate(succObj, true);
                            }
                            catch(Exception e){
                                LOG.e(LOG_TAG,e.getMessage());
                            }
                        }
                    }
                );        

                // Add postMessage interface
                class JsObject {
                    @JavascriptInterface
//                    public void postMessage(String data) {
//                        try {
//                            JSONObject obj = new JSONObject();
//                            obj.put("type", MESSAGE_EVENT);
//                            obj.put("data", new JSONObject(data));
//                            sendUpdate(obj, true);
//                        } catch (JSONException ex) {
//                            LOG.e(LOG_TAG, "data object passed to postMessage has caused a JSON error.");
//                        }
//                    }
                    public void postMessage(String data) {
                        try {
                            JSONObject obj = new JSONObject();
                            obj.put("type", MESSAGE_EVENT);

                            // 데이터가 JSON 문자열인지 확인
                            if (isJSONValid(data)) {
                                obj.put("data", new JSONObject(data)); // JSON 문자열 처리
                            } else {
                                throw new IllegalArgumentException("Invalid JSON data received: " + data);
                            }

                            sendUpdate(obj, true);
                        } catch (JSONException ex) {
                            LOG.e(LOG_TAG, "JSON parsing error in postMessage: " + ex.getMessage());
                        } catch (Exception ex) {
                            LOG.e(LOG_TAG, "Unexpected error in postMessage: " + ex.getMessage());
                        }
                    }

                    /**
                     * Helper method to validate if a string is a valid JSON.
                     */
                    private boolean isJSONValid(String data) {
                        try {
                            new JSONObject(data); // JSON으로 변환 시도
                            return true;
                        } catch (JSONException ex) {
                            return false;
                        }
                    }

                }

                settings.setMediaPlaybackRequiresUserGesture(mediaPlaybackRequiresUserGesture);
                inAppWebView.addJavascriptInterface(new JsObject(), "firebase");
                inAppWebView.addJavascriptInterface(new JsObject(), "cordova_iab");

// WebView 설정 코드
                inAppWebView.getSettings().setJavaScriptEnabled(true); // JavaScript 활성화
                AnalyticsWebInterface analyticsWebInterface = new AnalyticsWebInterface(cordova.getContext());
                inAppWebView.addJavascriptInterface(analyticsWebInterface, "AnalyticsWebInterface");

                String overrideUserAgent = preferences.getString("OverrideUserAgent", null);
                String appendUserAgent = preferences.getString("AppendUserAgent", null);

                if (overrideUserAgent != null) {
                    settings.setUserAgentString(overrideUserAgent);
                }
                if (appendUserAgent != null) {
                    settings.setUserAgentString(settings.getUserAgentString() + " " + appendUserAgent);
                }

//
//                // 기존 User-Agent 가져오기
//                String defaultUserAgent = settings.getUserAgentString();
//
//                // 새로운 User-Agent 추가 (Yellowin 추가 : /APTRACK_ANDROID => GA팀에서 추가요청으로 추가)
//                String customUserAgent = defaultUserAgent + " mobileapp androidapp amospro/APTRACK_ANDROID";
//                settings.setUserAgentString(customUserAgent);

                //Toggle whether this is enabled or not!
                Bundle appSettings = cordova.getActivity().getIntent().getExtras();
                boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
                if (enableDatabase) {
                    String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
                    settings.setDatabasePath(databasePath);
                    settings.setDatabaseEnabled(true);
                }
                settings.setDomStorageEnabled(true);

                if (clearAllCache) {
                    CookieManager.getInstance().removeAllCookie();
                } else if (clearSessionCache) {
                    CookieManager.getInstance().removeSessionCookie();
                }

                // Enable Thirdparty Cookies
                CookieManager.getInstance().setAcceptThirdPartyCookies(inAppWebView,true);

                inAppWebView.loadUrl(url);
                inAppWebView.setId(Integer.valueOf(6));
                inAppWebView.getSettings().setLoadWithOverviewMode(true);
                inAppWebView.getSettings().setUseWideViewPort(useWideViewPort);
                // Multiple Windows set to true to mitigate Chromium security bug.
                //  See: <https://bugs.chromium.org/p/chromium/issues/detail?id=1083819>
                inAppWebView.getSettings().setSupportMultipleWindows(true);
                inAppWebView.requestFocus();
                inAppWebView.requestFocusFromTouch();

                // Add the back and forward buttons to our action button container layout
                actionButtonContainer.addView(back);
                actionButtonContainer.addView(forward);

                // Add the views to our toolbar if they haven't been disabled
                if (!hideNavigationButtons) toolbar.addView(actionButtonContainer);
                if (!hideUrlBar) toolbar.addView(edittext);

                // Don't add the toolbar if its been disabled
                if (getShowLocationBar()) {
                    // Add our toolbar to our main view/layout
                    main.addView(toolbar);
                }

                // // Add our webview to our main view/layout
                // RelativeLayout webViewLayout = new RelativeLayout(cordova.getActivity());
                // webViewLayout.addView(inAppWebView);
                // main.addView(webViewLayout);

                // // Don't add the footer unless it's been enabled
                // if (showFooter) {
                //     webViewLayout.addView(footer);
                // }

                // WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
                // lp.copyFrom(dialog.getWindow().getAttributes());
                // lp.width = WindowManager.LayoutParams.MATCH_PARENT;
                // lp.height = WindowManager.LayoutParams.MATCH_PARENT;

                // yellowin yellowin start
                LayoutParams lp = new LayoutParams();
                lp.copyFrom(dialog.getWindow().getAttributes());
                lp.width = LayoutParams.MATCH_PARENT;
                lp.height = LayoutParams.MATCH_PARENT;
                // yellowin yellowin end

                if (dialog != null) {
                    // dialog.setContentView(main); // yellowin yellowin 
                    dialog.show();
                    dialog.getWindow().setAttributes(lp);
                }
                // the goal of openhidden is to load the url and not display it
                // Show() needs to be called to cause the URL to be loaded
                if (openWindowHidden && dialog != null) {
                    dialog.hide();
                }
            }
        };
        this.cordova.getActivity().runOnUiThread(runnable);
        return "";
    }

    public class AnalyticsWebInterface {
        private Context context;

        public AnalyticsWebInterface(Context context) {
            this.context = context;
        }

        @JavascriptInterface
        public void logEvent(String name, String jsonParams)  {
            Log.d("AnalyticsWebInterface", "logEvent called: name=" + name + ", params=" + jsonParams);
//
//            // 메인 스레드에서 loadUrl 실행
//            new Handler(Looper.getMainLooper()).post(() -> {
//                webView.loadUrl("javascript:call_logEvent(name,jsonParams);");
//            });

            // JavaScript로 JSON 그대로 전달
            new Handler(Looper.getMainLooper()).post(() -> {
                String javascript = String.format("javascript:call_logEvent('%s', %s);", name, jsonParams);
                webView.loadUrl(javascript);
            });
        }

        @JavascriptInterface
        public void setUserProperty(String name, String value) {
            Log.d("AnalyticsWebInterface", "setUserProperty called: name=" + name + ", value=" + value);

            new Handler(Looper.getMainLooper()).post(() -> {
                String javascript = String.format("javascript:call_setUserProperty('%s', '%s');", name, value);
                webView.loadUrl(javascript);
            });
        }

        @JavascriptInterface
        public void setUserId(String id) {
            Log.d("AnalyticsWebInterface", "setUserId called: id=" + id);

            new Handler(Looper.getMainLooper()).post(() -> {
                String javascript = String.format("javascript:call_setUserId('%s');", id);
                webView.loadUrl(javascript);
            });
        }

    }

    // yellowin yellowin window.open popupview WebViewClient선언 - start
    public class MyWebViewClient extends WebViewClient {
        private String TAG = "MyWebViewClient";
        private Context mApplicationContext = null;

        String beforeload;
        boolean waitForBeforeload;

        public MyWebViewClient(Context _applicationContext) {
            mApplicationContext = _applicationContext;
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            // MyLog.i(TAG,"shouldOverrideUrlLoading(view:"+view+ ", request:"+request+")");
            // return super.shouldOverrideUrlLoading(view, request);
            return shouldOverrideUrlLoading(request.getUrl().toString(), request.getMethod());
        }

        public boolean shouldOverrideUrlLoading(String url, String method) {
            boolean override = false;
            boolean useBeforeload = false;
            String errorMessage = null;

            LOG.d(LOG_TAG, "yellowin yellowin window.open >>>> url 11111  : " + url);

            // yellowin yellowin 외부 브라우져로 url 열기 시작
            if( url.contains("systempop=") ) {
                String[] array;
                array = url.split("systempop=");
                String url2 = array[1];

                LOG.d(LOG_TAG, "yellowin url window.open external link URL : " + url);

                try {
                    Intent intent = null;
                    Uri uri = Uri.parse(url2);
                    intent = new Intent(Intent.ACTION_VIEW, uri);
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    //e.printStackTrace();  //code break
                    override = false;
                }

            } else 
            if (url.startsWith(WebView.SCHEME_TEL)) {
                try {
                    Intent intent = new Intent(Intent.ACTION_DIAL);
                    intent.setData(Uri.parse(url));
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
                }
            } else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO)) {
                try {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setData(Uri.parse(url));
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
                }
            }
            // If sms:5551212?body=This is the message
            else if (url.startsWith("sms:")) {
                try {
                    Intent intent = new Intent(Intent.ACTION_VIEW);

                    // Get address
                    String address = null;
                    int parmIndex = url.indexOf('?');
                    if (parmIndex == -1) {
                        address = url.substring(4);
                    } else {
                        address = url.substring(4, parmIndex);

                        // If body, then set sms body
                        Uri uri = Uri.parse(url);
                        String query = uri.getQuery();
                        if (query != null) {
                            if (query.startsWith("body=")) {
                                intent.putExtra("sms_body", query.substring(5));
                            }
                        }
                    }
                    intent.setData(Uri.parse("sms:" + address));
                    intent.putExtra("address", address);
                    intent.setType("vnd.android-dir/mms-sms");
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
                }
            } else if ((!url.startsWith("http:") 
                    && !url.startsWith("https:") 
                    && url.matches("^[A-Za-z0-9+.-]*://.*?$"))
                    
                || url.startsWith("market:") 
                || url.startsWith("intent:")

                || url.startsWith("bandapp:")// 네이버 밴드
                || url.startsWith("kakaotalk:")// 카카오톡
                || url.startsWith("storylink:")
                || url.startsWith("kakaoplus:")
                || url.startsWith("kakaokompassauth:")
                || url.startsWith("storykompassauth:")
                || url.startsWith("kakaolink:")
                || url.startsWith("kakaotalk-5.9.7:")
                || url.startsWith("kakaostory-2.9.0:")
                || url.startsWith("naversearchapp:")// 네이버앱
                || url.startsWith("nidlogin:")
                || url.startsWith("naversearchthirdlogin:")
                || url.startsWith("daumapps:")// 다음
                || url.startsWith("googlechromes:")// 크롬
                || url.startsWith("fb:")// 페이스북
                // 본인인증
                || url.startsWith("tauthlink:")
                || url.startsWith("ktauthexternalcall:")
                || url.startsWith("upluscorporation:")

                // 결제
                || url.contains("com.kftc.bankpay.android://")
                || url.contains("com.lotte.lottesmartpay://")
                || url.contains("com.ahnlab.v3mobileplus://")
                || url.contains("hanaansim://")
                || url.contains("vguard://")
                || url.contains("droidxantivirus://")
                || url.contains("smshinhancardusim://")
                || url.contains("smartwall://")
                || url.contains("appfree://")

                || url.contains("kb-acp://")
                || url.contains("lguthepay://")
                || url.contains("v3mobile://")
                || url.contains("kakaopay://")

                || url.contains("kftc-bankpay://")
                || url.contains("ispmobile://")
                || url.contains("hdcardappcardansimclick://")
                || url.contains("smhyundaiansimclick://")
                || url.contains("shinhan-sr-ansimclick://")
                || url.contains("smshinhanansimclick://")
                || url.contains("nonghyupcardansimclick://")
                || url.contains("kb-acp://")
                || url.contains("mpocket.online.ansimclick://")
                || url.contains("ansimclickscard://")
                || url.contains("ansimclickipcollect://")
                || url.contains("vguardstart://")
                || url.contains("samsungpay://")
                || url.contains("scardcertiapp://")
                || url.contains("lottesmartpay://")
                || url.contains("lotteappcard://")
                || url.contains("cloudpay://")
                || url.contains("nhappvardansimclick://")
                || url.contains("nhappcardansimclick://")
                || url.contains("nhallonepayansimclick://")
                || url.contains("citispay://")
                || url.contains("citimobileapp://")
                || url.contains("citicardappkr://")
                || url.contains("payco://")
                || url.contains("paypin://")
                || url.contains("paycoapplogin://")
                || url.contains("tswansimclick://")
                || url.contains("bankwallet://")
                || url.contains("uppay://")
                || url.contains("kpay://")
                || url.contains("smilepayapp://")
                || url.contains("maps://")
                || url.contains("citymapper://")
                || url.contains("comgooglemaps://")
                || url.contains("navigon://")
                || url.contains("transit://")
                || url.contains("waze://")
                || url.contains("yandexnavi://")
                || url.contains("uber://")
                || url.contains("tomtomhome://")
                || url.contains("com.sygic.aura://")
                || url.contains("here-route://")
                || url.contains("moovit://")
                || url.contains("lyft://")
                || url.contains("mapsme://")
                || url.contains("cabify://")
                || url.contains("baidumap://")
                || url.contains("lguthepay://")
                || url.contains("smartxpay-transfer://")
                || url.contains("smilepay://")
                || url.contains("supertoss://")
                || url.contains("hanawalletmembers://")
                || url.contains("wooripay://")
                || url.contains("shinsegaeeasypayment://")
                || url.contains("lpayapp://")
                || url.contains("lmslpay://")
                || url.contains("chai://")
                || url.contains("intmoney://")
                || url.contains("hanaskcardmobileportal://")
                || url.contains("ukbanksmartbanknonloginpay://")
                || url.contains("kdb-bankpay://")
                || url.contains("ibk-bankpay://")
                || url.contains("kb-bankpay://")
                || url.contains("keb-bankpay://")
                || url.contains("sh-bankpay://")
                || url.contains("nhb-bankpay://")
                || url.contains("nh-bankpay://")
                || url.contains("wr-bankpay://")
                || url.contains("sc-bankpay://")
                || url.contains("s-bankpay://")
                || url.contains("ct-bankpay://")
                || url.contains("dg-bankpay://")
                || url.contains("bnk-bankpay://")
                || url.contains("kj-bankpay://")
                || url.contains("jj-bankpay://")
                || url.contains("kn-bankpay://")
                || url.contains("kp-bankpay://")
                || url.contains("cu-bankpay://")
                || url.contains("mg-bankpay://")
                || url.contains("kbn-bankpa://y")
                || url.contains("kkb-bankpay://")

                //|| url.contains("ansimclick")
                //|| (url.contains("ansimclick") && !url.equals("ansimclick.hyundiacard.com"))
                || url.contains("market://details?id=com.shcard.smartpay")
                || url.contains("<http://m.ahnlab.com/kr/site/download>")
                || url.endsWith(".apk")

                //본인인증
                || url.contains("tauthlink://")
                || url.contains("ktauthexternalcall://")
                || url.contains("upluscorporation://")

                || url.contains("line://")//라인
                || url.contains("bandapp://")//네이버 밴드
                || url.contains("kakaotalk://")//카카오톡
                || url.contains("storylink://")
                || url.contains("kakaoplus://")
                || url.contains("kakaokompassauth://")
                || url.contains("storykompassauth://")
                || url.contains("kakaolink://")
                || url.contains("kakaotalk-5.9.7://")
                || url.contains("kakaostory-2.9.0://")
                || url.contains("naversearchapp")//네이버앱
                || url.contains("naversearchthirdlogin")
                || (url.contains("nidlogin") && !url.contains("naver.com"))
                || url.contains("daumapps://open")//다음
                || url.contains("googlechromes://")//크롬
                || url.contains("fb://")//페이스북
                || url.contains("fbapi://")
                || url.contains("fb-messenger-api://")
                || url.contains("fbauth2://")
                || url.contains("fbshareextension://")

            ) {
                LOG.d(LOG_TAG, "yellowin window.open >>>> url scheme 11111 " + url);
                try {
                    Intent intent = null;
                    // Intent intent = new Intent();
                    try {
                        intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
                        LOG.d(LOG_TAG, "yellowin window.open >>>> url scheme aaaaaaa " + url);
                    } catch (java.net.URISyntaxException ex) {
                        //ex.printStackTrace(); //code break
                        LOG.d(LOG_TAG, "yellowin window.open >>>> url scheme eeeeeee " + ex.getMessage());
                        override = false;
                    }

                    try {
                        cordova.getActivity().startActivity(intent);
                        override = true;
                    } catch (android.content.ActivityNotFoundException e) {
                        // chrome Version type
                        LOG.d(LOG_TAG, "yellowin window.open >>>> url scheme bbbbbb " + e.getMessage());

                        if (cordova.getActivity().getPackageManager().resolveActivity(intent, 0) == null) {
                            LOG.d(LOG_TAG, "yellowin window.open >>>> url scheme 33333 " + url);
                            String packagename = intent.getPackage();
                            // LOG.d(LOG_TAG, "yellowin url scheme 33333 packagename : " + packagename);
                            if (packagename != null) {
                                // Uri uri = Uri.parse("market://search?q=pname:" + packagename);
                                Uri uri = Uri.parse("market://details?id=" + packagename);
                                intent = new Intent(Intent.ACTION_VIEW, uri);
                                cordova.getActivity().startActivity(intent);
                                override = true;
                            }
                        } else {
                            LOG.d(LOG_TAG, "yellowin window.open >>>> url scheme 44444 " + url);
                            intent.addCategory(Intent.CATEGORY_BROWSABLE);
                            intent.setComponent(null);
                            try {
                                if (cordova.getActivity().startActivityIfNeeded(intent, -1)) {
                                    override = true;
                                }
                            } catch (android.content.ActivityNotFoundException ex) {
                                override = false;
                            }
                        }
                        LOG.d(LOG_TAG, "yellowin window.open >>>> url scheme 44444 " + url);
                        override = true;
                    }
                } catch (android.content.ActivityNotFoundException e) {
                    // Log.e("error ===>", e.getMessage());
                    LOG.e("yellowin url", "yellowin window.open >>>> url scheme ssssssss ");
                    //e.printStackTrace();  //code break
                    override = false;
                }
            }
             else if (url.contains("amoshair.co.kr")
                
                 // 본인인증
                 || url.contains("checkplus.co.kr")
                 || url.contains("safe.ok-name.co.kr")
                 || url.contains("mobile-ok.com")
                 || url.contains("teledit.com")
                 || url.contains("kcp.co.kr") // 결제 & 본인인증

                 // tags.bluekai.com
                 || url.contains("tags.bluekai.com")
                 || url.contains("astg.widerplanet.com")

                 // <https://pf.kakao.com>
                 // || url.contains("pf.kakao.com") // 카카오 채널...
                 || url.contains("nid.naver.com")
                 || url.contains("accounts.kakao.com")
                 || url.contains("kauth.kakao.com")
                 || url.contains("api.twitter.com")
                 || (url.contains("facebook.com") && url.contains("oauth"))
                 || url.contains("accounts.google.com")
                 || url.contains("account/login")

             ) {

                 LOG.d(LOG_TAG, "yellowin window.open yes url :::::::: " + url);

                 override = false;
             } else if (url != null) {
                 try {
                     Intent intent = null;
                     try {
                         intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);

                     } catch (Exception e) {
                         //e.printStackTrace();  //code break
                     }

                     Uri uri = Uri.parse(url);
                     intent = new Intent(Intent.ACTION_VIEW, uri);
                     cordova.getActivity().startActivity(intent);

                     override = true;

                 } catch (android.content.ActivityNotFoundException e) {
                     //e.printStackTrace();  //code break
                     override = false;
                 }

                 // 외부 브라우져로 열리는 url이면 창 닫기 0.3초후에 실행되도록 지연시간을 주어야 함.
                 new Handler(getMainLooper()).postDelayed(new Runnable() {
                     @Override
                     public void run() {
                         newWebView.destroy();
                         dialog_child.dismiss();
                     }
                 }, 300);

                 LOG.d(LOG_TAG, "yellowin window.open no url :::::::: " + url);
             }

            if (useBeforeload) {
                this.waitForBeforeload = true;
            }
            return override;
        }

        private boolean sendBeforeLoad(String url, String method) {
            try {
                JSONObject obj = new JSONObject();
                obj.put("type", BEFORELOAD);
                obj.put("url", url);
                if (method != null) {
                    obj.put("method", method);
                }
                sendUpdate(obj, true);
                return true;
            } catch (JSONException ex) {
                LOG.e(LOG_TAG, "URI passed in has caused a JSON error.");
            }
            return false;
        }

        /**
         * New (added in API 21)
         * For Android 5.0 and above.
         *
         * @param view
         * @param request
         */
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            return shouldInterceptRequest(request.getUrl().toString(), super.shouldInterceptRequest(view, request),
                    request.getMethod());
        }

        public WebResourceResponse shouldInterceptRequest(String url, WebResourceResponse response, String method) {
            return response;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            // MyLog.i(TAG,"onPageStarted(view:"+view+ ", url:"+url+ ",
            // favicon:"+favicon+")");
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            // MyLog.i(TAG,"onPageFinished(view:"+view+ ", url:"+url+")");
        }

        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            super.onReceivedError(view, request, error);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                // Log.i(TAG, "onReceivedError() " + error.getErrorCode() + " ---> " +
                // error.getDescription());
                onReceivedError(error.getErrorCode(), String.valueOf(error.getDescription()));

            }
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                // Log.i(TAG, "onReceivedError() " + errorCode + " ---> " + description);
                onReceivedError(errorCode, description);
            }

        }

        private void onReceivedError(int errorCode, String description) {
            // MyLog.i(getClass().getName(), "onReceivedError() " + errorCode + " ---> " +
            // description);
            switch (errorCode) {
                case WebViewClient.ERROR_TIMEOUT: // 연결 시간 초과
                case WebViewClient.ERROR_CONNECT: // 서버로 연결 실패
                    // case WebViewClient.ERROR_UNKNOWN: // 일반 오류
                case WebViewClient.ERROR_FILE_NOT_FOUND: // 404
                case WebViewClient.ERROR_HOST_LOOKUP:
                case WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME:
                case WebViewClient.ERROR_AUTHENTICATION:
                case WebViewClient.ERROR_PROXY_AUTHENTICATION:
                case WebViewClient.ERROR_IO:
                case WebViewClient.ERROR_REDIRECT_LOOP:
                case WebViewClient.ERROR_UNSUPPORTED_SCHEME:
                case WebViewClient.ERROR_FAILED_SSL_HANDSHAKE:
                case WebViewClient.ERROR_BAD_URL:
                case WebViewClient.ERROR_FILE:
                case WebViewClient.ERROR_TOO_MANY_REQUESTS:
                case WebViewClient.ERROR_UNSAFE_RESOURCE:
                    // MyLog.toastMakeTextShow(mApplicationContext,getClass().getName(),"WebViewClient,onReceivedError("+errorCode+")
                    // 에러 발생 " );;
                    // MyLog.e(TAG,"WebViewClient,onReceivedError("+errorCode+") 에러 발생 " );
                    break;
            }
        }
    }
    // yellowin yellowin window.open popupview WebViewClient선언 - end

    
    **// yellowin camera-chooser 추가 - start**
    // 카메라,갤러리 선택 호출 기능 구현
    private void yellowinChooser_tmp(boolean _isCapture, boolean _selectMultiple, String _acceptType) {
        LOG.d("yellowin", "yellowin yellowinChooser 000000");
        LOG.d("yellowin", "yellowin yellowinChooser 000000 _isCapture : " + _isCapture);
        LOG.d("yellowin", "yellowin yellowinChooser 000000 _selectMultiple : " + _selectMultiple);
        LOG.d("yellowin", "yellowin yellowinChooser 000000 _acceptType : " + _acceptType);
        Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Intent intentCamera_video = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

        this.applicationId = (String) BuildHelper.getBuildConfigValue(cordova.getActivity(), "APPLICATION_ID");
        this.applicationId = preferences.getString("applicationId", this.applicationId);

        File photo = createCaptureFile(1);
        // File video = createCaptureFile(2);
        this.imageFilePath = photo.getAbsolutePath();
        // this.videoFilePath = video.getAbsolutePath();

        this.imageUri = androidx.core.content.FileProvider.getUriForFile(cordova.getActivity(),
                applicationId + ".cordova.plugin.camera.provider", photo);
        // => 카메라 플러그인을 설치해야함. cordova plugin add cordova-plugin-camera

        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, this.imageUri);

        // We can write to this URI, this will hopefully allow us to write files to get
        // to the next step
        intentCamera.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        Boolean chooser_sel = true; // 카메라/갤러리 모두 선택할수 있는창 : true, 카메라 바로 실행이면 false

        if (_isCapture) {
            LOG.d("yellowin", "yellowin yellowinChooser 11111");
            LOG.d("yellowin", "yellowin _isCapture true 1111");
            // 바로 카메라 실행..

            cordova.startActivityForResult(InAppBrowser.this, intentCamera, FILECHOOSER_LOLLIPOP_REQ_CODE);

        }else{ // 선택팝업 카메라, 갤러리 둘다 띄우고 싶을 때
            LOG.d("yellowin","yellowin _isCapture false 1111");

            Intent pickIntent = new Intent(Intent.ACTION_PICK);

            pickIntent.setType(MediaStore.Images.Media.CONTENT_TYPE);
            pickIntent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

            //yellowin multi
            //////////// yellowin yellowin 멀티 업로드 추가 수정 시작 22

            pickIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, _selectMultiple);
            //////////// yellowin multi upload 추가 수정 끝 22

            String pickTitle = "사진 가져올 방법을 선택하세요.";
            Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);

            // 카메라 intent 포함시키기..
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{intentCamera});
//            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,new Parcelable[]{intentCamera_video});

            // cordova.startActivityForResult((CordovaPlugin) this,chooserIntent, FILECHOOSER_LOLLIPOP_REQ_CODE);

            if(_selectMultiple){
                //갤러리 이미지 multi 선택이라면, 기존 방식으로 결과 리턴로직 타도록 함.
                cordova.startActivityForResult((CordovaPlugin) this,chooserIntent, FILECHOOSER_REQUESTCODE);

                // cordova.startActivityForResult(InAppBrowser.this, Intent.createChooser(content, "Select File"), FILECHOOSER_REQUESTCODE);
            }else{
                cordova.startActivityForResult((CordovaPlugin) this,chooserIntent, FILECHOOSER_LOLLIPOP_REQ_CODE);
            }
        }
    }

    private void yellowinChooser(boolean _isCapture, boolean _selectMultiple, String _acceptType) {
        LOG.d("yellowin", "yellowin yellowinChooser 000000");

        // 권한 확인
        if (ContextCompat.checkSelfPermission(cordova.getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // 권한이 없으면 권한 요청
            LOG.d("yellowin", "yellowin yellowinChooser 000000 권한 체크~~~~");
            ActivityCompat.requestPermissions(
                    cordova.getActivity(),
                    new String[]{Manifest.permission.CAMERA},
                    CAMERA_PERMISSION_REQUEST_CODE
            );

            if (filePathCallbackLollipop != null) { // resultCode에 RESULT_OK가 들어오지 않으면 null 처리 한다.(이렇게 하지 않으면
                // 다음부터 input 태그를 클릭해도 반응하지 않음)

                Log.d("onActivityResult() ",
                        "FILECHOOSER_LOLLIPOP_REQ_CODE 의 if문의 filePathCallbackLollipop이 null이 아니면");
                filePathCallbackLollipop.onReceiveValue(null);
                filePathCallbackLollipop = null;
            }

            return; // 권한 요청 후 바로 리턴하여 카메라 호출을 막음
        }

        // 여기서부터는 권한이 허용된 경우에만 실행
        Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Intent intentCamera_video = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

        this.applicationId = (String) BuildHelper.getBuildConfigValue(cordova.getActivity(), "APPLICATION_ID");
        this.applicationId = preferences.getString("applicationId", this.applicationId);

        File photo = createCaptureFile(1);
        this.imageFilePath = photo.getAbsolutePath();

        this.imageUri = androidx.core.content.FileProvider.getUriForFile(
                cordova.getActivity(),
                applicationId + ".cordova.plugin.camera.provider",
                photo
        );

        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, this.imageUri);
        intentCamera.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        Boolean chooser_sel = true;

        if (_isCapture) {
            LOG.d("yellowin", "yellowin yellowinChooser 11111");
            cordova.startActivityForResult(InAppBrowser.this, intentCamera, FILECHOOSER_LOLLIPOP_REQ_CODE);
        } else {
            LOG.d("yellowin","yellowin _isCapture false 1111");
            Intent pickIntent = new Intent(Intent.ACTION_PICK);
            pickIntent.setType(MediaStore.Images.Media.CONTENT_TYPE);
            pickIntent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            pickIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, _selectMultiple);

            String pickTitle = "사진 가져올 방법을 선택하세요.";
            Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{intentCamera});

            if (_selectMultiple) {
                cordova.startActivityForResult((CordovaPlugin) this, chooserIntent, FILECHOOSER_REQUESTCODE);
            } else {
                cordova.startActivityForResult((CordovaPlugin) this, chooserIntent, FILECHOOSER_LOLLIPOP_REQ_CODE);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 권한이 허용되었을 때, 카메라를 다시 호출
                yellowinChooser(true, false, "image/*"); // 예시로 기본 파라미터 설정
            } else {
                // 권한이 거부된 경우 사용자에게 알림을 표시하거나 다른 처리를 수행할 수 있음
                LOG.d("yellowin", "Camera permission denied");
            }
        }
        cordova.getActivity().onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    **// yellowin camera-chooser 추가 - end

    // yellowin camera-chooser 추가 - start**
    private File createCaptureFile(int encodingType) {
        return createCaptureFile(encodingType, "");
    }

    private File createCaptureFile(int encodingType, String fileName) {
        if (fileName.isEmpty()) {
            // 아래 라이브러리를 상단에 추가해야함
            // import java.text.SimpleDateFormat;
            // import java.util.Date;
            String timeStamp = new SimpleDateFormat(TIME_FORMAT).format(new Date());
            fileName = timeStamp;
            // Append the current time in milliseconds for empty filename to differentiate
            // between multiple files selected via gallery
            fileName = "Pic_" + System.currentTimeMillis();
        }

        if (encodingType == JPEG) {
            fileName = fileName + JPEG_EXTENSION;
        } else if (encodingType == PNG) {
            fileName = fileName + PNG_EXTENSION;
        } else if (encodingType == 2) {
            LOG.d("yellowin", "yellowin filename encodingType : " + Integer.toString(encodingType));
            fileName = fileName + ".mp4";
        } else {
            throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
        }
        LOG.d("yellowin", "yellowin filename fileName : " + fileName);

        return new File(getTempDirectoryPath(), fileName);
    }

    private String getTempDirectoryPath() {
        File cache = cordova.getActivity().getCacheDir();
        // Create the cache directory if it doesn't exist
        cache.mkdirs();
        return cache.getAbsolutePath();
    }
    **// yellowin camera-chooser 추가 - end**

    /**
     * Create a new plugin success result and send it back to JavaScript
     *
     * @param obj a JSONObject contain event payload information
     */
    private void sendUpdate(JSONObject obj, boolean keepCallback) {
        sendUpdate(obj, keepCallback, PluginResult.Status.OK);
    }

    /**
     * Create a new plugin result and send it back to JavaScript
     *
     * @param obj a JSONObject contain event payload information
     * @param status the status code to return to the JavaScript environment
     */
    private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
        if (callbackContext != null) {
            PluginResult result = new PluginResult(status, obj);
            result.setKeepCallback(keepCallback);
            callbackContext.sendPluginResult(result);
            if (!keepCallback) {
                callbackContext = null;
            }
        }
    }

    **// yellowin camera-chooser 추가 - start
    //기존** onActivityResult 메소드를 아래로 대체해야함.
    /**
     * Receive File Data from File Chooser
     *
     * @param requestCode the requested code from chromeclient
     * @param resultCode the result code returned from android system
     * @param intent the data from android file chooser
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d("onActivityResult() ",
                "requestCode = " + Integer.toString(requestCode) + " / resultCode = " + Integer.toString(resultCode));

        switch (requestCode) {
            case FILECHOOSER_NORMAL_REQ_CODE:
                if (resultCode == Activity.RESULT_OK) {
                    if (filePathCallbackNormal == null)
                        return;
                    Uri result = (data == null || resultCode != RESULT_OK) ? null : data.getData();
                    // onReceiveValue 로 파일을 전송한다.
                    filePathCallbackNormal.onReceiveValue(result);
                    filePathCallbackNormal = null;
                }
                break;
            case FILECHOOSER_LOLLIPOP_REQ_CODE:
                Log.d("onActivityResult() ",
                        "FILECHOOSER_LOLLIPOP_REQ_CODE = " + Integer.toString(FILECHOOSER_LOLLIPOP_REQ_CODE));

                if (resultCode == Activity.RESULT_OK) {
                    Log.d("onActivityResult() ", "FILECHOOSER_LOLLIPOP_REQ_CODE 의 if문  RESULT_OK 안에 들어옴");

                    if (filePathCallbackLollipop == null)
                        return;
                    if (data == null) {
                        data = new Intent();
                    }
                    if (data.getData() == null) {
                        // data.setData(cameraImageUri);

                        data.setData(this.imageUri);
                    }

                    filePathCallbackLollipop
                            .onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                    filePathCallbackLollipop = null;
                } else {
                    Log.d("onActivityResult() ", "FILECHOOSER_LOLLIPOP_REQ_CODE 의 if문의 else문 안으로~");
                    if (filePathCallbackLollipop != null) { // resultCode에 RESULT_OK가 들어오지 않으면 null 처리하지 한다.(이렇게 하지 않으면
                                                            // 다음부터 input 태그를 클릭해도 반응하지 않음)

                        Log.d("onActivityResult() ",
                                "FILECHOOSER_LOLLIPOP_REQ_CODE 의 if문의 filePathCallbackLollipop이 null이 아니면");
                        filePathCallbackLollipop.onReceiveValue(null);
                        filePathCallbackLollipop = null;
                    }

                    if (filePathCallbackNormal != null) {
                        filePathCallbackNormal.onReceiveValue(null);
                        filePathCallbackNormal = null;
                    }
                }
                break;
            default:
                // 기본 파일첨부 처리(기존방식)

                //////////// yellowin yellowin 멀티 업로드 추가 수정 시작 22
                // mUploadCallback.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode,
                //////////// intent));
                // mUploadCallback = null;
                Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, data);
                LOG.d(LOG_TAG, "yellowin Receive file chooser URL: " + result);
                // Uri[] result = null;
                if (resultCode == Activity.RESULT_OK && data != null) {
                    if (data.getClipData() != null) {
                        // handle multiple-selected files
                        final int numSelectedFiles = data.getClipData().getItemCount();
                        result = new Uri[numSelectedFiles];
                        for (int i = 0; i < numSelectedFiles; i++) {
                            result[i] = data.getClipData().getItemAt(i).getUri();
                            LOG.d(LOG_TAG, "Receive file chooser URL: " + result[i]);
                        }
                    } else if (data.getData() != null) {
                        // handle single-selected file
                        result = WebChromeClient.FileChooserParams.parseResult(resultCode, data);
                        LOG.d(LOG_TAG, "yellowin Receive file chooser URL: " + result);
                    }
                } else {

                    Log.d("onActivityResult() ",
                            "FILECHOOSER_LOLLIPOP_REQ_CODE = " + Integer.toString(FILECHOOSER_LOLLIPOP_REQ_CODE));

                    if (resultCode == Activity.RESULT_OK)

                    // if (resultCode == 0)
                    {
                        Log.d("onActivityResult() ", "FILECHOOSER_LOLLIPOP_REQ_CODE 의 if문  RESULT_OK 안에 들어옴");

                        if (filePathCallbackLollipop == null)
                            return;
                        if (data == null) {
                            data = new Intent();
                        }
                        if (data.getData() == null) {
                            // data.setData(cameraImageUri);

                            data.setData(this.imageUri);
                        }

                        filePathCallbackLollipop
                                .onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                        filePathCallbackLollipop = null;
                    } else {
                        Log.d("onActivityResult() ", "FILECHOOSER_LOLLIPOP_REQ_CODE 의 if문의 else문 안으로~");
                        if (filePathCallbackLollipop != null) { // resultCode에 RESULT_OK가 들어오지 않으면 null 처리하지 한다.(이렇게 하지
                                                                // 않으면 다음부터 input 태그를 클릭해도 반응하지 않음)

                            Log.d("onActivityResult() ",
                                    "FILECHOOSER_LOLLIPOP_REQ_CODE 의 if문의 filePathCallbackLollipop이 null이 아니면");
                            filePathCallbackLollipop.onReceiveValue(null);
                            filePathCallbackLollipop = null;
                        }

                        if (filePathCallbackNormal != null) {
                            filePathCallbackNormal.onReceiveValue(null);
                            filePathCallbackNormal = null;
                        }
                    }
                    break;
                }

                //////////// filePathsCallback.onReceiveValue(result);
                filePathCallbackLollipop.onReceiveValue(result);
                filePathCallbackLollipop = null;
                // yellowin multi upload 추가 수정 끝 22

                break;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }
    **// yellowin camera-chooser 추가 - end**

    /**
     * The webview client receives notifications about appView
     */
    public class InAppBrowserClient extends WebViewClient {
        EditText edittext;
        CordovaWebView webView;
        String beforeload;
        boolean waitForBeforeload;

        /**
         * Constructor.
         *
         * @param webView
         * @param mEditText
         */
        public InAppBrowserClient(CordovaWebView webView, EditText mEditText, String beforeload) {
            this.webView = webView;
            this.edittext = mEditText;
            this.beforeload = beforeload;
            this.waitForBeforeload = beforeload != null;
        }

        /**
         * Override the URL that should be loaded
         *
         * Legacy (deprecated in API 24)
         * For Android 6 and below.
         *
         * @param webView
         * @param url
         */
        @SuppressWarnings("deprecation")
        @Override
        public boolean shouldOverrideUrlLoading(WebView webView, String url) {
            return shouldOverrideUrlLoading(url, null);
        }

        /**
         * Override the URL that should be loaded
         *
         * New (added in API 24)
         * For Android 7 and above.
         *
         * @param webView
         * @param request
         */
        @TargetApi(Build.VERSION_CODES.N)
        @Override
        public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request) {
            return shouldOverrideUrlLoading(request.getUrl().toString(), request.getMethod());
        }

        /**
         * Override the URL that should be loaded
         *
         * This handles a small subset of all the URIs that would be encountered.
         *
         * @param url
         * @param method
         */
        public boolean shouldOverrideUrlLoading(String url, String method) {
            boolean override = false;
            boolean useBeforeload = false;
            String errorMessage = null;

            if (beforeload.equals("yes") && method == null) {
                useBeforeload = true;
            } else if(beforeload.equals("yes")
                    //TODO handle POST requests then this condition can be removed:
                    && !method.equals("POST"))
            {
                useBeforeload = true;
            } else if(beforeload.equals("get") && (method == null || method.equals("GET"))) {
                useBeforeload = true;
            } else if(beforeload.equals("post") && (method == null || method.equals("POST"))) {
                //TODO handle POST requests
                errorMessage = "beforeload doesn't yet support POST requests";
            }

            // On first URL change, initiate JS callback. Only after the beforeload event, continue.
            if (useBeforeload && this.waitForBeforeload) {
                if(sendBeforeLoad(url, method)) {
                    return true;
                }
            }

            if(errorMessage != null) {
                try {
                    LOG.e(LOG_TAG, errorMessage);
                    JSONObject obj = new JSONObject();
                    obj.put("type", LOAD_ERROR_EVENT);
                    obj.put("url", url);
                    obj.put("code", -1);
                    obj.put("message", errorMessage);
                    sendUpdate(obj, true, PluginResult.Status.ERROR);
                } catch(Exception e) {
                    LOG.e(LOG_TAG, "Error sending loaderror for " + url + ": " + e.toString());
                }
            }

            // yellowin yellowin 외부 브라우져로 url 열기 시작
            if( url.contains("systempop=") ) {
                String[] array;
                array = url.split("systempop=");
                String url2 = array[1];

                LOG.d(LOG_TAG, "yellowin url window.open external link URL : " + url);

                try {
                    Intent intent = null;
                    Uri uri = Uri.parse(url2);
                    intent = new Intent(Intent.ACTION_VIEW, uri);
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    //e.printStackTrace();  //code break
                    override = false;
                }

            } else 
            if (url.startsWith(WebView.SCHEME_TEL)) {
                try {
                    Intent intent = new Intent(Intent.ACTION_DIAL);
                    intent.setData(Uri.parse(url));
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
                }
            } else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO)) {
                try {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setData(Uri.parse(url));
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
                }
            }
            // If sms:5551212?body=This is the message
            else if (url.startsWith("sms:")) {
                try {
                    Intent intent = new Intent(Intent.ACTION_VIEW);

                    // Get address
                    String address = null;
                    int parmIndex = url.indexOf('?');
                    if (parmIndex == -1) {
                        address = url.substring(4);
                    } else {
                        address = url.substring(4, parmIndex);

                        // If body, then set sms body
                        Uri uri = Uri.parse(url);
                        String query = uri.getQuery();
                        if (query != null) {
                            if (query.startsWith("body=")) {
                                intent.putExtra("sms_body", query.substring(5));
                            }
                        }
                    }
                    intent.setData(Uri.parse("sms:" + address));
                    intent.putExtra("address", address);
                    intent.setType("vnd.android-dir/mms-sms");
                    cordova.getActivity().startActivity(intent);
                    override = true;
                } catch (android.content.ActivityNotFoundException e) {
                    LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
                }
            }
            else if (url.startsWith("market:") 
                || url.startsWith("intent:")

                || url.startsWith("bandapp:")// 네이버 밴드
                || url.startsWith("kakaotalk:")// 카카오톡
                || url.startsWith("storylink:")
                || url.startsWith("kakaoplus:")
                || url.startsWith("kakaokompassauth:")
                || url.startsWith("storykompassauth:")
                || url.startsWith("kakaolink:")
                || url.startsWith("kakaotalk-5.9.7:")
                || url.startsWith("kakaostory-2.9.0:")
                || url.startsWith("naversearchapp:")// 네이버앱
                || url.startsWith("nidlogin:")
                || url.startsWith("naversearchthirdlogin:")
                || url.startsWith("daumapps:")// 다음
                || url.startsWith("googlechromes:")// 크롬
                || url.startsWith("fb:")// 페이스북
                // 본인인증
                || url.startsWith("tauthlink:")
                || url.startsWith("ktauthexternalcall:")
                || url.startsWith("upluscorporation:")

                // 결제
                || url.contains("com.kftc.bankpay.android://")
                || url.contains("com.lotte.lottesmartpay://")
                || url.contains("com.ahnlab.v3mobileplus://")
                || url.contains("hanaansim://")
                || url.contains("vguard://")
                || url.contains("droidxantivirus://")
                || url.contains("smshinhancardusim://")
                || url.contains("smartwall://")
                || url.contains("appfree://")

                || url.contains("kb-acp://")
                || url.contains("lguthepay://")
                || url.contains("v3mobile://")
                || url.contains("kakaopay://")

                || url.contains("kftc-bankpay://")
                || url.contains("ispmobile://")
                || url.contains("hdcardappcardansimclick://")
                || url.contains("smhyundaiansimclick://")
                || url.contains("shinhan-sr-ansimclick://")
                || url.contains("smshinhanansimclick://")
                || url.contains("nonghyupcardansimclick://")
                || url.contains("kb-acp://")
                || url.contains("mpocket.online.ansimclick://")
                || url.contains("ansimclickscard://")
                || url.contains("ansimclickipcollect://")
                || url.contains("vguardstart://")
                || url.contains("samsungpay://")
                || url.contains("scardcertiapp://")
                || url.contains("lottesmartpay://")
                || url.contains("lotteappcard://")
                || url.contains("cloudpay://")
                || url.contains("nhappvardansimclick://")
                || url.contains("nhappcardansimclick://")
                || url.contains("nhallonepayansimclick://")
                || url.contains("citispay://")
                || url.contains("citimobileapp://")
                || url.contains("citicardappkr://")
                || url.contains("payco://")
                || url.contains("paypin://")
                || url.contains("paycoapplogin://")
                || url.contains("tswansimclick://")
                || url.contains("bankwallet://")
                || url.contains("uppay://")
                || url.contains("kpay://")
                || url.contains("smilepayapp://")
                || url.contains("maps://")
                || url.contains("citymapper://")
                || url.contains("comgooglemaps://")
                || url.contains("navigon://")
                || url.contains("transit://")
                || url.contains("waze://")
                || url.contains("yandexnavi://")
                || url.contains("uber://")
                || url.contains("tomtomhome://")
                || url.contains("com.sygic.aura://")
                || url.contains("here-route://")
                || url.contains("moovit://")
                || url.contains("lyft://")
                || url.contains("mapsme://")
                || url.contains("cabify://")
                || url.contains("baidumap://")
                || url.contains("lguthepay://")
                || url.contains("smartxpay-transfer://")
                || url.contains("smilepay://")
                || url.contains("supertoss://")
                || url.contains("hanawalletmembers://")
                || url.contains("wooripay://")
                || url.contains("shinsegaeeasypayment://")
                || url.contains("lpayapp://")
                || url.contains("lmslpay://")
                || url.contains("chai://")
                || url.contains("intmoney://")
                || url.contains("hanaskcardmobileportal://")
                || url.contains("ukbanksmartbanknonloginpay://")
                || url.contains("kdb-bankpay://")
                || url.contains("ibk-bankpay://")
                || url.contains("kb-bankpay://")
                || url.contains("keb-bankpay://")
                || url.contains("sh-bankpay://")
                || url.contains("nhb-bankpay://")
                || url.contains("nh-bankpay://")
                || url.contains("wr-bankpay://")
                || url.contains("sc-bankpay://")
                || url.contains("s-bankpay://")
                || url.contains("ct-bankpay://")
                || url.contains("dg-bankpay://")
                || url.contains("bnk-bankpay://")
                || url.contains("kj-bankpay://")
                || url.contains("jj-bankpay://")
                || url.contains("kn-bankpay://")
                || url.contains("kp-bankpay://")
                || url.contains("cu-bankpay://")
                || url.contains("mg-bankpay://")
                || url.contains("kbn-bankpa://y")
                || url.contains("kkb-bankpay://")

                //|| url.contains("ansimclick")
                //|| (url.contains("ansimclick") && !url.equals("ansimclick.hyundiacard.com"))
                || url.contains("market://details?id=com.shcard.smartpay")
                || url.contains("<http://m.ahnlab.com/kr/site/download>")
                || url.endsWith(".apk")

                //본인인증
                || url.contains("tauthlink://")
                || url.contains("ktauthexternalcall://")
                || url.contains("upluscorporation://")

                || url.contains("line://")//라인
                || url.contains("bandapp://")//네이버 밴드
                || url.contains("kakaotalk://")//카카오톡
                || url.contains("storylink://")
                || url.contains("kakaoplus://")
                || url.contains("kakaokompassauth://")
                || url.contains("storykompassauth://")
                || url.contains("kakaolink://")
                || url.contains("kakaotalk-5.9.7://")
                || url.contains("kakaostory-2.9.0://")
                || url.contains("naversearchapp")//네이버앱
                || url.contains("naversearchthirdlogin")
                || (url.contains("nidlogin") && !url.contains("naver.com"))
                || url.contains("daumapps://open")//다음
                || url.contains("googlechromes://")//크롬
                || url.contains("fb://")//페이스북
                || url.contains("fbapi://")
                || url.contains("fb-messenger-api://")
                || url.contains("fbauth2://")
                || url.contains("fbshareextension://")
            ) {
                try {
                    Intent intent = null;
                    // Intent intent = new Intent();
                    try {
                        intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
                        LOG.d(LOG_TAG, "yellowin url scheme aaaaaaa " + url);
                    } catch (java.net.URISyntaxException ex) {
                        //ex.printStackTrace();  //code break
                        LOG.d(LOG_TAG, "yellowin url scheme eeeeeee " + ex.getMessage());
                        override = false;
                    }
                    try {
                        cordova.getActivity().startActivity(intent);
                        override = true;
                    } catch (android.content.ActivityNotFoundException e) {
                        // chrome Version type
                        LOG.d(LOG_TAG, "yellowin url scheme bbbbbb " + e.getMessage());

                        if (cordova.getActivity().getPackageManager().resolveActivity(intent, 0) == null) {
                            LOG.d(LOG_TAG, "yellowin url scheme 33333 " + url);
                            String packagename = intent.getPackage();
                            if (packagename != null) {
                                Uri uri = Uri.parse("market://search?q=pname:" + packagename);
                                intent = new Intent(Intent.ACTION_VIEW, uri);
                                cordova.getActivity().startActivity(intent);
                                override = true;
                            }
                        } else {
                            LOG.d(LOG_TAG, "yellowin url scheme 44444 " + url);
                            intent.addCategory(Intent.CATEGORY_BROWSABLE);
                            intent.setComponent(null);
                            try {
                                if (cordova.getActivity().startActivityIfNeeded(intent, -1)) {
                                    override = true;
                                }
                            } catch (android.content.ActivityNotFoundException ex) {
                                override = false;
                            }
                        }
                        override = true;
                    }
                } catch (android.content.ActivityNotFoundException e) {
                    // Log.e("error ===>", e.getMessage());
                    LOG.e("yellowin url", "yellowin url scheme ssssssss ");
                    ////e.printStackTrace();  //code break  //code break
                    override = false;
                }
            }
            // Test for whitelisted custom scheme names like mycoolapp:// or twitteroauthresponse:// (Twitter Oauth Response)
            else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^[A-Za-z0-9+.-]*://.*?$")) {
                if (allowedSchemes == null) {
                    String allowed = preferences.getString("AllowedSchemes", null);
                    if(allowed != null) {
                        allowedSchemes = allowed.split(",");
                    }
                }
                if (allowedSchemes != null) {
                    for (String scheme : allowedSchemes) {
                        if (url.startsWith(scheme)) {
                            try {
                                JSONObject obj = new JSONObject();
                                obj.put("type", "customscheme");
                                obj.put("url", url);
                                sendUpdate(obj, true);
                                override = true;
                            } catch (JSONException ex) {
                                LOG.e(LOG_TAG, "Custom Scheme URI passed in has caused a JSON error.");
                            }
                        }
                    }
                }
            }
            else if (url.startsWith("<https://devfo.amoshair.co.kr>")
            || url.startsWith("<http://devfo.amoshair.co.kr>")
            || url.startsWith("<https://stgfo.amoshair.co.kr>")
            || url.startsWith("<http://stgfo.amoshair.co.kr>")
            || url.startsWith("<https://amospro.amoshair.co.kr>")
            || url.startsWith("<http://amospro.amoshair.co.kr>")
            || url.contains("amoshair.co.kr")
                        
                // 본인인증
                || url.contains("checkplus.co.kr")
                || url.contains("safe.ok-name.co.kr")
                || url.contains("mobile-ok.com")
                || url.contains("teledit.com")
                || url.contains("kcp.co.kr") // 결제 & 본인인증

                // tags.bluekai.com
                || url.contains("tags.bluekai.com")
                || url.contains("astg.widerplanet.com")

                // <https://pf.kakao.com>
                // || url.contains("pf.kakao.com") // 카카오 채널...
                || url.contains("nid.naver.com")
                || url.contains("accounts.kakao.com")
                || url.contains("kauth.kakao.com")
                || url.contains("api.twitter.com")
                || (url.contains("facebook.com") && url.contains("oauth"))
                || url.contains("accounts.google.com")
                || url.contains("account/login")

                // 결제
                || url.contains("drmobile.inicis.com")
                || url.contains("mobilians.co.kr")
                || url.contains("alipay.com")
                || url.contains("allpayx.com")
                || url.contains("fcmobile.inicis.com")
                || url.contains("<http://aio.best>")
                || url.contains("smpay.kcp.co.kr")
                || url.contains("kcp.co.kr")
                || url.contains("ansimclick.hyundiacard.com")
                || url.contains("allatpay.com")
                || url.contains("xpay.lgdacom.net")
                || url.contains("pg-web.kakao.com") // 카카오
                // || url.contains("kakao.com")
                || url.contains("shinhancard.com")
                || url.contains("hyundaicard.com")
                || url.contains("ssgpay.com")
                || url.contains("payco.com")
                || url.contains("lpay.com")
                || url.contains("inicis.com")
                || url.contains("vpay.co.kr")
                || url.contains("bootpay.co.kr")
                || url.contains("allatpay.com")
                || url.contains("smilepay.co.kr")
                || url.contains("nicepay.co.kr")
                || url.contains("teledit.com")

                || url.contains("eximbay.com")
                || url.contains("paypal.com")
                || url.contains("paypalobjects.com")
                || url.contains("tpay.co.kr")
                || url.contains("uplus.co.kr")
                || url.contains("bankpay.or.kr")
                || url.contains("ksmobile.inicis.com")
                // || url.contains("kftc-bankpay")
                || url.contains("allthegate.com")
                || url.contains("iamport.kr")
                || url.contains("pay.toss")
                || url.contains("samsungcard.co.kr")
                || url.contains("samsungcard.com")
                || url.contains("samsungcard-ad.com")
                || url.contains("nonghyup.com")
                || url.contains("pay.tosspayments.com/card")
                || url.contains("acs.hanacard.co.kr")
                || url.contains("tosspayments.com")
                || url.contains("pay.naver.com")
                || url.contains("pstatic.net")
                || url.contains("paymentwall.com")
                || url.contains("pay.kakao.com")
                || url.contains("welcomepayments.co.kr")
                || url.contains("payletter.com")
                || url.contains("easypay.co.kr")
                || url.contains("citibank.co.kr")
                || url.contains("godo.co.kr")
                || url.contains("godomall.com")
                || url.contains("chai.finance")
                || url.contains("payapp.kr")
                || url.contains("payprotocol.io") // 페이코인
                || url.contains("yeskey.or.kr") // 현대카드 핀번호 결제
                || url.contains("billgate.net")
                || url.contains("passcall.co.kr")
                || url.contains("cnspay.co.kr") // 스마일페이
                || url.contains("mysmilepay.com")
                || url.contains("e-ncp.com")
            ) {

                LOG.d(LOG_TAG, "yellowin yellowin inappbrowser yes url :::::::: " + url);

                override = false;
            } else if (url != null) {
                try {
                    Intent intent = null;
                    try {
                        intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);

                    } catch (Exception e) {
                        //e.printStackTrace();  //code break
                    }

                    Uri uri = Uri.parse(url);
                    intent = new Intent(Intent.ACTION_VIEW, uri);
                    cordova.getActivity().startActivity(intent);

                    override = true;

                } catch (android.content.ActivityNotFoundException e) {
                    //e.printStackTrace();  //code break
                    override = false;
                }
                LOG.d(LOG_TAG, "yellowin yellowin inappbrowser no url :::::::: " + url);
            }

            if (useBeforeload) {
                this.waitForBeforeload = true;
            }
            return override;
        }

        private boolean sendBeforeLoad(String url, String method) {
            try {
                JSONObject obj = new JSONObject();
                obj.put("type", BEFORELOAD);
                obj.put("url", url);
                if(method != null) {
                    obj.put("method", method);
                }
                sendUpdate(obj, true);
                return true;
            } catch (JSONException ex) {
                LOG.e(LOG_TAG, "URI passed in has caused a JSON error.");
            }
            return false;
        }

        /**
         * New (added in API 21)
         * For Android 5.0 and above.
         *
         * @param view
         * @param request
         */
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            return shouldInterceptRequest(request.getUrl().toString(), super.shouldInterceptRequest(view, request), request.getMethod());
        }

        public WebResourceResponse shouldInterceptRequest(String url, WebResourceResponse response, String method) {
            return response;
        }

        /*
         * onPageStarted fires the LOAD_START_EVENT
         *
         * @param view
         * @param url
         * @param favicon
         */
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            String newloc = "";
            if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
                newloc = url;
            }
            else
            {
                // Assume that everything is HTTP at this point, because if we don't specify,
                // it really should be.  Complain loudly about this!!!
                LOG.e(LOG_TAG, "Possible Uncaught/Unknown URI");
                newloc = "http://" + url;
            }

            // Update the UI if we haven't already
            if (!newloc.equals(edittext.getText().toString())) {
                edittext.setText(newloc);
            }

            try {
                JSONObject obj = new JSONObject();
                obj.put("type", LOAD_START_EVENT);
                obj.put("url", newloc);
                sendUpdate(obj, true);
            } catch (JSONException ex) {
                LOG.e(LOG_TAG, "URI passed in has caused a JSON error.");
            }
        }

        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);

            LOG.d("","yellowin yellowin security~~~~ onPageFinished 1111");

            //yellowin yellowin 보안처리 - start
            if (detectDebugger() || detect_threadCpuTimeNanos()) {  //디버그 개발용

                String msg_val = "디버그모드가 감지되었습니다. 앱을 종료합니다.";

//                Log.e("Security", "yellowin Security This device is rooted. Exiting app. 333");

                new AlertDialog.Builder(cordova.getContext())
                        .setTitle("보안 경고")
                        .setMessage(msg_val)
                        .setPositiveButton("확인", null)
                        .setOnDismissListener(new DialogInterface.OnDismissListener() {
                            @Override
                            public void onDismiss(DialogInterface dialog) {
                                // 다이얼로그가 닫힐 때 앱을 종료합니다.
                                ThemeableBrowser.closeGlobalInstance();
                                InAppBrowser.closeGlobalInstance();
//                                        MainActivity.this.finish();
                            }
                        })
                        .show();
            }

            injectDeferredObject(
        "if (!window.webkit) { window.webkit = {}; }" +
                "if (!window.webkit.messageHandlers) { window.webkit.messageHandlers = {}; }" +

                // cordova_iab 인터페이스 추가
                "window.webkit.messageHandlers.cordova_iab = {" +
                "    postMessage: function(message) {" +
                "        if (typeof message === 'object') {" +
                "            message = JSON.stringify(message);" + // 객체를 JSON 문자열로 변환
                "        }" +
                "        cordova_iab.postMessage(message);" +
                "    }" +
                "};" +

                // firebase 인터페이스 추가
                "window.webkit.messageHandlers.firebase = {" +
                "    postMessage: function(message) {" +
                "        if (typeof message === 'object') {" +
                "            message = JSON.stringify(message);" + // 객체를 JSON 문자열로 변환
                "        }" +
                "        firebase.postMessage(message);" +
                "    }" +
                "};" +

                "if (!webkit) { var webkit = window.webkit; }",
                null
            );

            //  // yellowin yellowin toolbar button 뒤로가기 가능여부
            //  if (inAppWebView.canGoBack()) {
            //     // tabView1.setAlpha(1f);
            //     tabView1_flag = 0;
            // } else {
            //     // tabView1.setAlpha(0.3f);
            //     tabView1_flag = 1;
            // }

            //  cur_url = "";

            // CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
            CookieManager.getInstance().flush();

            // <https://issues.apache.org/jira/browse/CB-11248>
            view.clearFocus();
            view.requestFocus();

            try {
                JSONObject obj = new JSONObject();
                obj.put("type", LOAD_STOP_EVENT);
                obj.put("url", url);

                sendUpdate(obj, true);
            } catch (JSONException ex) {
                LOG.d(LOG_TAG, "Should never happen");
            }
          	// yellowin yellowin swipeRefreshLayout
            swipeRefreshLayout.setRefreshing(false);
        }

        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);

            try {
                JSONObject obj = new JSONObject();
                obj.put("type", LOAD_ERROR_EVENT);
                obj.put("url", failingUrl);
                obj.put("code", errorCode);
                obj.put("message", description);

                sendUpdate(obj, true, PluginResult.Status.ERROR);
            } catch (JSONException ex) {
                LOG.d(LOG_TAG, "Should never happen");
            }
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            super.onReceivedSslError(view, handler, error);
            try {
                JSONObject obj = new JSONObject();
                obj.put("type", LOAD_ERROR_EVENT);
                obj.put("url", error.getUrl());
                obj.put("code", 0);
                obj.put("sslerror", error.getPrimaryError());
                String message;
                switch (error.getPrimaryError()) {
                case SslError.SSL_DATE_INVALID:
                    message = "The date of the certificate is invalid";
                    break;
                case SslError.SSL_EXPIRED:
                    message = "The certificate has expired";
                    break;
                case SslError.SSL_IDMISMATCH:
                    message = "Hostname mismatch";
                    break;
                default:
                case SslError.SSL_INVALID:
                    message = "A generic error occurred";
                    break;
                case SslError.SSL_NOTYETVALID:
                    message = "The certificate is not yet valid";
                    break;
                case SslError.SSL_UNTRUSTED:
                    message = "The certificate authority is not trusted";
                    break;
                }
                obj.put("message", message);

                sendUpdate(obj, true, PluginResult.Status.ERROR);
            } catch (JSONException ex) {
                LOG.d(LOG_TAG, "Should never happen");
            }
            handler.cancel();
        }

        /**
         * On received http auth request.
         */
        @Override
        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {

            // Check if there is some plugin which can resolve this auth challenge
            PluginManager pluginManager = null;
            try {
                Method gpm = webView.getClass().getMethod("getPluginManager");
                pluginManager = (PluginManager)gpm.invoke(webView);
            } catch (NoSuchMethodException e) {
                LOG.d(LOG_TAG, e.getLocalizedMessage());
            } catch (IllegalAccessException e) {
                LOG.d(LOG_TAG, e.getLocalizedMessage());
            } catch (InvocationTargetException e) {
                LOG.d(LOG_TAG, e.getLocalizedMessage());
            }

            if (pluginManager == null) {
                try {
                    Field pmf = webView.getClass().getField("pluginManager");
                    pluginManager = (PluginManager)pmf.get(webView);
                } catch (NoSuchFieldException e) {
                    LOG.d(LOG_TAG, e.getLocalizedMessage());
                } catch (IllegalAccessException e) {
                    LOG.d(LOG_TAG, e.getLocalizedMessage());
                }
            }

            if (pluginManager != null && pluginManager.onReceivedHttpAuthRequest(webView, new CordovaHttpAuthHandler(handler), host, realm)) {
                return;
            }

            // By default handle 401 like we'd normally do!
            super.onReceivedHttpAuthRequest(view, handler, host, realm);
        }
    }
}

Powered by (주)옐로우윈