Home | History | Annotate | Download | only in android_webview
      1 // Copyright 2013 The Chromium Authors. 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.chromium.android_webview;
      6 
      7 import android.graphics.Rect;
      8 import android.os.Handler;
      9 import android.os.Looper;
     10 import android.os.Message;
     11 import android.util.Log;
     12 import android.view.KeyEvent;
     13 import android.view.View;
     14 import android.webkit.ConsoleMessage;
     15 import android.webkit.ValueCallback;
     16 
     17 import org.chromium.base.ThreadUtils;
     18 import org.chromium.content.browser.ContentViewCore;
     19 
     20 /**
     21  * Adapts the AwWebContentsDelegate interface to the AwContentsClient interface.
     22  * This class also serves a secondary function of routing certain callbacks from the content layer
     23  * to specific listener interfaces.
     24  */
     25 class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
     26     private static final String TAG = "AwWebContentsDelegateAdapter";
     27 
     28     final AwContentsClient mContentsClient;
     29     final View mContainerView;
     30 
     31     public AwWebContentsDelegateAdapter(AwContentsClient contentsClient,
     32             View containerView) {
     33         mContentsClient = contentsClient;
     34         mContainerView = containerView;
     35     }
     36 
     37     @Override
     38     public void onLoadProgressChanged(int progress) {
     39         mContentsClient.onProgressChanged(progress);
     40     }
     41 
     42     @Override
     43     public void handleKeyboardEvent(KeyEvent event) {
     44         if (event.getAction() == KeyEvent.ACTION_DOWN) {
     45             int direction;
     46             switch (event.getKeyCode()) {
     47                 case KeyEvent.KEYCODE_DPAD_DOWN:
     48                     direction = View.FOCUS_DOWN;
     49                     break;
     50                 case KeyEvent.KEYCODE_DPAD_UP:
     51                     direction = View.FOCUS_UP;
     52                     break;
     53                 case KeyEvent.KEYCODE_DPAD_LEFT:
     54                     direction = View.FOCUS_LEFT;
     55                     break;
     56                 case KeyEvent.KEYCODE_DPAD_RIGHT:
     57                     direction = View.FOCUS_RIGHT;
     58                     break;
     59                 default:
     60                     direction = 0;
     61                     break;
     62             }
     63             if (direction != 0 && tryToMoveFocus(direction)) return;
     64         }
     65         mContentsClient.onUnhandledKeyEvent(event);
     66     }
     67 
     68     @Override
     69     public boolean takeFocus(boolean reverse) {
     70         int direction =
     71             (reverse == (mContainerView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL)) ?
     72             View.FOCUS_RIGHT : View.FOCUS_LEFT;
     73         if (tryToMoveFocus(direction)) return true;
     74         direction = reverse ? View.FOCUS_UP : View.FOCUS_DOWN;
     75         return tryToMoveFocus(direction);
     76     }
     77 
     78     private boolean tryToMoveFocus(int direction) {
     79         View focus = mContainerView.focusSearch(direction);
     80         return focus != null && focus != mContainerView && focus.requestFocus();
     81     }
     82 
     83     @Override
     84     public boolean addMessageToConsole(int level, String message, int lineNumber,
     85             String sourceId) {
     86         ConsoleMessage.MessageLevel messageLevel = ConsoleMessage.MessageLevel.DEBUG;
     87         switch(level) {
     88             case LOG_LEVEL_TIP:
     89                 messageLevel = ConsoleMessage.MessageLevel.TIP;
     90                 break;
     91             case LOG_LEVEL_LOG:
     92                 messageLevel = ConsoleMessage.MessageLevel.LOG;
     93                 break;
     94             case LOG_LEVEL_WARNING:
     95                 messageLevel = ConsoleMessage.MessageLevel.WARNING;
     96                 break;
     97             case LOG_LEVEL_ERROR:
     98                 messageLevel = ConsoleMessage.MessageLevel.ERROR;
     99                 break;
    100             default:
    101                 Log.w(TAG, "Unknown message level, defaulting to DEBUG");
    102                 break;
    103         }
    104 
    105         return mContentsClient.onConsoleMessage(
    106                 new ConsoleMessage(message, sourceId, lineNumber, messageLevel));
    107     }
    108 
    109     @Override
    110     public void onUpdateUrl(String url) {
    111         // TODO: implement
    112     }
    113 
    114     @Override
    115     public void openNewTab(String url, String extraHeaders, byte[] postData, int disposition) {
    116         // This is only called in chrome layers.
    117         assert false;
    118     }
    119 
    120     @Override
    121     public boolean addNewContents(int nativeSourceWebContents, int nativeWebContents,
    122             int disposition, Rect initialPosition, boolean userGesture) {
    123         // This is overridden native side; see the other addNewContents overload.
    124         throw new RuntimeException("Impossible");
    125     }
    126 
    127     @Override
    128     public void closeContents() {
    129         mContentsClient.onCloseWindow();
    130     }
    131 
    132     @Override
    133     public void showRepostFormWarningDialog(final ContentViewCore contentViewCore) {
    134         // TODO(mkosiba) We should be using something akin to the JsResultReceiver as the
    135         // callback parameter (instead of ContentViewCore) and implement a way of converting
    136         // that to a pair of messages.
    137         final int MSG_CONTINUE_PENDING_RELOAD = 1;
    138         final int MSG_CANCEL_PENDING_RELOAD = 2;
    139 
    140         // TODO(sgurun) Remember the URL to cancel the reload behavior
    141         // if it is different than the most recent NavigationController entry.
    142         final Handler handler = new Handler(ThreadUtils.getUiThreadLooper()) {
    143             @Override
    144             public void handleMessage(Message msg) {
    145                 switch(msg.what) {
    146                     case MSG_CONTINUE_PENDING_RELOAD: {
    147                         contentViewCore.continuePendingReload();
    148                         break;
    149                     }
    150                     case MSG_CANCEL_PENDING_RELOAD: {
    151                         contentViewCore.cancelPendingReload();
    152                         break;
    153                     }
    154                     default:
    155                         throw new IllegalStateException(
    156                                 "WebContentsDelegateAdapter: unhandled message " + msg.what);
    157                 }
    158             }
    159         };
    160 
    161         Message resend = handler.obtainMessage(MSG_CONTINUE_PENDING_RELOAD);
    162         Message dontResend = handler.obtainMessage(MSG_CANCEL_PENDING_RELOAD);
    163         mContentsClient.onFormResubmission(dontResend, resend);
    164     }
    165 
    166     @Override
    167     public void runFileChooser(final int processId, final int renderId, final int mode_flags,
    168             String acceptTypes, String title, String defaultFilename, boolean capture) {
    169         AwContentsClient.FileChooserParams params = new AwContentsClient.FileChooserParams();
    170         params.mode = mode_flags;
    171         params.acceptTypes = acceptTypes;
    172         params.title = title;
    173         params.defaultFilename = defaultFilename;
    174         params.capture = capture;
    175 
    176         mContentsClient.showFileChooser(new ValueCallback<String[]>() {
    177             boolean completed = false;
    178             @Override
    179             public void onReceiveValue(String[] results) {
    180                 if (completed) {
    181                     throw new IllegalStateException("Duplicate showFileChooser result");
    182                 }
    183                 completed = true;
    184                 nativeFilesSelectedInChooser(processId, renderId, mode_flags, results);
    185             }
    186         }, params);
    187     }
    188 
    189     @Override
    190     public boolean addNewContents(boolean isDialog, boolean isUserGesture) {
    191         return mContentsClient.onCreateWindow(isDialog, isUserGesture);
    192     }
    193 
    194     @Override
    195     public void activateContents() {
    196         mContentsClient.onRequestFocus();
    197     }
    198 }
    199