UNPKG

37.3 kBtext/x-java-sourceView Raw
1/*
2 Licensed to the Apache Software Foundation (ASF) under one
3 or more contributor license agreements. See the NOTICE file
4 distributed with this work for additional information
5 regarding copyright ownership. The ASF licenses this file
6 to you under the Apache License, Version 2.0 (the
7 "License"); you may not use this file except in compliance
8 with the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing,
13 software distributed under the License is distributed on an
14 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 KIND, either express or implied. See the License for the
16 specific language governing permissions and limitations
17 under the License.
18*/
19package org.apache.cordova.inappbrowser;
20
21import android.annotation.SuppressLint;
22import org.apache.cordova.inappbrowser.InAppBrowserDialog;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
26import android.content.res.Resources;
27import android.graphics.Bitmap;
28import android.graphics.drawable.Drawable;
29import android.net.Uri;
30import android.os.Build;
31import android.os.Bundle;
32import android.text.InputType;
33import android.util.Log;
34import android.util.TypedValue;
35import android.view.Gravity;
36import android.view.KeyEvent;
37import android.view.View;
38import android.view.Window;
39import android.view.WindowManager;
40import android.view.WindowManager.LayoutParams;
41import android.view.inputmethod.EditorInfo;
42import android.view.inputmethod.InputMethodManager;
43import com.amazon.android.webkit.AmazonWebChromeClient;
44import com.amazon.android.webkit.AmazonGeolocationPermissions.Callback;
45import com.amazon.android.webkit.AmazonJsPromptResult;
46import com.amazon.android.webkit.AmazonWebSettings;
47import com.amazon.android.webkit.AmazonWebStorage;
48import com.amazon.android.webkit.AmazonWebView;
49import com.amazon.android.webkit.AmazonWebViewClient;
50import com.amazon.android.webkit.AmazonCookieManager;
51import android.widget.Button;
52import android.widget.EditText;
53import android.widget.LinearLayout;
54import android.widget.RelativeLayout;
55
56import org.apache.cordova.CallbackContext;
57import org.apache.cordova.Config;
58import org.apache.cordova.CordovaArgs;
59import org.apache.cordova.CordovaPlugin;
60import org.apache.cordova.CordovaWebView;
61import org.apache.cordova.LOG;
62import org.apache.cordova.PluginResult;
63import org.apache.cordova.CordovaActivity;
64import org.json.JSONException;
65import org.json.JSONObject;
66
67import java.util.HashMap;
68import java.util.StringTokenizer;
69
70@SuppressLint("SetJavaScriptEnabled")
71public class InAppBrowser extends CordovaPlugin {
72
73 private static final String NULL = "null";
74 protected static final String LOG_TAG = "InAppBrowser";
75 private static final String SELF = "_self";
76 private static final String SYSTEM = "_system";
77 // private static final String BLANK = "_blank";
78 private static final String EXIT_EVENT = "exit";
79 private static final String LOCATION = "location";
80 private static final String HIDDEN = "hidden";
81 private static final String ZOOM = "zoom";
82 private static final String LOAD_START_EVENT = "loadstart";
83 private static final String LOAD_STOP_EVENT = "loadstop";
84 private static final String LOAD_ERROR_EVENT = "loaderror";
85 private static final String CLEAR_ALL_CACHE = "clearcache";
86 private static final String CLEAR_SESSION_CACHE = "clearsessioncache";
87 private static final String HARDWARE_BACK_BUTTON = "hardwareback";
88
89 private InAppBrowserDialog dialog;
90 private AmazonWebView inAppWebView;
91 private EditText edittext;
92 private CallbackContext callbackContext;
93 private boolean showLocationBar = true;
94 private boolean showZoomControls = true;
95 private boolean openWindowHidden = false;
96 private boolean clearAllCache= false;
97 private boolean clearSessionCache=false;
98 private boolean hadwareBackButton=true;
99
100 /**
101 * Executes the request and returns PluginResult.
102 *
103 * @param action The action to execute.
104 * @param args JSONArry of arguments for the plugin.
105 * @param callbackId The callback id used when calling back into JavaScript.
106 * @return A PluginResult object with a status and message.
107 */
108 public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
109 if (action.equals("open")) {
110 this.callbackContext = callbackContext;
111 final String url = args.getString(0);
112 String t = args.optString(1);
113 if (t == null || t.equals("") || t.equals(NULL)) {
114 t = SELF;
115 }
116 final String target = t;
117 final HashMap<String, Boolean> features = parseFeature(args.optString(2));
118
119 Log.d(LOG_TAG, "target = " + target);
120
121 this.cordova.getActivity().runOnUiThread(new Runnable() {
122 @Override
123 public void run() {
124 String result = "";
125 // SELF
126 if (SELF.equals(target)) {
127 Log.d(LOG_TAG, "in self");
128 // load in webview
129 if (url.startsWith("file://") || url.startsWith("javascript:")
130 || Config.isUrlWhiteListed(url)) {
131 Log.d(LOG_TAG, "loading in webview");
132 webView.loadUrl(url);
133 }
134 //Load the dialer
135 else if (url.startsWith(AmazonWebView.SCHEME_TEL))
136 {
137 try {
138 Log.d(LOG_TAG, "loading in dialer");
139 Intent intent = new Intent(Intent.ACTION_DIAL);
140 intent.setData(Uri.parse(url));
141 cordova.getActivity().startActivity(intent);
142 } catch (android.content.ActivityNotFoundException e) {
143 LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
144 }
145 }
146 // load in InAppBrowser
147 else {
148 Log.d(LOG_TAG, "loading in InAppBrowser");
149 result = showWebPage(url, features);
150 }
151 }
152 // SYSTEM
153 else if (SYSTEM.equals(target)) {
154 Log.d(LOG_TAG, "in system");
155 result = openExternal(url);
156 }
157 // BLANK - or anything else
158 else {
159 Log.d(LOG_TAG, "in blank");
160 result = showWebPage(url, features);
161 }
162
163 PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
164 pluginResult.setKeepCallback(true);
165 callbackContext.sendPluginResult(pluginResult);
166 }
167 });
168 }
169 else if (action.equals("close")) {
170 closeDialog();
171 }
172 else if (action.equals("injectScriptCode")) {
173 String jsWrapper = null;
174 if (args.getBoolean(1)) {
175 jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
176 }
177 injectDeferredObject(args.getString(0), jsWrapper);
178 }
179 else if (action.equals("injectScriptFile")) {
180 String jsWrapper;
181 if (args.getBoolean(1)) {
182 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());
183 } else {
184 jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
185 }
186 injectDeferredObject(args.getString(0), jsWrapper);
187 }
188 else if (action.equals("injectStyleCode")) {
189 String jsWrapper;
190 if (args.getBoolean(1)) {
191 jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
192 } else {
193 jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
194 }
195 injectDeferredObject(args.getString(0), jsWrapper);
196 }
197 else if (action.equals("injectStyleFile")) {
198 String jsWrapper;
199 if (args.getBoolean(1)) {
200 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());
201 } else {
202 jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
203 }
204 injectDeferredObject(args.getString(0), jsWrapper);
205 }
206 else if (action.equals("show")) {
207 this.cordova.getActivity().runOnUiThread(new Runnable() {
208 @Override
209 public void run() {
210 dialog.show();
211 }
212 });
213 PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
214 pluginResult.setKeepCallback(true);
215 this.callbackContext.sendPluginResult(pluginResult);
216 }
217 else if (action.equals("hide")) {
218 this.cordova.getActivity().runOnUiThread(new Runnable() {
219 @Override
220 public void run() {
221 dialog.hide();
222 }
223 });
224 PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
225 pluginResult.setKeepCallback(true);
226 this.callbackContext.sendPluginResult(pluginResult);
227 }
228 else {
229 return false;
230 }
231 return true;
232 }
233
234 /**
235 * Called when the view navigates.
236 */
237 @Override
238 public void onReset() {
239 closeDialog();
240 }
241
242 /**
243 * Called by AccelBroker when listener is to be shut down.
244 * Stop listener.
245 */
246 public void onDestroy() {
247 closeDialog();
248 }
249
250 /**
251 * Inject an object (script or style) into the InAppBrowser AmazonWebView.
252 *
253 * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
254 * provides a consistent method for injecting JavaScript code into the document.
255 *
256 * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
257 * quotes) and wrapped using string formatting. (The wrapper string should have a single
258 * '%s' marker)
259 *
260 * @param source The source object (filename or script/style text) to inject into
261 * the document.
262 * @param jsWrapper A JavaScript string to wrap the source string in, so that the object
263 * is properly injected, or null if the source string is JavaScript text
264 * which should be executed directly.
265 */
266 private void injectDeferredObject(String source, String jsWrapper) {
267 final String scriptToInject;
268 if (jsWrapper != null) {
269 org.json.JSONArray jsonEsc = new org.json.JSONArray();
270 jsonEsc.put(source);
271 String jsonRepr = jsonEsc.toString();
272 String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
273 scriptToInject = String.format(jsWrapper, jsonSourceString);
274 } else {
275 scriptToInject = source;
276 }
277 final String finalScriptToInject = scriptToInject;
278 this.cordova.getActivity().runOnUiThread(new Runnable() {
279 @SuppressLint("NewApi")
280 @Override
281 public void run() {
282 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
283 // This action will have the side-effect of blurring the currently focused element
284 inAppWebView.loadUrl("javascript:" + finalScriptToInject);
285 } /*else {
286 inAppWebView.evaluateJavascript(finalScriptToInject, null);
287 }*/
288 }
289 });
290 }
291
292 /**
293 * Put the list of features into a hash map
294 *
295 * @param optString
296 * @return
297 */
298 private HashMap<String, Boolean> parseFeature(String optString) {
299 if (optString.equals(NULL)) {
300 return null;
301 } else {
302 HashMap<String, Boolean> map = new HashMap<String, Boolean>();
303 StringTokenizer features = new StringTokenizer(optString, ",");
304 StringTokenizer option;
305 while(features.hasMoreElements()) {
306 option = new StringTokenizer(features.nextToken(), "=");
307 if (option.hasMoreElements()) {
308 String key = option.nextToken();
309 Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
310 map.put(key, value);
311 }
312 }
313 return map;
314 }
315 }
316
317 /**
318 * Display a new browser with the specified URL.
319 *
320 * @param url The url to load.
321 * @param usePhoneGap Load url in PhoneGap webview
322 * @return "" if ok, or error message.
323 */
324 public String openExternal(String url) {
325 try {
326 Intent intent = null;
327 intent = new Intent(Intent.ACTION_VIEW);
328 // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
329 // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
330 Uri uri = Uri.parse(url);
331 if ("file".equals(uri.getScheme())) {
332 intent.setDataAndType(uri, webView.getResourceApi().getMimeType(uri));
333 } else {
334 intent.setData(uri);
335 }
336 this.cordova.getActivity().startActivity(intent);
337 return "";
338 } catch (android.content.ActivityNotFoundException e) {
339 Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString());
340 return e.toString();
341 }
342 }
343
344 /**
345 * Closes the dialog
346 */
347 public void closeDialog() {
348 final AmazonWebView childView = this.inAppWebView;
349 // The JS protects against multiple calls, so this should happen only when
350 // closeDialog() is called by other native code.
351 if (childView == null) {
352 return;
353 }
354 this.cordova.getActivity().runOnUiThread(new Runnable() {
355 @Override
356 public void run() {
357 childView.setWebViewClient(new AmazonWebViewClient() {
358 // NB: wait for about:blank before dismissing
359 public void onPageFinished(AmazonWebView view, String url) {
360 if (dialog != null) {
361 dialog.dismiss();
362 }
363 }
364 });
365 // NB: From SDK 19: "If you call methods on WebView from any thread
366 // other than your app's UI thread, it can cause unexpected results."
367 // http://developer.android.com/guide/webapps/migrating.html#Threads
368 childView.loadUrl("about:blank");
369 }
370 });
371
372 try {
373 JSONObject obj = new JSONObject();
374 obj.put("type", EXIT_EVENT);
375 sendUpdate(obj, false);
376 } catch (JSONException ex) {
377 Log.d(LOG_TAG, "Should never happen");
378 }
379 }
380 /**
381 * Checks to see if it is possible to go back one page in history, then does so.
382 */
383 public void goBack() {
384 this.cordova.getActivity().runOnUiThread(new Runnable() {
385 public void run() {
386 if (InAppBrowser.this.inAppWebView.canGoBack()) {
387 InAppBrowser.this.inAppWebView.goBack();
388 }
389 }
390 });
391 }
392
393 /**
394 * Can the web browser go back?
395 * @return boolean
396 */
397 public boolean canGoBack() {
398 return this.inAppWebView.canGoBack();
399 }
400
401 /**
402 * Has the user set the hardware back button to go back
403 * @return boolean
404 */
405 public boolean hardwareBack() {
406 return hadwareBackButton;
407 }
408
409 /**
410 * Checks to see if it is possible to go forward one page in history, then does so.
411 */
412 private void goForward() {
413 this.cordova.getActivity().runOnUiThread(new Runnable() {
414 public void run() {
415 if (InAppBrowser.this.inAppWebView.canGoForward()) {
416 InAppBrowser.this.inAppWebView.goForward();
417 }
418 }
419 });
420 }
421
422 /**
423 * Navigate to the new page
424 *
425 * @param url to load
426 */
427 private void navigate(final String url) {
428 InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
429 imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
430
431 this.cordova.getActivity().runOnUiThread(new Runnable() {
432 public void run() {
433 if (!url.startsWith("http") && !url.startsWith("file:")) {
434 InAppBrowser.this.inAppWebView.loadUrl("http://" + url);
435 } else {
436 InAppBrowser.this.inAppWebView.loadUrl(url);
437 }
438 InAppBrowser.this.inAppWebView.requestFocus();
439 }
440 });
441 }
442
443
444 /**
445 * Should we show the location bar?
446 *
447 * @return boolean
448 */
449 private boolean getShowLocationBar() {
450 return this.showLocationBar;
451 }
452
453 /**
454 * Should we show the zoom controls?
455 *
456 * @return boolean
457 */
458 private boolean getShowZoomControls() {
459 return this.showZoomControls;
460 }
461
462 private InAppBrowser getInAppBrowser(){
463 return this;
464 }
465
466 /**
467 * Display a new browser with the specified URL.
468 *
469 * @param url The url to load.
470 * @param jsonObject
471 */
472 public String showWebPage(final String url, HashMap<String, Boolean> features) {
473 // Determine if we should hide the location bar.
474 showLocationBar = true;
475 showZoomControls = true;
476 openWindowHidden = false;
477 if (features != null) {
478 Boolean show = features.get(LOCATION);
479 if (show != null) {
480 showLocationBar = show.booleanValue();
481 }
482 Boolean zoom = features.get(ZOOM);
483 if (zoom != null) {
484 showZoomControls = zoom.booleanValue();
485 }
486 Boolean hidden = features.get(HIDDEN);
487 if (hidden != null) {
488 openWindowHidden = hidden.booleanValue();
489 }
490 Boolean hardwareBack = features.get(HARDWARE_BACK_BUTTON);
491 if (hardwareBack != null) {
492 hadwareBackButton = hardwareBack.booleanValue();
493 }
494 Boolean cache = features.get(CLEAR_ALL_CACHE);
495 if (cache != null) {
496 clearAllCache = cache.booleanValue();
497 } else {
498 cache = features.get(CLEAR_SESSION_CACHE);
499 if (cache != null) {
500 clearSessionCache = cache.booleanValue();
501 }
502 }
503 }
504
505 final CordovaWebView thatWebView = this.webView;
506
507 // Create dialog in new thread
508 Runnable runnable = new Runnable() {
509 /**
510 * Convert our DIP units to Pixels
511 *
512 * @return int
513 */
514 private int dpToPixels(int dipValue) {
515 int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,
516 (float) dipValue,
517 cordova.getActivity().getResources().getDisplayMetrics()
518 );
519
520 return value;
521 }
522
523 @SuppressLint("NewApi")
524 public void run() {
525 // Let's create the main dialog
526 dialog = new InAppBrowserDialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar);
527 dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
528 dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
529 dialog.setCancelable(true);
530 dialog.setInAppBroswer(getInAppBrowser());
531
532 // Main container layout
533 LinearLayout main = new LinearLayout(cordova.getActivity());
534 main.setOrientation(LinearLayout.VERTICAL);
535
536 // Toolbar layout
537 RelativeLayout toolbar = new RelativeLayout(cordova.getActivity());
538 //Please, no more black!
539 toolbar.setBackgroundColor(android.graphics.Color.LTGRAY);
540 toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44)));
541 toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
542 toolbar.setHorizontalGravity(Gravity.LEFT);
543 toolbar.setVerticalGravity(Gravity.TOP);
544
545 // Action Button Container layout
546 RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity());
547 actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
548 actionButtonContainer.setHorizontalGravity(Gravity.LEFT);
549 actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
550 actionButtonContainer.setId(1);
551
552 // Back button
553 Button back = new Button(cordova.getActivity());
554 RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
555 backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
556 back.setLayoutParams(backLayoutParams);
557 back.setContentDescription("Back Button");
558 back.setId(2);
559 Resources activityRes = cordova.getActivity().getResources();
560 int backResId = activityRes.getIdentifier("ic_action_previous_item", "drawable", cordova.getActivity().getPackageName());
561 Drawable backIcon = activityRes.getDrawable(backResId);
562 if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
563 {
564 back.setBackgroundDrawable(backIcon);
565 }
566 else
567 {
568 back.setBackground(backIcon);
569 }
570
571 back.setOnClickListener(new View.OnClickListener() {
572 public void onClick(View v) {
573 goBack();
574 }
575 });
576
577 // Forward button
578 Button forward = new Button(cordova.getActivity());
579 RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
580 forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
581 forward.setLayoutParams(forwardLayoutParams);
582 forward.setContentDescription("Forward Button");
583 forward.setId(3);
584 int fwdResId = activityRes.getIdentifier("ic_action_next_item", "drawable", cordova.getActivity().getPackageName());
585 Drawable fwdIcon = activityRes.getDrawable(fwdResId);
586 if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
587 {
588 forward.setBackgroundDrawable(fwdIcon);
589 }
590 else
591 {
592 forward.setBackground(fwdIcon);
593 }
594 forward.setOnClickListener(new View.OnClickListener() {
595 public void onClick(View v) {
596 goForward();
597 }
598 });
599
600 // Edit Text Box
601 edittext = new EditText(cordova.getActivity());
602 RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
603 textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
604 textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
605 edittext.setLayoutParams(textLayoutParams);
606 edittext.setId(4);
607 edittext.setSingleLine(true);
608 edittext.setText(url);
609 edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
610 edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
611 edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
612 edittext.setOnKeyListener(new View.OnKeyListener() {
613 public boolean onKey(View v, int keyCode, KeyEvent event) {
614 // If the event is a key-down event on the "enter" button
615 if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
616 navigate(edittext.getText().toString());
617 return true;
618 }
619 return false;
620 }
621 });
622
623 // Close/Done button
624 Button close = new Button(cordova.getActivity());
625 RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
626 closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
627 close.setLayoutParams(closeLayoutParams);
628 forward.setContentDescription("Close Button");
629 close.setId(5);
630 int closeResId = activityRes.getIdentifier("ic_action_remove", "drawable", cordova.getActivity().getPackageName());
631 Drawable closeIcon = activityRes.getDrawable(closeResId);
632 if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
633 {
634 close.setBackgroundDrawable(closeIcon);
635 }
636 else
637 {
638 close.setBackground(closeIcon);
639 }
640 close.setOnClickListener(new View.OnClickListener() {
641 public void onClick(View v) {
642 closeDialog();
643 }
644 });
645
646 // WebView
647 inAppWebView = new AmazonWebView(cordova.getActivity());
648
649 CordovaActivity app = (CordovaActivity) cordova.getActivity();
650 cordova.getFactory().initializeWebView(inAppWebView, 0x00FF00, false, null);
651
652 inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
653 inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
654 AmazonWebViewClient client = new InAppBrowserClient(thatWebView, edittext);
655 inAppWebView.setWebViewClient(client);
656 AmazonWebSettings settings = inAppWebView.getSettings();
657 settings.setJavaScriptEnabled(true);
658 settings.setJavaScriptCanOpenWindowsAutomatically(true);
659 settings.setBuiltInZoomControls(getShowZoomControls());
660 settings.setPluginState(com.amazon.android.webkit.AmazonWebSettings.PluginState.ON);
661
662 //Toggle whether this is enabled or not!
663 Bundle appSettings = cordova.getActivity().getIntent().getExtras();
664 boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
665 if (enableDatabase) {
666 String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
667 settings.setDatabasePath(databasePath);
668 settings.setDatabaseEnabled(true);
669 }
670 settings.setDomStorageEnabled(true);
671
672 if (clearAllCache) {
673 AmazonCookieManager.getInstance().removeAllCookie();
674 } else if (clearSessionCache) {
675 AmazonCookieManager.getInstance().removeSessionCookie();
676 }
677
678 inAppWebView.loadUrl(url);
679 inAppWebView.setId(6);
680 inAppWebView.getSettings().setLoadWithOverviewMode(true);
681 inAppWebView.getSettings().setUseWideViewPort(true);
682 inAppWebView.requestFocus();
683 inAppWebView.requestFocusFromTouch();
684
685 // Add the back and forward buttons to our action button container layout
686 actionButtonContainer.addView(back);
687 actionButtonContainer.addView(forward);
688
689 // Add the views to our toolbar
690 toolbar.addView(actionButtonContainer);
691 toolbar.addView(edittext);
692 toolbar.addView(close);
693
694 // Don't add the toolbar if its been disabled
695 if (getShowLocationBar()) {
696 // Add our toolbar to our main view/layout
697 main.addView(toolbar);
698 }
699
700 // Add our webview to our main view/layout
701 main.addView(inAppWebView);
702
703 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
704 lp.copyFrom(dialog.getWindow().getAttributes());
705 lp.width = WindowManager.LayoutParams.MATCH_PARENT;
706 lp.height = WindowManager.LayoutParams.MATCH_PARENT;
707
708 dialog.setContentView(main);
709 dialog.show();
710 dialog.getWindow().setAttributes(lp);
711 // the goal of openhidden is to load the url and not display it
712 // Show() needs to be called to cause the URL to be loaded
713 if(openWindowHidden) {
714 dialog.hide();
715 }
716 }
717 };
718 this.cordova.getActivity().runOnUiThread(runnable);
719 return "";
720 }
721
722 /**
723 * Create a new plugin success result and send it back to JavaScript
724 *
725 * @param obj a JSONObject contain event payload information
726 */
727 private void sendUpdate(JSONObject obj, boolean keepCallback) {
728 sendUpdate(obj, keepCallback, PluginResult.Status.OK);
729 }
730
731 /**
732 * Create a new plugin result and send it back to JavaScript
733 *
734 * @param obj a JSONObject contain event payload information
735 * @param status the status code to return to the JavaScript environment
736 */
737 private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
738 if (callbackContext != null) {
739 PluginResult result = new PluginResult(status, obj);
740 result.setKeepCallback(keepCallback);
741 callbackContext.sendPluginResult(result);
742 if (!keepCallback) {
743 callbackContext = null;
744 }
745 }
746 }
747
748 /**
749 * The webview client receives notifications about appView
750 */
751 public class InAppBrowserClient extends AmazonWebViewClient {
752 EditText edittext;
753 CordovaWebView webView;
754
755 /**
756 * Constructor.
757 *
758 * @param mContext
759 * @param edittext
760 */
761 public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
762 this.webView = webView;
763 this.edittext = mEditText;
764 }
765
766 /**
767 * Notify the host application that a page has started loading.
768 *
769 * @param view The webview initiating the callback.
770 * @param url The url of the page.
771 */
772 @Override
773 public void onPageStarted(AmazonWebView view, String url, Bitmap favicon) {
774 super.onPageStarted(view, url, favicon);
775 String newloc = "";
776 if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
777 newloc = url;
778 }
779 // If dialing phone (tel:5551212)
780 else if (url.startsWith(AmazonWebView.SCHEME_TEL)) {
781 try {
782 Intent intent = new Intent(Intent.ACTION_DIAL);
783 intent.setData(Uri.parse(url));
784 cordova.getActivity().startActivity(intent);
785 } catch (android.content.ActivityNotFoundException e) {
786 LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
787 }
788 }
789
790 else if (url.startsWith("geo:") || url.startsWith(AmazonWebView.SCHEME_MAILTO) || url.startsWith("market:")) {
791 try {
792 Intent intent = new Intent(Intent.ACTION_VIEW);
793 intent.setData(Uri.parse(url));
794 cordova.getActivity().startActivity(intent);
795 } catch (android.content.ActivityNotFoundException e) {
796 LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
797 }
798 }
799 // If sms:5551212?body=This is the message
800 else if (url.startsWith("sms:")) {
801 try {
802 Intent intent = new Intent(Intent.ACTION_VIEW);
803
804 // Get address
805 String address = null;
806 int parmIndex = url.indexOf('?');
807 if (parmIndex == -1) {
808 address = url.substring(4);
809 }
810 else {
811 address = url.substring(4, parmIndex);
812
813 // If body, then set sms body
814 Uri uri = Uri.parse(url);
815 String query = uri.getQuery();
816 if (query != null) {
817 if (query.startsWith("body=")) {
818 intent.putExtra("sms_body", query.substring(5));
819 }
820 }
821 }
822 intent.setData(Uri.parse("sms:" + address));
823 intent.putExtra("address", address);
824 intent.setType("vnd.android-dir/mms-sms");
825 cordova.getActivity().startActivity(intent);
826 } catch (android.content.ActivityNotFoundException e) {
827 LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
828 }
829 }
830 else {
831 newloc = "http://" + url;
832 }
833
834 if (!newloc.equals(edittext.getText().toString())) {
835 edittext.setText(newloc);
836 }
837
838 try {
839 JSONObject obj = new JSONObject();
840 obj.put("type", LOAD_START_EVENT);
841 obj.put("url", newloc);
842
843 sendUpdate(obj, true);
844 } catch (JSONException ex) {
845 Log.d(LOG_TAG, "Should never happen");
846 }
847 }
848
849 public void onPageFinished(AmazonWebView view, String url) {
850 super.onPageFinished(view, url);
851
852 try {
853 JSONObject obj = new JSONObject();
854 obj.put("type", LOAD_STOP_EVENT);
855 obj.put("url", url);
856
857 sendUpdate(obj, true);
858 } catch (JSONException ex) {
859 Log.d(LOG_TAG, "Should never happen");
860 }
861 }
862
863 public void onReceivedError(AmazonWebView view, int errorCode, String description, String failingUrl) {
864 super.onReceivedError(view, errorCode, description, failingUrl);
865
866 try {
867 JSONObject obj = new JSONObject();
868 obj.put("type", LOAD_ERROR_EVENT);
869 obj.put("url", failingUrl);
870 obj.put("code", errorCode);
871 obj.put("message", description);
872
873 sendUpdate(obj, true, PluginResult.Status.ERROR);
874 } catch (JSONException ex) {
875 Log.d(LOG_TAG, "Should never happen");
876 }
877 }
878 }
879}