1 // Copyright (c) 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.
5 package org.chromium.android_webview;
7 import android.graphics.Picture;
8 import android.os.Handler;
9 import android.os.Looper;
10 import android.os.Message;
11 import android.os.SystemClock;
13 import org.chromium.content.browser.ContentViewCore;
15 import java.util.concurrent.Callable;
18 * This class is responsible for calling certain client callbacks on the UI thread.
20 * Most callbacks do no go through here, but get forwarded to AwContentsClient directly. The
21 * messages processed here may originate from the IO or UI thread.
23 class AwContentsClientCallbackHelper {
25 // TODO(boliu): Consider removing DownloadInfo and LoginRequestInfo by using native
26 // MessageLoop to post directly to AwContents.
28 private static class DownloadInfo {
30 final String mUserAgent;
31 final String mContentDisposition;
32 final String mMimeType;
33 final long mContentLength;
35 DownloadInfo(String url,
37 String contentDisposition,
41 mUserAgent = userAgent;
42 mContentDisposition = contentDisposition;
44 mContentLength = contentLength;
48 private static class LoginRequestInfo {
50 final String mAccount;
53 LoginRequestInfo(String realm, String account, String args) {
60 private static class OnReceivedErrorInfo {
62 final String mDescription;
63 final String mFailingUrl;
65 OnReceivedErrorInfo(int errorCode, String description, String failingUrl) {
66 mErrorCode = errorCode;
67 mDescription = description;
68 mFailingUrl = failingUrl;
72 private final static int MSG_ON_LOAD_RESOURCE = 1;
73 private final static int MSG_ON_PAGE_STARTED = 2;
74 private final static int MSG_ON_DOWNLOAD_START = 3;
75 private final static int MSG_ON_RECEIVED_LOGIN_REQUEST = 4;
76 private final static int MSG_ON_RECEIVED_ERROR = 5;
77 private final static int MSG_ON_NEW_PICTURE = 6;
78 private final static int MSG_ON_SCALE_CHANGED_SCALED = 7;
80 // Minimum period allowed between consecutive onNewPicture calls, to rate-limit the callbacks.
81 private static final long ON_NEW_PICTURE_MIN_PERIOD_MILLIS = 500;
82 // Timestamp of the most recent onNewPicture callback.
83 private long mLastPictureTime = 0;
84 // True when a onNewPicture callback is currenly in flight.
85 private boolean mHasPendingOnNewPicture = false;
87 private final AwContentsClient mContentsClient;
89 private final Handler mHandler;
91 private class MyHandler extends Handler {
92 private MyHandler(Looper looper) {
97 public void handleMessage(Message msg) {
99 case MSG_ON_LOAD_RESOURCE: {
100 final String url = (String) msg.obj;
101 mContentsClient.onLoadResource(url);
104 case MSG_ON_PAGE_STARTED: {
105 final String url = (String) msg.obj;
106 mContentsClient.onPageStarted(url);
109 case MSG_ON_DOWNLOAD_START: {
110 DownloadInfo info = (DownloadInfo) msg.obj;
111 mContentsClient.onDownloadStart(info.mUrl, info.mUserAgent,
112 info.mContentDisposition, info.mMimeType, info.mContentLength);
115 case MSG_ON_RECEIVED_LOGIN_REQUEST: {
116 LoginRequestInfo info = (LoginRequestInfo) msg.obj;
117 mContentsClient.onReceivedLoginRequest(info.mRealm, info.mAccount, info.mArgs);
120 case MSG_ON_RECEIVED_ERROR: {
121 OnReceivedErrorInfo info = (OnReceivedErrorInfo) msg.obj;
122 mContentsClient.onReceivedError(info.mErrorCode, info.mDescription,
126 case MSG_ON_NEW_PICTURE: {
127 Picture picture = null;
129 if (msg.obj != null) picture = (Picture) ((Callable<?>) msg.obj).call();
130 } catch (Exception e) {
131 throw new RuntimeException("Error getting picture", e);
133 mContentsClient.onNewPicture(picture);
134 mLastPictureTime = SystemClock.uptimeMillis();
135 mHasPendingOnNewPicture = false;
138 case MSG_ON_SCALE_CHANGED_SCALED: {
139 float oldScale = Float.intBitsToFloat(msg.arg1);
140 float newScale = Float.intBitsToFloat(msg.arg2);
141 mContentsClient.onScaleChangedScaled(oldScale, newScale);
145 throw new IllegalStateException(
146 "AwContentsClientCallbackHelper: unhandled message " + msg.what);
151 public AwContentsClientCallbackHelper(Looper looper, AwContentsClient contentsClient) {
152 mHandler = new MyHandler(looper);
153 mContentsClient = contentsClient;
156 public void postOnLoadResource(String url) {
157 mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_LOAD_RESOURCE, url));
160 public void postOnPageStarted(String url) {
161 mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_PAGE_STARTED, url));
164 public void postOnDownloadStart(String url, String userAgent, String contentDisposition,
165 String mimeType, long contentLength) {
166 DownloadInfo info = new DownloadInfo(url, userAgent, contentDisposition, mimeType,
168 mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DOWNLOAD_START, info));
171 public void postOnReceivedLoginRequest(String realm, String account, String args) {
172 LoginRequestInfo info = new LoginRequestInfo(realm, account, args);
173 mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_RECEIVED_LOGIN_REQUEST, info));
176 public void postOnReceivedError(int errorCode, String description, String failingUrl) {
177 OnReceivedErrorInfo info = new OnReceivedErrorInfo(errorCode, description, failingUrl);
178 mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_RECEIVED_ERROR, info));
181 public void postOnNewPicture(Callable<Picture> pictureProvider) {
182 if (mHasPendingOnNewPicture) return;
183 mHasPendingOnNewPicture = true;
184 long pictureTime = java.lang.Math.max(mLastPictureTime + ON_NEW_PICTURE_MIN_PERIOD_MILLIS,
185 SystemClock.uptimeMillis());
186 mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ON_NEW_PICTURE, pictureProvider),
190 public void postOnScaleChangedScaled(float oldScale, float newScale) {
191 // The float->int->float conversion here is to avoid unnecessary allocations. The
192 // documentation states that intBitsToFloat(floatToIntBits(a)) == a for all values of a
193 // (except for NaNs which are collapsed to a single canonical NaN, but we don't care for
195 mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_SCALE_CHANGED_SCALED,
196 Float.floatToIntBits(oldScale), Float.floatToIntBits(newScale)));