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