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.net.Uri;
12 import android.os.Build.VERSION;
13 import android.os.Build.VERSION_CODES;
14 import android.view.KeyEvent;
15 import android.view.View;
16 import android.view.WindowManager;
17 import android.webkit.ValueCallback;
18 import android.widget.EditText;
21 * This class notifies the embedder UI events/callbacks.
23 public class XWalkUIClientInternal {
25 // Strings for displaying Dialog.
26 private static String mJSAlertTitle;
27 private static String mJSConfirmTitle;
28 private static String mJSPromptTitle;
29 private static String mOKButton;
30 private static String mCancelButton;
32 private Context mContext;
33 private AlertDialog mDialog;
34 private EditText mPromptText;
35 private int mSystemUiFlag;
36 private View mDecorView;
37 private XWalkViewInternal mXWalkView;
38 private boolean mOriginalFullscreen;
39 private boolean mOriginalForceNotFullscreen;
43 * @param view the owner XWalkViewInternal instance.
46 public XWalkUIClientInternal(XWalkViewInternal view) {
47 mContext = view.getContext();
48 mDecorView = view.getActivity().getWindow().getDecorView();
49 if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
50 mSystemUiFlag = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
51 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
52 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
58 private void initResources() {
59 if (mJSAlertTitle != null) return;
60 mJSAlertTitle = mContext.getString(R.string.js_alert_title);
61 mJSConfirmTitle = mContext.getString(R.string.js_confirm_title);
62 mJSPromptTitle = mContext.getString(R.string.js_prompt_title);
63 mOKButton = mContext.getString(android.R.string.ok);
64 mCancelButton = mContext.getString(android.R.string.cancel);
68 * Request display and focus for this XWalkViewInternal.
69 * @param view the owner XWalkViewInternal instance.
72 public void onRequestFocus(XWalkViewInternal view) {
76 * Notify the client to close the given XWalkViewInternal.
77 * @param view the owner XWalkViewInternal instance.
80 public void onJavascriptCloseWindow(XWalkViewInternal view) {
81 if (view != null && view.getActivity() != null) {
82 view.getActivity().finish();
87 * The type of JavaScript modal dialog.
90 public enum JavascriptMessageTypeInternal {
91 /** JavaScript alert dialog. */
93 /** JavaScript confirm dialog. */
95 /** JavaScript prompt dialog. */
97 /** JavaScript dialog for a window-before-unload notification. */
98 JAVASCRIPT_BEFOREUNLOAD
102 * Tell the client to display a prompt dialog to the user.
103 * @param view the owner XWalkViewInternal instance.
104 * @param type the type of JavaScript modal dialog.
105 * @param url the url of the web page which wants to show this dialog.
106 * @param message the message to be shown.
107 * @param defaultValue the default value string. Only valid for Prompt dialog.
108 * @param result the callback to handle the result from caller.
111 public boolean onJavascriptModalDialog(XWalkViewInternal view, JavascriptMessageTypeInternal type,
112 String url, String message, String defaultValue, XWalkJavascriptResultInternal result) {
114 case JAVASCRIPT_ALERT:
115 return onJsAlert(view, url, message, result);
116 case JAVASCRIPT_CONFIRM:
117 return onJsConfirm(view, url, message, result);
118 case JAVASCRIPT_PROMPT:
119 return onJsPrompt(view, url, message, defaultValue, result);
120 case JAVASCRIPT_BEFOREUNLOAD:
121 // Reuse onJsConfirm to show the dialog.
122 return onJsConfirm(view, url, message, result);
131 * Tell the client to toggle fullscreen mode.
132 * @param view the owner XWalkViewInternal instance.
133 * @param enterFullscreen true if it has entered fullscreen mode.
136 public void onFullscreenToggled(XWalkViewInternal view, boolean enterFullscreen) {
137 Activity activity = view.getActivity();
138 if (enterFullscreen) {
139 if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
140 mSystemUiFlag = mDecorView.getSystemUiVisibility();
141 mDecorView.setSystemUiVisibility(
142 View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
143 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
144 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
145 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
146 View.SYSTEM_UI_FLAG_FULLSCREEN |
147 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
148 if ((activity.getWindow().getAttributes().flags &
149 WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) != 0) {
150 mOriginalForceNotFullscreen = true;
151 activity.getWindow().clearFlags(
152 WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
154 mOriginalForceNotFullscreen = false;
157 if ((activity.getWindow().getAttributes().flags &
158 WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
159 mOriginalFullscreen = true;
161 mOriginalFullscreen = false;
162 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
166 if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
167 mDecorView.setSystemUiVisibility(mSystemUiFlag);
168 if (mOriginalForceNotFullscreen) {
169 activity.getWindow().addFlags(
170 WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
173 // Clear the activity fullscreen flag.
174 if (!mOriginalFullscreen) {
175 activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
182 * Tell the client to open a file chooser.
183 * @param view the owner XWalkViewInternal instance.
184 * @param uploadFile the callback class to handle the result from caller. It MUST
185 * be invoked in all cases. Leave it not invoked will block all following
186 * requests to open file chooser.
187 * @param acceptType value of the 'accept' attribute of the input tag associated
188 * with this file picker.
189 * @param capture value of the 'capture' attribute of the input tag associated
190 * with this file picker
193 public void openFileChooser(XWalkViewInternal view, ValueCallback<Uri> uploadFile,
194 String acceptType, String capture) {
195 uploadFile.onReceiveValue(null);
199 * Notify the client that the scale applied to the XWalkViewInternal has changed.
200 * @param view the owner XWalkViewInternal instance.
201 * @param oldScale the old scale before scaling.
202 * @param newScale the current scale factor after scaling.
205 public void onScaleChanged(XWalkViewInternal view, float oldScale, float newScale) {
209 * Give the host application a chance to handle the key event synchronously.
210 * e.g. menu shortcut key events need to be filtered this way. If return
211 * true, XWalkViewInternal will not handle the key event. If return false, XWalkViewInternal
212 * will always handle the key event, so none of the super in the view chain
213 * will see the key event. The default behavior returns false.
215 * @param view The XWalkViewInternal that is initiating the callback.
216 * @param event The key event.
217 * @return True if the host application wants to handle the key event
218 * itself, otherwise return false
222 public boolean shouldOverrideKeyEvent(XWalkViewInternal view, KeyEvent event) {
227 * Notify the host application that a key was not handled by the XWalkViewInternal.
228 * Except system keys, XWalkViewInternal always consumes the keys in the normal flow
229 * or if shouldOverrideKeyEvent returns true. This is called asynchronously
230 * from where the key is dispatched. It gives the host application a chance
231 * to handle the unhandled key events.
233 * @param view The XWalkViewInternal that is initiating the callback.
234 * @param event The key event.
238 public void onUnhandledKeyEvent(XWalkViewInternal view, KeyEvent event) {
242 * Notify the host application of a change in the document title.
243 * @param view The XWalkViewInternal that initiated the callback.
244 * @param title A String containing the new title of the document.
247 public void onReceivedTitle(XWalkViewInternal view, String title) {
252 * The status when a page stopped loading
255 public enum LoadStatusInternal {
256 /** Loading finished. */
258 /** Loading failed. */
260 /** Loading cancelled by user. */
265 * Notify the host application that a page has started loading. This method
266 * is called once for each main frame load so a page with iframes or
267 * framesets will call onPageLoadStarted one time for the main frame. This also
268 * means that onPageLoadStarted will not be called when the contents of an
269 * embedded frame changes, i.e. clicking a link whose target is an iframe.
271 * @param view The XWalkViewInternal that is initiating the callback.
272 * @param url The url to be loaded.
276 public void onPageLoadStarted(XWalkViewInternal view, String url) {
280 * Notify the host application that a page has stopped loading. This method
281 * is called only for main frame. When onPageLoadStopped() is called, the
282 * rendering picture may not be updated yet. To get the notification for the
283 * new Picture, use {@link XWalkViewInternal.PictureListener#onNewPicture}.
285 * @param view The XWalkViewInternal that is initiating the callback.
286 * @param url The url of the page.
287 * @param status The status when the page stopped loading.
291 public void onPageLoadStopped(XWalkViewInternal view, String url, LoadStatusInternal status) {
294 private boolean onJsAlert(XWalkViewInternal view, String url, String message,
295 XWalkJavascriptResultInternal result) {
296 final XWalkJavascriptResultInternal fResult = result;
297 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
298 dialogBuilder.setTitle(mJSAlertTitle)
301 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
303 public void onClick(DialogInterface dialog, int which) {
308 .setOnCancelListener(new DialogInterface.OnCancelListener() {
310 public void onCancel(DialogInterface dialog) {
314 mDialog = dialogBuilder.create();
319 private boolean onJsConfirm(XWalkViewInternal view, String url, String message,
320 XWalkJavascriptResultInternal result) {
321 final XWalkJavascriptResultInternal fResult = result;
322 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
323 dialogBuilder.setTitle(mJSConfirmTitle)
326 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
328 public void onClick(DialogInterface dialog, int which) {
333 // Need to implement 'onClick' and call the dialog.cancel. Otherwise, the
334 // UI will be locked.
335 .setNegativeButton(mCancelButton, new DialogInterface.OnClickListener() {
337 public void onClick(DialogInterface dialog, int which) {
338 // This will call OnCancelLisitener.onCancel().
342 .setOnCancelListener(new DialogInterface.OnCancelListener() {
344 public void onCancel(DialogInterface dialog) {
348 mDialog = dialogBuilder.create();
353 private boolean onJsPrompt(XWalkViewInternal view, String url, String message,
354 String defaultValue, XWalkJavascriptResultInternal result) {
355 final XWalkJavascriptResultInternal fResult = result;
356 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
357 dialogBuilder.setTitle(mJSPromptTitle)
359 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
361 public void onClick(DialogInterface dialog, int which) {
362 fResult.confirmWithResult(mPromptText.getText().toString());
366 // Need to implement 'onClick' and call the dialog.cancel. Otherwise, the
367 // UI will be locked.
368 .setNegativeButton(mCancelButton, new DialogInterface.OnClickListener() {
370 public void onClick(DialogInterface dialog, int which) {
371 // This will call OnCancelLisitener.onCancel().
375 .setOnCancelListener(new DialogInterface.OnCancelListener() {
377 public void onCancel(DialogInterface dialog) {
381 mPromptText = new EditText(mContext);
382 mPromptText.setVisibility(View.VISIBLE);
383 mPromptText.setText(defaultValue);
384 mPromptText.selectAll();
386 dialogBuilder.setView(mPromptText);
387 mDialog = dialogBuilder.create();