1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.xwalk.core.internal;
7 import android.app.Activity;
8 import android.app.AlertDialog;
9 import android.content.Context;
10 import android.content.DialogInterface;
11 import android.graphics.Bitmap;
12 import android.net.Uri;
13 import android.os.Build.VERSION;
14 import android.os.Build.VERSION_CODES;
15 import android.os.Message;
16 import android.view.KeyEvent;
17 import android.view.View;
18 import android.view.WindowManager;
19 import android.webkit.ValueCallback;
20 import android.widget.EditText;
23 * This class notifies the embedder UI events/callbacks.
25 @XWalkAPI(createExternally = true)
26 public class XWalkUIClientInternal {
28 // Strings for displaying Dialog.
29 private static String mJSAlertTitle;
30 private static String mJSConfirmTitle;
31 private static String mJSPromptTitle;
32 private static String mOKButton;
33 private static String mCancelButton;
35 private Context mContext;
36 private AlertDialog mDialog;
37 private EditText mPromptText;
38 private int mSystemUiFlag;
39 private View mDecorView;
40 private XWalkViewInternal mXWalkView;
41 private boolean mOriginalFullscreen;
42 private boolean mOriginalForceNotFullscreen;
43 private boolean mIsFullscreen = false;
50 public enum InitiateByInternal {
57 * @param view the owner XWalkViewInternal instance.
61 public XWalkUIClientInternal(XWalkViewInternal view) {
62 mContext = view.getContext();
63 mDecorView = view.getActivity().getWindow().getDecorView();
64 if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
65 mSystemUiFlag = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
66 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
67 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
73 private void initResources() {
74 if (mJSAlertTitle != null) return;
75 mJSAlertTitle = mContext.getString(R.string.js_alert_title);
76 mJSConfirmTitle = mContext.getString(R.string.js_confirm_title);
77 mJSPromptTitle = mContext.getString(R.string.js_prompt_title);
78 mOKButton = mContext.getString(android.R.string.ok);
79 mCancelButton = mContext.getString(android.R.string.cancel);
83 * Request the host application to create a new window
84 * @param view The XWalkView which initiate the request for a new window
85 * @param initiator How the request was initiated
86 * @param callback Callback when once a new XWalkView has been created
87 * @return Return true if the host application will create a new window
91 public boolean onCreateWindowRequested(XWalkViewInternal view, InitiateByInternal initiator,
92 ValueCallback<XWalkViewInternal> callback) {
97 * Notify the host application that an icon is available, send the message to start the downloading
98 * @param view The XWalkView that icon belongs to
99 * @param url The icon url
100 * @param startDownload Message to initiate icon download
104 public void onIconAvailable(XWalkViewInternal view, String url, Message startDownload) {
108 * Notify the host application of a new icon has been downloaded
109 * @param view The XWalkView that icon belongs to
110 * @param url The icon url
111 * @param icon The icon image
115 public void onReceivedIcon(XWalkViewInternal view, String url, Bitmap icon) {
119 * Request display and focus for this XWalkViewInternal.
120 * @param view the owner XWalkViewInternal instance.
124 public void onRequestFocus(XWalkViewInternal view) {
128 * Notify the client to close the given XWalkViewInternal.
129 * @param view the owner XWalkViewInternal instance.
133 public void onJavascriptCloseWindow(XWalkViewInternal view) {
134 if (view != null && view.getActivity() != null) {
135 view.getActivity().finish();
140 * The type of JavaScript modal dialog.
144 public enum JavascriptMessageTypeInternal {
145 /** JavaScript alert dialog. */
147 /** JavaScript confirm dialog. */
149 /** JavaScript prompt dialog. */
151 /** JavaScript dialog for a window-before-unload notification. */
152 JAVASCRIPT_BEFOREUNLOAD
156 * Tell the client to display a prompt dialog to the user.
157 * @param view the owner XWalkViewInternal instance.
158 * @param type the type of JavaScript modal dialog.
159 * @param url the url of the web page which wants to show this dialog.
160 * @param message the message to be shown.
161 * @param defaultValue the default value string. Only valid for Prompt dialog.
162 * @param result the callback to handle the result from caller.
166 public boolean onJavascriptModalDialog(XWalkViewInternal view, JavascriptMessageTypeInternal type,
167 String url, String message, String defaultValue, XWalkJavascriptResultInternal result) {
169 case JAVASCRIPT_ALERT:
170 return onJsAlert(view, url, message, result);
171 case JAVASCRIPT_CONFIRM:
172 return onJsConfirm(view, url, message, result);
173 case JAVASCRIPT_PROMPT:
174 return onJsPrompt(view, url, message, defaultValue, result);
175 case JAVASCRIPT_BEFOREUNLOAD:
176 // Reuse onJsConfirm to show the dialog.
177 return onJsConfirm(view, url, message, result);
186 * Tell the client to toggle fullscreen mode.
187 * @param view the owner XWalkViewInternal instance.
188 * @param enterFullscreen true if it has entered fullscreen mode.
192 public void onFullscreenToggled(XWalkViewInternal view, boolean enterFullscreen) {
193 Activity activity = view.getActivity();
194 if (enterFullscreen) {
195 if ((activity.getWindow().getAttributes().flags &
196 WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) != 0) {
197 mOriginalForceNotFullscreen = true;
198 activity.getWindow().clearFlags(
199 WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
201 mOriginalForceNotFullscreen = false;
203 if (!mIsFullscreen) {
204 if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
205 mSystemUiFlag = mDecorView.getSystemUiVisibility();
206 mDecorView.setSystemUiVisibility(
207 View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
208 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
209 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
210 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
211 View.SYSTEM_UI_FLAG_FULLSCREEN |
212 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
214 if ((activity.getWindow().getAttributes().flags &
215 WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
216 mOriginalFullscreen = true;
218 mOriginalFullscreen = false;
219 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
222 mIsFullscreen = true;
225 if (mOriginalForceNotFullscreen) {
226 activity.getWindow().addFlags(
227 WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
229 if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
230 mDecorView.setSystemUiVisibility(mSystemUiFlag);
232 // Clear the activity fullscreen flag.
233 if (!mOriginalFullscreen) {
234 activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
237 mIsFullscreen = false;
242 * Tell the client to open a file chooser.
243 * @param view the owner XWalkViewInternal instance.
244 * @param uploadFile the callback class to handle the result from caller. It MUST
245 * be invoked in all cases. Leave it not invoked will block all following
246 * requests to open file chooser.
247 * @param acceptType value of the 'accept' attribute of the input tag associated
248 * with this file picker.
249 * @param capture value of the 'capture' attribute of the input tag associated
250 * with this file picker
254 public void openFileChooser(XWalkViewInternal view, ValueCallback<Uri> uploadFile,
255 String acceptType, String capture) {
256 uploadFile.onReceiveValue(null);
260 * Notify the client that the scale applied to the XWalkViewInternal has changed.
261 * @param view the owner XWalkViewInternal instance.
262 * @param oldScale the old scale before scaling.
263 * @param newScale the current scale factor after scaling.
267 public void onScaleChanged(XWalkViewInternal view, float oldScale, float newScale) {
271 * Give the host application a chance to handle the key event synchronously.
272 * e.g. menu shortcut key events need to be filtered this way. If return
273 * true, XWalkViewInternal will not handle the key event. If return false, XWalkViewInternal
274 * will always handle the key event, so none of the super in the view chain
275 * will see the key event. The default behavior returns false.
277 * @param view The XWalkViewInternal that is initiating the callback.
278 * @param event The key event.
279 * @return True if the host application wants to handle the key event
280 * itself, otherwise return false
285 public boolean shouldOverrideKeyEvent(XWalkViewInternal view, KeyEvent event) {
290 * Notify the host application that a key was not handled by the XWalkViewInternal.
291 * Except system keys, XWalkViewInternal always consumes the keys in the normal flow
292 * or if shouldOverrideKeyEvent returns true. This is called asynchronously
293 * from where the key is dispatched. It gives the host application a chance
294 * to handle the unhandled key events.
296 * @param view The XWalkViewInternal that is initiating the callback.
297 * @param event The key event.
302 public void onUnhandledKeyEvent(XWalkViewInternal view, KeyEvent event) {
306 * Notify the host application of a change in the document title.
307 * @param view The XWalkViewInternal that initiated the callback.
308 * @param title A String containing the new title of the document.
312 public void onReceivedTitle(XWalkViewInternal view, String title) {
317 * The status when a page stopped loading
321 public enum LoadStatusInternal {
322 /** Loading finished. */
324 /** Loading failed. */
326 /** Loading cancelled by user. */
331 * Notify the host application that a page has started loading. This method
332 * is called once for each main frame load so a page with iframes or
333 * framesets will call onPageLoadStarted one time for the main frame. This also
334 * means that onPageLoadStarted will not be called when the contents of an
335 * embedded frame changes, i.e. clicking a link whose target is an iframe.
337 * @param view The XWalkViewInternal that is initiating the callback.
338 * @param url The url to be loaded.
343 public void onPageLoadStarted(XWalkViewInternal view, String url) {
347 * Notify the host application that a page has stopped loading. This method
348 * is called only for main frame. When onPageLoadStopped() is called, the
349 * rendering picture may not be updated yet.
351 * @param view The XWalkViewInternal that is initiating the callback.
352 * @param url The url of the page.
353 * @param status The status when the page stopped loading.
358 public void onPageLoadStopped(XWalkViewInternal view, String url, LoadStatusInternal status) {
361 private boolean onJsAlert(XWalkViewInternal view, String url, String message,
362 XWalkJavascriptResultInternal result) {
363 final XWalkJavascriptResultInternal fResult = result;
364 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
365 dialogBuilder.setTitle(mJSAlertTitle)
368 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
370 public void onClick(DialogInterface dialog, int which) {
375 .setOnCancelListener(new DialogInterface.OnCancelListener() {
377 public void onCancel(DialogInterface dialog) {
381 mDialog = dialogBuilder.create();
386 private boolean onJsConfirm(XWalkViewInternal view, String url, String message,
387 XWalkJavascriptResultInternal result) {
388 final XWalkJavascriptResultInternal fResult = result;
389 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
390 dialogBuilder.setTitle(mJSConfirmTitle)
393 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
395 public void onClick(DialogInterface dialog, int which) {
400 // Need to implement 'onClick' and call the dialog.cancel. Otherwise, the
401 // UI will be locked.
402 .setNegativeButton(mCancelButton, new DialogInterface.OnClickListener() {
404 public void onClick(DialogInterface dialog, int which) {
405 // This will call OnCancelLisitener.onCancel().
409 .setOnCancelListener(new DialogInterface.OnCancelListener() {
411 public void onCancel(DialogInterface dialog) {
415 mDialog = dialogBuilder.create();
420 private boolean onJsPrompt(XWalkViewInternal view, String url, String message,
421 String defaultValue, XWalkJavascriptResultInternal result) {
422 final XWalkJavascriptResultInternal fResult = result;
423 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
424 dialogBuilder.setTitle(mJSPromptTitle)
426 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
428 public void onClick(DialogInterface dialog, int which) {
429 fResult.confirmWithResult(mPromptText.getText().toString());
433 // Need to implement 'onClick' and call the dialog.cancel. Otherwise, the
434 // UI will be locked.
435 .setNegativeButton(mCancelButton, new DialogInterface.OnClickListener() {
437 public void onClick(DialogInterface dialog, int which) {
438 // This will call OnCancelLisitener.onCancel().
442 .setOnCancelListener(new DialogInterface.OnCancelListener() {
444 public void onCancel(DialogInterface dialog) {
448 mPromptText = new EditText(mContext);
449 mPromptText.setVisibility(View.VISIBLE);
450 mPromptText.setText(defaultValue);
451 mPromptText.selectAll();
453 dialogBuilder.setView(mPromptText);
454 mDialog = dialogBuilder.create();