Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core_internal / src / org / xwalk / core / internal / XWalkUIClientInternal.java
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.
4
5 package org.xwalk.core.internal;
6
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;
21
22 /**
23  * This class notifies the embedder UI events/callbacks.
24  */
25 @XWalkAPI(createExternally = true)
26 public class XWalkUIClientInternal {
27
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;
34
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;
44
45     /**
46      * Initiator
47      * @since 4.0
48      */
49     @XWalkAPI
50     public enum InitiateByInternal {
51         BY_USER_GESTURE,
52         BY_JAVASCRIPT
53     }
54
55     /**
56      * Constructor.
57      * @param view the owner XWalkViewInternal instance.
58      * @since 1.0
59      */
60     @XWalkAPI
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;
68         }
69         mXWalkView = view;
70         initResources();
71     }
72
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);
80     }
81
82     /**
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
88      * @since 4.0
89      */
90     @XWalkAPI
91     public boolean onCreateWindowRequested(XWalkViewInternal view, InitiateByInternal initiator,
92             ValueCallback<XWalkViewInternal> callback) {
93         return false;
94     }
95
96     /**
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
101      * @since 4.0
102      */
103     @XWalkAPI
104     public void onIconAvailable(XWalkViewInternal view, String url, Message startDownload) {
105     }
106
107     /**
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
112      * @since 4.0
113      */
114     @XWalkAPI
115     public void onReceivedIcon(XWalkViewInternal view, String url, Bitmap icon) {
116     }
117
118     /**
119      * Request display and focus for this XWalkViewInternal.
120      * @param view the owner XWalkViewInternal instance.
121      * @since 1.0
122      */
123     @XWalkAPI
124     public void onRequestFocus(XWalkViewInternal view) {
125     }
126
127     /**
128      * Notify the client to close the given XWalkViewInternal.
129      * @param view the owner XWalkViewInternal instance.
130      * @since 1.0
131      */
132     @XWalkAPI
133     public void onJavascriptCloseWindow(XWalkViewInternal view) {
134         if (view != null && view.getActivity() != null) {
135             view.getActivity().finish();
136         }
137     }
138
139     /**
140      * The type of JavaScript modal dialog.
141      * @since 1.0
142      */
143     @XWalkAPI
144     public enum JavascriptMessageTypeInternal {
145         /** JavaScript alert dialog. */
146         JAVASCRIPT_ALERT,
147         /** JavaScript confirm dialog. */
148         JAVASCRIPT_CONFIRM,
149         /** JavaScript prompt dialog. */
150         JAVASCRIPT_PROMPT,
151         /** JavaScript dialog for a window-before-unload notification. */
152         JAVASCRIPT_BEFOREUNLOAD
153     }
154
155     /**
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.
163      * @since 1.0
164      */
165     @XWalkAPI
166     public boolean onJavascriptModalDialog(XWalkViewInternal view, JavascriptMessageTypeInternal type,
167             String url, String message, String defaultValue, XWalkJavascriptResultInternal result) {
168         switch(type) {
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);
178             default:
179                 break;
180         }
181         assert(false);
182         return false;
183     }
184
185     /**
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.
189      * @since 1.0
190      */
191     @XWalkAPI
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);
200             } else {
201                 mOriginalForceNotFullscreen = false;
202             }
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);
213                 } else {
214                     if ((activity.getWindow().getAttributes().flags &
215                             WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
216                         mOriginalFullscreen = true;
217                     } else {
218                         mOriginalFullscreen = false;
219                         activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
220                     }
221                 }
222                 mIsFullscreen = true;
223             }
224         } else {
225             if (mOriginalForceNotFullscreen) {
226                 activity.getWindow().addFlags(
227                         WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
228             }
229             if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
230                 mDecorView.setSystemUiVisibility(mSystemUiFlag);
231             } else {
232                 // Clear the activity fullscreen flag.
233                 if (!mOriginalFullscreen) {
234                     activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
235                 }
236             }
237             mIsFullscreen = false;
238         }
239     }
240
241     /**
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
251      * @since 1.0
252      */
253     @XWalkAPI
254     public void openFileChooser(XWalkViewInternal view, ValueCallback<Uri> uploadFile,
255             String acceptType, String capture) {
256         uploadFile.onReceiveValue(null);
257     }
258
259     /**
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.
264      * @since 1.0
265      */
266     @XWalkAPI
267     public void onScaleChanged(XWalkViewInternal view, float oldScale, float newScale) {
268     }
269
270     /**
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.
276      *
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
281      *
282      * @since 2.1
283      */
284     @XWalkAPI
285     public boolean shouldOverrideKeyEvent(XWalkViewInternal view, KeyEvent event) {
286         return false;
287     }
288
289     /**
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.
295      *
296      * @param view The XWalkViewInternal that is initiating the callback.
297      * @param event The key event.
298      *
299      * @since 2.1
300      */
301     @XWalkAPI
302     public void onUnhandledKeyEvent(XWalkViewInternal view, KeyEvent event) {
303     }
304
305     /**
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.
309      * @since 2.1
310      */
311     @XWalkAPI
312     public void onReceivedTitle(XWalkViewInternal view, String title) {
313     }
314
315
316     /**
317      * The status when a page stopped loading
318      * @since 2.1
319      */
320     @XWalkAPI
321     public enum LoadStatusInternal {
322         /** Loading finished. */
323         FINISHED,
324         /** Loading failed. */
325         FAILED,
326         /** Loading cancelled by user. */
327         CANCELLED
328     }
329
330     /**
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.
336      *
337      * @param view The XWalkViewInternal that is initiating the callback.
338      * @param url The url to be loaded.
339      *
340      * @since 2.1
341      */
342     @XWalkAPI
343     public void onPageLoadStarted(XWalkViewInternal view, String url) {
344     }
345
346     /**
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.
350      *
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.
354      *
355      * @since 2.1
356      */
357     @XWalkAPI
358     public void onPageLoadStopped(XWalkViewInternal view, String url, LoadStatusInternal status) {
359     }
360
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)
366                 .setMessage(message)
367                 .setCancelable(true)
368                 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
369                     @Override
370                     public void onClick(DialogInterface dialog, int which) {
371                         fResult.confirm();
372                         dialog.dismiss();
373                     }
374                 })
375                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
376                     @Override
377                     public void onCancel(DialogInterface dialog) {
378                         fResult.cancel();
379                     }
380                 });
381         mDialog = dialogBuilder.create();
382         mDialog.show();
383         return false;
384     }
385
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)
391                 .setMessage(message)
392                 .setCancelable(true)
393                 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
394                     @Override
395                     public void onClick(DialogInterface dialog, int which) {
396                         fResult.confirm();
397                         dialog.dismiss();
398                     }
399                 })
400                 // Need to implement 'onClick' and call the dialog.cancel. Otherwise, the
401                 // UI will be locked.
402                 .setNegativeButton(mCancelButton, new DialogInterface.OnClickListener() {
403                     @Override
404                     public void onClick(DialogInterface dialog, int which) {
405                         // This will call OnCancelLisitener.onCancel().
406                         dialog.cancel();
407                     }
408                 })
409                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
410                     @Override
411                     public void onCancel(DialogInterface dialog) {
412                         fResult.cancel();
413                     }
414                 });
415         mDialog = dialogBuilder.create();
416         mDialog.show();
417         return false;
418     }
419
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)
425                 .setMessage(message)
426                 .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
427                     @Override
428                     public void onClick(DialogInterface dialog, int which) {
429                         fResult.confirmWithResult(mPromptText.getText().toString());
430                         dialog.dismiss();
431                     }
432                 })
433                 // Need to implement 'onClick' and call the dialog.cancel. Otherwise, the
434                 // UI will be locked.
435                 .setNegativeButton(mCancelButton, new DialogInterface.OnClickListener() {
436                     @Override
437                     public void onClick(DialogInterface dialog, int which) {
438                         // This will call OnCancelLisitener.onCancel().
439                         dialog.cancel();
440                     }
441                 })
442                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
443                     @Override
444                     public void onCancel(DialogInterface dialog) {
445                         fResult.cancel();
446                     }
447                 });
448         mPromptText = new EditText(mContext);
449         mPromptText.setVisibility(View.VISIBLE);
450         mPromptText.setText(defaultValue);
451         mPromptText.selectAll();
452
453         dialogBuilder.setView(mPromptText);
454         mDialog = dialogBuilder.create();
455         mDialog.show();
456         return false;
457     }
458 }