// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.android_webview;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ConsoleMessage;
import android.webkit.ValueCallback;
import org.chromium.base.ThreadUtils;
import org.chromium.content.browser.ContentViewCore;
/**
* Adapts the AwWebContentsDelegate interface to the AwContentsClient interface.
* This class also serves a secondary function of routing certain callbacks from the content layer
* to specific listener interfaces.
*/
class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
private static final String TAG = "AwWebContentsDelegateAdapter";
final AwContentsClient mContentsClient;
final View mContainerView;
public AwWebContentsDelegateAdapter(AwContentsClient contentsClient,
View containerView) {
mContentsClient = contentsClient;
mContainerView = containerView;
}
@Override
public void onLoadProgressChanged(int progress) {
mContentsClient.onProgressChanged(progress);
}
@Override
public void handleKeyboardEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
int direction;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_DOWN:
direction = View.FOCUS_DOWN;
break;
case KeyEvent.KEYCODE_DPAD_UP:
direction = View.FOCUS_UP;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
direction = View.FOCUS_LEFT;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
direction = View.FOCUS_RIGHT;
break;
default:
direction = 0;
break;
}
if (direction != 0 && tryToMoveFocus(direction)) return;
}
mContentsClient.onUnhandledKeyEvent(event);
}
@Override
public boolean takeFocus(boolean reverse) {
int direction =
(reverse == (mContainerView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL)) ?
View.FOCUS_RIGHT : View.FOCUS_LEFT;
if (tryToMoveFocus(direction)) return true;
direction = reverse ? View.FOCUS_UP : View.FOCUS_DOWN;
return tryToMoveFocus(direction);
}
private boolean tryToMoveFocus(int direction) {
View focus = mContainerView.focusSearch(direction);
return focus != null && focus != mContainerView && focus.requestFocus();
}
@Override
public boolean addMessageToConsole(int level, String message, int lineNumber,
String sourceId) {
ConsoleMessage.MessageLevel messageLevel = ConsoleMessage.MessageLevel.DEBUG;
switch(level) {
case LOG_LEVEL_TIP:
messageLevel = ConsoleMessage.MessageLevel.TIP;
break;
case LOG_LEVEL_LOG:
messageLevel = ConsoleMessage.MessageLevel.LOG;
break;
case LOG_LEVEL_WARNING:
messageLevel = ConsoleMessage.MessageLevel.WARNING;
break;
case LOG_LEVEL_ERROR:
messageLevel = ConsoleMessage.MessageLevel.ERROR;
break;
default:
Log.w(TAG, "Unknown message level, defaulting to DEBUG");
break;
}
return mContentsClient.onConsoleMessage(
new ConsoleMessage(message, sourceId, lineNumber, messageLevel));
}
@Override
public void onUpdateUrl(String url) {
// TODO: implement
}
@Override
public void openNewTab(String url, String extraHeaders, byte[] postData, int disposition) {
// This is only called in chrome layers.
assert false;
}
@Override
public void closeContents() {
mContentsClient.onCloseWindow();
}
@Override
public void showRepostFormWarningDialog(final ContentViewCore contentViewCore) {
// TODO(mkosiba) We should be using something akin to the JsResultReceiver as the
// callback parameter (instead of ContentViewCore) and implement a way of converting
// that to a pair of messages.
final int MSG_CONTINUE_PENDING_RELOAD = 1;
final int MSG_CANCEL_PENDING_RELOAD = 2;
// TODO(sgurun) Remember the URL to cancel the reload behavior
// if it is different than the most recent NavigationController entry.
final Handler handler = new Handler(ThreadUtils.getUiThreadLooper()) {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_CONTINUE_PENDING_RELOAD: {
contentViewCore.continuePendingReload();
break;
}
case MSG_CANCEL_PENDING_RELOAD: {
contentViewCore.cancelPendingReload();
break;
}
default:
throw new IllegalStateException(
"WebContentsDelegateAdapter: unhandled message " + msg.what);
}
}
};
Message resend = handler.obtainMessage(MSG_CONTINUE_PENDING_RELOAD);
Message dontResend = handler.obtainMessage(MSG_CANCEL_PENDING_RELOAD);
mContentsClient.onFormResubmission(dontResend, resend);
}
@Override
public void runFileChooser(final int processId, final int renderId, final int mode_flags,
String acceptTypes, String title, String defaultFilename, boolean capture) {
AwContentsClient.FileChooserParams params = new AwContentsClient.FileChooserParams();
params.mode = mode_flags;
params.acceptTypes = acceptTypes;
params.title = title;
params.defaultFilename = defaultFilename;
params.capture = capture;
mContentsClient.showFileChooser(new ValueCallback<String[]>() {
boolean completed = false;
@Override
public void onReceiveValue(String[] results) {
if (completed) {
throw new IllegalStateException("Duplicate showFileChooser result");
}
completed = true;
nativeFilesSelectedInChooser(processId, renderId, mode_flags, results);
}
}, params);
}
@Override
public boolean addNewContents(boolean isDialog, boolean isUserGesture) {
return mContentsClient.onCreateWindow(isDialog, isUserGesture);
}
@Override
public void activateContents() {
mContentsClient.onRequestFocus();
}
}