Methods Summary |
---|
public void | addJavascriptInterface(java.lang.Object obj, java.lang.String interfaceName)Use this function to bind an object to Javascript so that the
methods can be accessed from Javascript.
IMPORTANT:
- Using addJavascriptInterface() allows JavaScript to control your
application. This can be a very useful feature or a dangerous security
issue. When the HTML in the WebView is untrustworthy (for example, part
or all of the HTML is provided by some person or process), then an
attacker could inject HTML that will execute your code and possibly any
code of the attacker's choosing.
Do not use addJavascriptInterface() unless all of the HTML in this
WebView was written by you.
- The Java object that is bound runs in another thread and not in
the thread that it was constructed in.
// Use Hashmap rather than Bundle as Bundles can't cope with Objects
HashMap arg = new HashMap();
arg.put("object", obj);
arg.put("interfaceName", interfaceName);
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
|
private void | calcOurContentVisibleRect(android.graphics.Rect r)
calcOurVisibleRect(r);
r.left = viewToContent(r.left);
r.top = viewToContent(r.top);
r.right = viewToContent(r.right);
r.bottom = viewToContent(r.bottom);
|
private void | calcOurVisibleRect(android.graphics.Rect r)
Point p = new Point();
getGlobalVisibleRect(r, p);
r.offset(-p.x, -p.y);
|
public boolean | canGoBack()Return true if this WebView has a back history item.
WebBackForwardList l = mCallbackProxy.getBackForwardList();
synchronized (l) {
if (l.getClearPending()) {
return false;
} else {
return l.getCurrentIndex() > 0;
}
}
|
public boolean | canGoBackOrForward(int steps)Return true if the page can go back or forward the given
number of steps.
WebBackForwardList l = mCallbackProxy.getBackForwardList();
synchronized (l) {
if (l.getClearPending()) {
return false;
} else {
int newIndex = l.getCurrentIndex() + steps;
return newIndex >= 0 && newIndex < l.getSize();
}
}
|
public boolean | canGoForward()Return true if this WebView has a forward history item.
WebBackForwardList l = mCallbackProxy.getBackForwardList();
synchronized (l) {
if (l.getClearPending()) {
return false;
} else {
return l.getCurrentIndex() < l.getSize() - 1;
}
}
|
private boolean | canZoomScrollOut()
if (mContentWidth == 0 || mContentHeight == 0) {
return false;
}
int width = getViewWidth();
int height = getViewHeight();
float x = (float) width / (float) mContentWidth;
float y = (float) height / (float) mContentHeight;
mZoomScrollLimit = Math.max(DEFAULT_MIN_ZOOM_SCALE, Math.min(x, y));
mZoomScrollInvLimit = 1.0f / mZoomScrollLimit;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "canZoomScrollOut"
+ " mInvActualScale=" + mInvActualScale
+ " mZoomScrollLimit=" + mZoomScrollLimit
+ " mZoomScrollInvLimit=" + mZoomScrollInvLimit
+ " mContentWidth=" + mContentWidth
+ " mContentHeight=" + mContentHeight
);
}
// don't zoom out unless magnify area is at least half as wide
// or tall as content
float limit = mZoomScrollLimit * 2;
return mContentWidth >= width * limit
|| mContentHeight >= height * limit;
|
public android.graphics.Picture | capturePicture()Return a new picture that captures the current display of the webview.
This is a copy of the display, and will be unaffected if the webview
later loads a different URL.
if (null == mWebViewCore) return null; // check for out of memory tab
return mWebViewCore.copyContentPicture();
|
public void | clearCache(boolean includeDiskFiles)Clear the resource cache. This will cause resources to be re-downloaded
if accessed again.
Note: this really needs to be a static method as it clears cache for all
WebView. But we need mWebViewCore to send message to WebCore thread, so
we can't make this static.
mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
includeDiskFiles ? 1 : 0, 0);
|
public void | clearFormData()Make sure that clearing the form data removes the adapter from the
currently focused textfield if there is one.
if (inEditingMode()) {
AutoCompleteAdapter adapter = null;
mTextEntry.setAdapterCustom(adapter);
}
|
public void | clearHistory()Tell the WebView to clear its internal back/forward list.
mCallbackProxy.getBackForwardList().setClearPending();
mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
|
public void | clearMatches()
mFindIsUp = false;
nativeSetFindIsDown();
// Now that the dialog has been removed, ensure that we scroll to a
// location that is not beyond the end of the page.
pinScrollTo(mScrollX, mScrollY, false, 0);
invalidate();
|
public void | clearSslPreferences()Clear the SSL preferences table stored in response to proceeding with SSL
certificate errors.
mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
|
private void | clearTextEntry()
if (inEditingMode()) {
mTextEntry.remove();
}
|
public void | clearView()Clear the view so that onDraw() will draw nothing but white background,
and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY
mContentWidth = 0;
mContentHeight = 0;
mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
|
private boolean | commitCopy()
boolean copiedSomething = false;
if (mExtendSelection) {
// copy region so core operates on copy without touching orig.
Region selection = new Region(nativeGetSelection());
if (selection.isEmpty() == false) {
Toast.makeText(mContext
, com.android.internal.R.string.text_copied
, Toast.LENGTH_SHORT).show();
mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
copiedSomething = true;
}
mExtendSelection = false;
}
mShiftIsPressed = false;
if (mTouchMode == TOUCH_SELECT_MODE) {
mTouchMode = TOUCH_INIT_MODE;
}
return copiedSomething;
|
private static int | computeDuration(int dx, int dy)
int distance = Math.max(Math.abs(dx), Math.abs(dy));
int duration = distance * 1000 / STD_SPEED;
return Math.min(duration, MAX_DURATION);
|
protected int | computeHorizontalScrollRange()
if (mDrawHistory) {
return mHistoryWidth;
} else {
return contentToView(mContentWidth);
}
|
public void | computeScroll()
if (mScroller.computeScrollOffset()) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = mScroller.getCurrX();
mScrollY = mScroller.getCurrY();
postInvalidate(); // So we draw again
if (oldX != mScrollX || oldY != mScrollY) {
// as onScrollChanged() is not called, sendOurVisibleRect()
// needs to be call explicitly
sendOurVisibleRect();
}
} else {
super.computeScroll();
}
|
protected int | computeVerticalScrollRange()
if (mDrawHistory) {
return mHistoryHeight;
} else {
int height = contentToView(mContentHeight);
if (mFindIsUp) {
height += FIND_HEIGHT;
}
return height;
}
|
private void | contentSizeChanged(boolean updateLayout)These are from webkit, and are in content coordinate system (unzoomed)
// suppress 0,0 since we usually see real dimensions soon after
// this avoids drawing the prev content in a funny place. If we find a
// way to consolidate these notifications, this check may become
// obsolete
if ((mContentWidth | mContentHeight) == 0) {
return;
}
if (mHeightCanMeasure) {
if (getMeasuredHeight() != contentToView(mContentHeight)
&& updateLayout) {
requestLayout();
}
} else if (mWidthCanMeasure) {
if (getMeasuredWidth() != contentToView(mContentWidth)
&& updateLayout) {
requestLayout();
}
} else {
// If we don't request a layout, try to send our view size to the
// native side to ensure that WebCore has the correct dimensions.
sendViewSizeZoom();
}
|
private int | contentToView(int x)
return Math.round(x * mActualScale);
|
private android.graphics.Rect | contentToView(android.graphics.Rect x)
return new Rect(contentToView(x.left), contentToView(x.top)
, contentToView(x.right), contentToView(x.bottom));
|
public WebBackForwardList | copyBackForwardList()Return the WebBackForwardList for this WebView. This contains the
back/forward list for use in querying each item in the history stack.
This is a copy of the private WebBackForwardList so it contains only a
snapshot of the current state. Multiple calls to this method may return
different objects. The object returned from this method will not be
updated to reflect any new state.
return mCallbackProxy.getBackForwardList().clone();
|
private android.webkit.WebView$ExtendedZoomControls | createZoomControls()
ExtendedZoomControls zoomControls = new ExtendedZoomControls(mContext
, null);
zoomControls.setOnZoomInClickListener(new OnClickListener() {
public void onClick(View v) {
// reset time out
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
mPrivateHandler.postDelayed(mZoomControlRunnable,
ZOOM_CONTROLS_TIMEOUT);
zoomIn();
}
});
zoomControls.setOnZoomOutClickListener(new OnClickListener() {
public void onClick(View v) {
// reset time out
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
mPrivateHandler.postDelayed(mZoomControlRunnable,
ZOOM_CONTROLS_TIMEOUT);
zoomOut();
}
});
zoomControls.setOnZoomMagnifyClickListener(new OnClickListener() {
public void onClick(View v) {
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
mPrivateHandler.postDelayed(mZoomControlRunnable,
ZOOM_CONTROLS_TIMEOUT);
zoomScrollOut();
}
});
return zoomControls;
|
public void | debugDump()
nativeDebugDump();
mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
|
void | deleteSelection(int start, int end)Delete text from start to end in the focused textfield. If there is no
focus, or if start == end, silently fail. If start and end are out of
order, swap them.
/* package */
mTextGeneration++;
mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end,
new WebViewCore.FocusData(mFocusData));
|
public void | destroy()Destroy the internal state of the WebView. This method should be called
after the WebView has been removed from the view system. No other
methods may be called on a WebView after destroy.
clearTextEntry();
if (mWebViewCore != null) {
// Set the handlers to null before destroying WebViewCore so no
// more messages will be posted.
mCallbackProxy.setWebViewClient(null);
mCallbackProxy.setWebChromeClient(null);
// Tell WebViewCore to destroy itself
WebViewCore webViewCore = mWebViewCore;
mWebViewCore = null; // prevent using partial webViewCore
webViewCore.destroy();
// Remove any pending messages that might not be serviced yet.
mPrivateHandler.removeCallbacksAndMessages(null);
mCallbackProxy.removeCallbacksAndMessages(null);
// Wake up the WebCore thread just in case it is waiting for a
// javascript dialog.
synchronized (mCallbackProxy) {
mCallbackProxy.notify();
}
}
if (mNativeClass != 0) {
nativeDestroy();
mNativeClass = 0;
}
|
public static void | disablePlatformNotifications()If platform notifications are enabled, this should be called
from onPause() or onStop().
Network.disablePlatformNotifications();
|
public boolean | dispatchKeyEvent(android.view.KeyEvent event)
boolean dispatch = true;
if (!inEditingMode()) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mGotKeyDown = true;
} else {
if (!mGotKeyDown) {
/*
* We got a key up for which we were not the recipient of
* the original key down. Don't give it to the view.
*/
dispatch = false;
}
mGotKeyDown = false;
}
}
if (dispatch) {
return super.dispatchKeyEvent(event);
} else {
// We didn't dispatch, so let something else handle the key
return false;
}
|
private void | displaySoftKeyboard()
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mTextEntry, 0);
mTextEntry.enableScrollOnScreen(true);
// Now we need to fake a touch event to place the cursor where the
// user touched.
AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
mTextEntry.getLayoutParams();
if (lp != null) {
// Take the last touch and adjust for the location of the
// TextDialog.
float x = mLastTouchX + (float) (mScrollX - lp.x);
float y = mLastTouchY + (float) (mScrollY - lp.y);
mTextEntry.fakeTouchEvent(x, y);
}
|
private void | doFling()
if (mVelocityTracker == null) {
return;
}
int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
mVelocityTracker.computeCurrentVelocity(1000);
int vx = (int) mVelocityTracker.getXVelocity();
int vy = (int) mVelocityTracker.getYVelocity();
if (mSnapScrollMode != SNAP_NONE) {
if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_X_LOCK) {
vy = 0;
} else {
vx = 0;
}
}
if (true /* EMG release: make our fling more like Maps' */) {
// maps cuts their velocity in half
vx = vx * 3 / 4;
vy = vy * 3 / 4;
}
mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY);
// TODO: duration is calculated based on velocity, if the range is
// small, the animation will stop before duration is up. We may
// want to calculate how long the animation is going to run to precisely
// resume the webcore update.
final int time = mScroller.getDuration();
mPrivateHandler.sendEmptyMessageDelayed(RESUME_WEBCORE_UPDATE, time);
invalidate();
|
private void | doShortPress()
if (mNativeClass == 0) {
return;
}
switchOutDrawHistory();
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
if (nativeMotionUp(contentX, contentY, mNavSlop, true)) {
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
}
}
if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
&& !mFocusNode.mIsTextArea) {
playSoundEffect(SoundEffectConstants.CLICK);
}
|
private void | doTrackball(long time)
int elapsed = (int) (mTrackballLastTime - mTrackballFirstTime);
if (elapsed == 0) {
elapsed = TRACKBALL_TIMEOUT;
}
float xRate = mTrackballRemainsX * 1000 / elapsed;
float yRate = mTrackballRemainsY * 1000 / elapsed;
if (mShiftIsPressed) {
moveSelection(xRate, yRate);
mTrackballRemainsX = mTrackballRemainsY = 0;
return;
}
float ax = Math.abs(xRate);
float ay = Math.abs(yRate);
float maxA = Math.max(ax, ay);
if (LOGV_ENABLED) {
Log.v(LOGTAG, "doTrackball elapsed=" + elapsed
+ " xRate=" + xRate
+ " yRate=" + yRate
+ " mTrackballRemainsX=" + mTrackballRemainsX
+ " mTrackballRemainsY=" + mTrackballRemainsY);
}
int width = mContentWidth - getViewWidth();
int height = mContentHeight - getViewHeight();
if (width < 0) width = 0;
if (height < 0) height = 0;
if (mTouchMode == SCROLL_ZOOM_OUT) {
int oldX = mZoomScrollX;
int oldY = mZoomScrollY;
int maxWH = Math.max(width, height);
mZoomScrollX += scaleTrackballX(xRate, maxWH);
mZoomScrollY += scaleTrackballY(yRate, maxWH);
if (LOGV_ENABLED) {
Log.v(LOGTAG, "doTrackball SCROLL_ZOOM_OUT"
+ " mZoomScrollX=" + mZoomScrollX
+ " mZoomScrollY=" + mZoomScrollY);
}
mZoomScrollX = Math.min(width, Math.max(0, mZoomScrollX));
mZoomScrollY = Math.min(height, Math.max(0, mZoomScrollY));
if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
invalidate();
}
mTrackballRemainsX = mTrackballRemainsY = 0;
return;
}
ax = Math.abs(mTrackballRemainsX * TRACKBALL_MULTIPLIER);
ay = Math.abs(mTrackballRemainsY * TRACKBALL_MULTIPLIER);
maxA = Math.max(ax, ay);
int count = Math.max(0, (int) maxA);
int oldScrollX = mScrollX;
int oldScrollY = mScrollY;
if (count > 0) {
int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
KeyEvent.KEYCODE_DPAD_RIGHT;
count = Math.min(count, TRACKBALL_MOVE_COUNT);
if (LOGV_ENABLED) {
Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
+ " count=" + count
+ " mTrackballRemainsX=" + mTrackballRemainsX
+ " mTrackballRemainsY=" + mTrackballRemainsY);
}
if (navHandledKey(selectKeyCode, count, false, time)) {
playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
}
mTrackballRemainsX = mTrackballRemainsY = 0;
}
if (count >= TRACKBALL_SCROLL_COUNT) {
int xMove = scaleTrackballX(xRate, width);
int yMove = scaleTrackballY(yRate, height);
if (LOGV_ENABLED) {
Log.v(LOGTAG, "doTrackball pinScrollBy"
+ " count=" + count
+ " xMove=" + xMove + " yMove=" + yMove
+ " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
+ " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
);
}
if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
xMove = 0;
}
if (Math.abs(mScrollY - oldScrollY) > Math.abs(yMove)) {
yMove = 0;
}
if (xMove != 0 || yMove != 0) {
pinScrollBy(xMove, yMove, true, 0);
}
mUserScroll = true;
}
mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS);
|
public void | documentAsText(android.os.Message callback){@hide}
mWebViewCore.sendMessage(EventHub.REQUEST_DOC_AS_TEXT, callback);
|
public void | documentHasImages(android.os.Message response)Query the document to see if it contains any image references. The
message object will be dispatched with arg1 being set to 1 if images
were found and 0 if the document does not reference any images.
if (response == null) {
return;
}
mWebViewCore.sendMessage(EventHub.DOC_HAS_IMAGES, response);
|
private void | drawCoreAndFocusRing(android.graphics.Canvas canvas, int color, boolean drawFocus)
if (mDrawHistory) {
canvas.scale(mActualScale, mActualScale);
canvas.drawPicture(mHistoryPicture);
return;
}
boolean animateZoom = mZoomScale != 0;
boolean animateScroll = !mScroller.isFinished()
|| mVelocityTracker != null;
if (animateZoom) {
float zoomScale;
int interval = (int) (SystemClock.uptimeMillis() - mZoomStart);
if (interval < ZOOM_ANIMATION_LENGTH) {
float ratio = (float) interval / ZOOM_ANIMATION_LENGTH;
zoomScale = 1.0f / (mInvInitialZoomScale
+ (mInvFinalZoomScale - mInvInitialZoomScale) * ratio);
invalidate();
} else {
zoomScale = mZoomScale;
// set mZoomScale to be 0 as we have done animation
mZoomScale = 0;
}
float scale = (mActualScale - zoomScale) * mInvActualScale;
float tx = scale * (mZoomCenterX + mScrollX);
float ty = scale * (mZoomCenterY + mScrollY);
// this block pins the translate to "legal" bounds. This makes the
// animation a bit non-obvious, but it means we won't pop when the
// "real" zoom takes effect
if (true) {
// canvas.translate(mScrollX, mScrollY);
tx -= mScrollX;
ty -= mScrollY;
tx = -pinLoc(-Math.round(tx), getViewWidth(), Math
.round(mContentWidth * zoomScale));
ty = -pinLoc(-Math.round(ty), getViewHeight(), Math
.round(mContentHeight * zoomScale));
tx += mScrollX;
ty += mScrollY;
}
canvas.translate(tx, ty);
canvas.scale(zoomScale, zoomScale);
} else {
canvas.scale(mActualScale, mActualScale);
}
mWebViewCore.drawContentPicture(canvas, color, animateZoom,
animateScroll);
if (mNativeClass == 0) return;
if (mShiftIsPressed) {
if (mTouchSelection) {
nativeDrawSelectionRegion(canvas);
} else {
nativeDrawSelection(canvas, mSelectX, mSelectY,
mExtendSelection);
}
} else if (drawFocus) {
if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mTouchMode = TOUCH_SHORTPRESS_MODE;
HitTestResult hitTest = getHitTestResult();
if (hitTest != null &&
hitTest.mType != HitTestResult.UNKNOWN_TYPE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_LONGPRESS),
LONG_PRESS_TIMEOUT);
}
}
nativeDrawFocusRing(canvas);
}
// When the FindDialog is up, only draw the matches if we are not in
// the process of scrolling them into view.
if (mFindIsUp && !animateScroll) {
nativeDrawMatches(canvas);
}
|
boolean | drawHistory()
// Only check the flag, can be called from WebCore thread
return mDrawHistory;
|
private void | drawMagnifyFrame(android.graphics.Canvas canvas, android.graphics.Rect frame, android.graphics.Paint paint)
final float ADORNMENT_LEN = 16.0f;
float width = frame.width();
float height = frame.height();
Path path = new Path();
path.moveTo(-ADORNMENT_LEN, -ADORNMENT_LEN);
path.lineTo(0, 0);
path.lineTo(width, 0);
path.lineTo(width + ADORNMENT_LEN, -ADORNMENT_LEN);
path.moveTo(-ADORNMENT_LEN, height + ADORNMENT_LEN);
path.lineTo(0, height);
path.lineTo(width, height);
path.lineTo(width + ADORNMENT_LEN, height + ADORNMENT_LEN);
path.moveTo(0, 0);
path.lineTo(0, height);
path.moveTo(width, 0);
path.lineTo(width, height);
path.offset(frame.left, frame.top);
canvas.drawPath(path, paint);
|
public void | emulateShiftHeld()
mExtendSelection = false;
mShiftIsPressed = true;
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
nativeClearFocus(contentX, contentY);
|
public static void | enablePlatformNotifications()Enables platform notifications of data state and proxy changes.
Network.enablePlatformNotifications();
|
private boolean | extendScroll(int y)
int finalY = mScroller.getFinalY();
int newY = pinLocY(finalY + y);
if (newY == finalY) return false;
mScroller.setFinalY(newY);
mScroller.extendDuration(computeDuration(0, y));
return true;
|
public void | externalRepresentation(android.os.Message callback){@hide}
mWebViewCore.sendMessage(EventHub.REQUEST_EXT_REPRESENTATION, callback);
|
protected void | finalize()
destroy();
|
public static java.lang.String | findAddress(java.lang.String addr)Return the first substring consisting of the address of a physical
location. Currently, only addresses in the United States are detected,
and consist of:
- a house number
- a street name
- a street type (Road, Circle, etc), either spelled out or abbreviated
- a city name
- a state or territory, either spelled out or two-letter abbr.
- an optional 5 digit or 9 digit zip code.
All names must be correctly capitalized, and the zip code, if present,
must be valid for the state. The street type must be a standard USPS
spelling or abbreviation. The state or territory must also be spelled
or abbreviated using USPS standards. The house number may not exceed
five digits.
return WebViewCore.nativeFindAddress(addr);
|
public int | findAll(java.lang.String find)
mFindIsUp = true;
int result = nativeFindAll(find.toLowerCase(), find.toUpperCase());
invalidate();
return result;
|
public void | findNext(boolean forward)
nativeFindNext(forward);
|
public void | flingScroll(int vx, int vy)
int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
mScroller.fling(mScrollX, mScrollY, vx, vy, 0, maxX, 0, maxY);
invalidate();
|
public android.net.http.SslCertificate | getCertificate()
return mCertificate;
|
public int | getContentHeight()
return mContentHeight;
|
public android.graphics.Bitmap | getFavicon()Get the favicon for the current page. This is the favicon of the current
page until WebViewClient.onReceivedIcon is called.
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getFavicon() : null;
|
public android.webkit.WebView$HitTestResult | getHitTestResult()Return a HitTestResult based on the current focus node. If a HTML::a tag
is found and the anchor has a non-javascript url, the HitTestResult type
is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
anchor does not have a url or if it is a javascript url, the type will
be UNKNOWN_TYPE and the url has to be retrieved through
{@link #requestFocusNodeHref} asynchronously. If a HTML::img tag is
found, the HitTestResult type is set to IMAGE_TYPE and the url is set in
the "extra" field. A type of
SRC_IMAGE_ANCHOR_TYPE indicates an anchor with a url that has an image as
a child node. If a phone number is found, the HitTestResult type is set
to PHONE_TYPE and the phone number is set in the "extra" field of
HitTestResult. If a map address is found, the HitTestResult type is set
to GEO_TYPE and the address is set in the "extra" field of HitTestResult.
If an email address is found, the HitTestResult type is set to EMAIL_TYPE
and the email is set in the "extra" field of HitTestResult. Otherwise,
HitTestResult type is set to UNKNOWN_TYPE.
if (mNativeClass == 0) {
return null;
}
HitTestResult result = new HitTestResult();
if (nativeUpdateFocusNode()) {
FocusNode node = mFocusNode;
if (node.mIsTextField || node.mIsTextArea) {
result.setType(HitTestResult.EDIT_TEXT_TYPE);
} else if (node.mText != null) {
String text = node.mText;
if (text.startsWith(SCHEME_TEL)) {
result.setType(HitTestResult.PHONE_TYPE);
result.setExtra(text.substring(SCHEME_TEL.length()));
} else if (text.startsWith(SCHEME_MAILTO)) {
result.setType(HitTestResult.EMAIL_TYPE);
result.setExtra(text.substring(SCHEME_MAILTO.length()));
} else if (text.startsWith(SCHEME_GEO)) {
result.setType(HitTestResult.GEO_TYPE);
result.setExtra(URLDecoder.decode(text
.substring(SCHEME_GEO.length())));
} else if (node.mIsAnchor) {
result.setType(HitTestResult.SRC_ANCHOR_TYPE);
result.setExtra(text);
}
}
}
int type = result.getType();
if (type == HitTestResult.UNKNOWN_TYPE
|| type == HitTestResult.SRC_ANCHOR_TYPE) {
// Now check to see if it is an image.
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
String text = nativeImageURI(contentX, contentY);
if (text != null) {
result.setType(type == HitTestResult.UNKNOWN_TYPE ?
HitTestResult.IMAGE_TYPE :
HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
result.setExtra(text);
}
}
return result;
|
public java.lang.String[] | getHttpAuthUsernamePassword(java.lang.String host, java.lang.String realm)Retrieve the HTTP authentication username and password for a given
host & realm pair
return mDatabase.getHttpAuthUsernamePassword(host, realm);
|
public java.lang.String | getOriginalUrl()Get the original url for the current page. This is not always the same
as the url passed to WebViewClient.onPageStarted because although the
load for that url has begun, the current page may not have changed.
Also, there may have been redirects resulting in a different url to that
originally requested.
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getOriginalUrl() : null;
|
public static synchronized PluginList | getPluginList()Return the list of currently loaded plugins.
if (sPluginList == null) {
sPluginList = new PluginList();
}
return sPluginList;
|
public int | getProgress()Get the progress for the current page.
return mCallbackProxy.getProgress();
|
public float | getScale()Return the current scale of the WebView
return mActualScale;
|
private int | getScaledMaxXScroll()
int width;
if (mHeightCanMeasure == false) {
width = getViewWidth() / 4;
} else {
Rect visRect = new Rect();
calcOurVisibleRect(visRect);
width = visRect.width() / 2;
}
// FIXME the divisor should be retrieved from somewhere
return viewToContent(width);
|
private int | getScaledMaxYScroll()
int height;
if (mHeightCanMeasure == false) {
height = getViewHeight() / 4;
} else {
Rect visRect = new Rect();
calcOurVisibleRect(visRect);
height = visRect.height() / 2;
}
// FIXME the divisor should be retrieved from somewhere
// the closest thing today is hard-coded into ScrollView.java
// (from ScrollView.java, line 363) int maxJump = height/2;
return viewToContent(height);
|
public WebSettings | getSettings()Return the WebSettings object used to control the settings for this
WebView.
return mWebViewCore.getSettings();
|
public java.lang.String | getTitle()Get the title for the current page. This is the title of the current page
until WebViewClient.onReceivedTitle is called.
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getTitle() : null;
|
public java.lang.String | getUrl()Get the url for the current page. This is not always the same as the url
passed to WebViewClient.onPageStarted because although the load for
that url has begun, the current page may not have changed.
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getUrl() : null;
|
private int | getViewHeight()
if (!isHorizontalScrollBarEnabled() || mOverlayHorizontalScrollbar) {
return getHeight();
} else {
return getHeight() - getHorizontalScrollbarHeight();
}
|
private int | getViewWidth()
if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) {
return getWidth();
} else {
return getWidth() - getVerticalScrollbarWidth();
}
|
WebViewCore | getWebViewCore()
return mWebViewCore;
|
public android.widget.ZoomButtonsController | getZoomButtonsController()Gets the {@link ZoomButtonsController} which can be used to add
additional buttons to the zoom controls window.
return mZoomButtonsController;
|
public android.view.View | getZoomControls()Returns a view containing zoom controls i.e. +/- buttons. The caller is
in charge of installing this view to the view hierarchy. This view will
become visible when the user starts scrolling via touch and fade away if
the user does not interact with it.
API version 3 introduces a built-in zoom mechanism that is shown
automatically by the MapView. This is the preferred approach for
showing the zoom UI.
if (!getSettings().supportZoom()) {
Log.w(LOGTAG, "This WebView doesn't support zoom.");
return null;
}
if (mZoomControls == null) {
mZoomControls = createZoomControls();
/*
* need to be set to VISIBLE first so that getMeasuredHeight() in
* {@link #onSizeChanged()} can return the measured value for proper
* layout.
*/
mZoomControls.setVisibility(View.VISIBLE);
mZoomControlRunnable = new Runnable() {
public void run() {
/* Don't dismiss the controls if the user has
* focus on them. Wait and check again later.
*/
if (!mZoomControls.hasFocus()) {
mZoomControls.hide();
} else {
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
mPrivateHandler.postDelayed(mZoomControlRunnable,
ZOOM_CONTROLS_TIMEOUT);
}
}
};
}
return mZoomControls;
|
public void | goBack()Go back in the history of this WebView.
goBackOrForward(-1);
|
public void | goBackOrForward(int steps)Go to the history item that is the number of steps away from
the current item. Steps is negative if backward and positive
if forward.
goBackOrForward(steps, false);
|
private void | goBackOrForward(int steps, boolean ignoreSnapshot)
// every time we go back or forward, we want to reset the
// WebView certificate:
// if the new site is secure, we will reload it and get a
// new certificate set;
// if the new site is not secure, the certificate must be
// null, and that will be the case
mCertificate = null;
if (steps != 0) {
clearTextEntry();
mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps,
ignoreSnapshot ? 1 : 0);
}
|
public void | goForward()Go forward in the history of this WebView.
goBackOrForward(1);
|
private boolean | inEditingMode()Return true if the browser is displaying a TextView for text input.
return mTextEntry != null && mTextEntry.getParent() != null
&& mTextEntry.hasFocus();
|
private void | init()
setWillNotDraw(false);
setFocusable(true);
setFocusableInTouchMode(true);
setClickable(true);
setLongClickable(true);
final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mTouchSlopSquare = slop * slop;
mMinLockSnapReverseDistance = slop;
// use one line height, 16 based on our current default font, for how
// far we allow a touch be away from the edge of a link
mNavSlop = (int) (16 * getContext().getResources()
.getDisplayMetrics().density);
|
private void | initZoomController(android.content.Context context)
// Create the buttons controller
mZoomButtonsController = new ZoomButtonsController(this);
mZoomButtonsController.setOnZoomListener(mZoomListener);
// Create the accessory buttons
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup container = mZoomButtonsController.getContainer();
inflater.inflate(com.android.internal.R.layout.zoom_browser_accessory_buttons, container);
mZoomOverviewButton =
(ImageView) container.findViewById(com.android.internal.R.id.zoom_page_overview);
mZoomOverviewButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
mZoomButtonsController.setVisible(false);
zoomScrollOut();
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
Checkin.Stats.Tag.BROWSER_ZOOM_OVERVIEW, 1, 0.0);
}
}
});
mZoomFitPageButton =
(ImageView) container.findViewById(com.android.internal.R.id.zoom_fit_page);
mZoomFitPageButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
zoomWithPreview(1f);
updateZoomButtonsEnabled();
}
});
|
public void | invokeZoomPicker()Invoke the graphical zoom picker widget for this WebView. This will
result in the zoom widget appearing on the screen to control the zoom
level of this WebView.
if (!getSettings().supportZoom()) {
Log.w(LOGTAG, "This WebView doesn't support zoom.");
return;
}
clearTextEntry();
if (getSettings().getBuiltInZoomControls()) {
mZoomButtonsController.setVisible(true);
} else {
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
mPrivateHandler.postDelayed(mZoomControlRunnable,
ZOOM_CONTROLS_TIMEOUT);
}
|
private int | keyCodeToSoundsEffect(int keyCode)
switch(keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
return SoundEffectConstants.NAVIGATION_UP;
case KeyEvent.KEYCODE_DPAD_RIGHT:
return SoundEffectConstants.NAVIGATION_RIGHT;
case KeyEvent.KEYCODE_DPAD_DOWN:
return SoundEffectConstants.NAVIGATION_DOWN;
case KeyEvent.KEYCODE_DPAD_LEFT:
return SoundEffectConstants.NAVIGATION_LEFT;
}
throw new IllegalArgumentException("keyCode must be one of " +
"{KEYCODE_DPAD_UP, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_DOWN, " +
"KEYCODE_DPAD_LEFT}.");
|
public void | loadData(java.lang.String data, java.lang.String mimeType, java.lang.String encoding)Load the given data into the WebView. This will load the data into
WebView using the data: scheme. Content loaded through this mechanism
does not have the ability to load content from the network.
loadUrl("data:" + mimeType + ";" + encoding + "," + data);
|
public void | loadDataWithBaseURL(java.lang.String baseUrl, java.lang.String data, java.lang.String mimeType, java.lang.String encoding, java.lang.String failUrl)Load the given data into the WebView, use the provided URL as the base
URL for the content. The base URL is the URL that represents the page
that is loaded through this interface. As such, it is used for the
history entry and to resolve any relative URLs. The failUrl is used if
browser fails to load the data provided. If it is empty or null, and the
load fails, then no history entry is created.
Note for post 1.0. Due to the change in the WebKit, the access to asset
files through "file:///android_asset/" for the sub resources is more
restricted. If you provide null or empty string as baseUrl, you won't be
able to access asset files. If the baseUrl is anything other than
http(s)/ftp(s)/about/javascript as scheme, you can access asset files for
sub resources.
if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
loadData(data, mimeType, encoding);
return;
}
switchOutDrawHistory();
HashMap arg = new HashMap();
arg.put("baseUrl", baseUrl);
arg.put("data", data);
arg.put("mimeType", mimeType);
arg.put("encoding", encoding);
arg.put("failUrl", failUrl);
mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
clearTextEntry();
|
public void | loadUrl(java.lang.String url)Load the given url.
switchOutDrawHistory();
mWebViewCore.sendMessage(EventHub.LOAD_URL, url);
clearTextEntry();
|
void | moveSelection(float xRate, float yRate)
if (mNativeClass == 0)
return;
int width = getViewWidth();
int height = getViewHeight();
mSelectX += scaleTrackballX(xRate, width);
mSelectY += scaleTrackballY(yRate, height);
int maxX = width + mScrollX;
int maxY = height + mScrollY;
mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
, mSelectX));
mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
, mSelectY));
if (LOGV_ENABLED) {
Log.v(LOGTAG, "moveSelection"
+ " mSelectX=" + mSelectX
+ " mSelectY=" + mSelectY
+ " mScrollX=" + mScrollX
+ " mScrollY=" + mScrollY
+ " xRate=" + xRate
+ " yRate=" + yRate
);
}
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), mExtendSelection);
int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
: mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
: mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
pinScrollBy(scrollX, scrollY, true, 0);
Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
requestRectangleOnScreen(select);
invalidate();
|
private void | moveZoomScrollWindow(float x, float y)
if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
&& Math.abs(y - mLastZoomScrollRawY) < 1.5f) {
return;
}
mLastZoomScrollRawX = x;
mLastZoomScrollRawY = y;
int oldX = mZoomScrollX;
int oldY = mZoomScrollY;
int width = getViewWidth();
int height = getViewHeight();
int maxZoomX = mContentWidth - width;
if (maxZoomX > 0) {
int maxScreenX = width - (int) Math.ceil(width
* mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "moveZoomScrollWindow-X"
+ " maxScreenX=" + maxScreenX + " width=" + width
+ " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
}
x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX;
x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit);
mZoomScrollX = Math.max(0, Math.min(maxZoomX, (int) x));
}
int maxZoomY = mContentHeight - height;
if (maxZoomY > 0) {
int maxScreenY = height - (int) Math.ceil(height
* mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "moveZoomScrollWindow-Y"
+ " maxScreenY=" + maxScreenY + " height=" + height
+ " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
}
y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY;
y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit);
mZoomScrollY = Math.max(0, Math.min(maxZoomY, (int) y));
}
if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
invalidate();
}
if (LOGV_ENABLED) {
Log.v(LOGTAG, "moveZoomScrollWindow"
+ " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
+ " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
+ " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
+ " last=("+mLastScrollX+", "+mLastScrollY+")"
+ " x=" + x + " y=" + y);
}
|
private native void | nativeClearFocus(int x, int y)
|
private native void | nativeCreate(int ptr)
|
private native void | nativeDebugDump()
|
private native void | nativeDestroy()
|
private native void | nativeDrawFocusRing(android.graphics.Canvas content)
|
private native void | nativeDrawMatches(android.graphics.Canvas canvas)
|
private native void | nativeDrawSelection(android.graphics.Canvas content, int x, int y, boolean extendSelection)
|
private native void | nativeDrawSelectionRegion(android.graphics.Canvas content)
|
private native void | nativeDumpDisplayTree(java.lang.String urlOrNull)
|
private native int | nativeFindAll(java.lang.String findLower, java.lang.String findUpper)
|
private native void | nativeFindNext(boolean forward)
|
private native boolean | nativeFocusNodeWantsKeyEvents()Returns true if the native focus nodes says it wants to handle key events
(ala plugins). This can only be called if mNativeClass is non-zero!
|
private native android.graphics.Rect | nativeGetFocusRingBounds()
|
private native android.graphics.Rect | nativeGetNavBounds()
|
private native android.graphics.Region | nativeGetSelection()
|
private native java.lang.String | nativeImageURI(int x, int y)
|
private native void | nativeInstrumentReport()
|
private native void | nativeMarkNodeInvalid(int node)
|
private native boolean | nativeMotionUp(int x, int y, int slop, boolean isClick)
|
private native boolean | nativeMoveFocus(int keyCode, int count, boolean noScroll)
|
private native void | nativeMoveSelection(int x, int y, boolean extendSelection)
|
private native void | nativeNotifyFocusSet(boolean inEditingMode)
|
private native void | nativeRecomputeFocus()
|
private native void | nativeRecordButtons(boolean focused, boolean pressed, boolean invalidate)
|
private native void | nativeResetFocus()
|
private native void | nativeResetNavClipBounds()
|
private native void | nativeSelectBestAt(android.graphics.Rect rect)
|
private native void | nativeSetFindIsDown()
|
private native void | nativeSetFollowedLink(boolean followed)
|
private native void | nativeSetHeightCanMeasure(boolean measure)
|
private native void | nativeSetNavBounds(android.graphics.Rect rect)
|
private native void | nativeSetNavClipBounds(android.graphics.Rect rect)
|
private native void | nativeUpdateCachedTextfield(java.lang.String updatedText, int generation)
|
private native boolean | nativeUpdateFocusNode()
|
private boolean | navHandledKey(int keyCode, int count, boolean noScroll, long time)
if (mNativeClass == 0) {
return false;
}
mLastFocusTime = time;
mLastFocusBounds = nativeGetFocusRingBounds();
boolean keyHandled = nativeMoveFocus(keyCode, count, noScroll) == false;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "navHandledKey mLastFocusBounds=" + mLastFocusBounds
+ " mLastFocusTime=" + mLastFocusTime
+ " handled=" + keyHandled);
}
if (keyHandled == false || mHeightCanMeasure == false) {
return keyHandled;
}
Rect contentFocus = nativeGetFocusRingBounds();
if (contentFocus.isEmpty()) return keyHandled;
Rect viewFocus = contentToView(contentFocus);
Rect visRect = new Rect();
calcOurVisibleRect(visRect);
Rect outset = new Rect(visRect);
int maxXScroll = visRect.width() / 2;
int maxYScroll = visRect.height() / 2;
outset.inset(-maxXScroll, -maxYScroll);
if (Rect.intersects(outset, viewFocus) == false) {
return keyHandled;
}
// FIXME: Necessary because ScrollView/ListView do not scroll left/right
int maxH = Math.min(viewFocus.right - visRect.right, maxXScroll);
if (maxH > 0) {
pinScrollBy(maxH, 0, true, 0);
} else {
maxH = Math.max(viewFocus.left - visRect.left, -maxXScroll);
if (maxH < 0) {
pinScrollBy(maxH, 0, true, 0);
}
}
if (mLastFocusBounds.isEmpty()) return keyHandled;
if (mLastFocusBounds.equals(contentFocus)) return keyHandled;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "navHandledKey contentFocus=" + contentFocus);
}
requestRectangleOnScreen(viewFocus);
mUserScroll = true;
return keyHandled;
|
protected void | onAttachedToWindow()
super.onAttachedToWindow();
ViewParent parent = getParent();
if (parent instanceof ViewGroup) {
ViewGroup p = (ViewGroup) parent;
p.setOnHierarchyChangeListener(this);
}
|
public void | onChildViewAdded(android.view.View parent, android.view.View child)
|
public void | onChildViewRemoved(android.view.View p, android.view.View child)
if (child == this) {
if (inEditingMode()) {
clearTextEntry();
mNeedsUpdateTextEntry = true;
}
}
|
protected void | onDetachedFromWindow()
super.onDetachedFromWindow();
ViewParent parent = getParent();
if (parent instanceof ViewGroup) {
ViewGroup p = (ViewGroup) parent;
p.setOnHierarchyChangeListener(null);
}
// Clean up the zoom controller
mZoomButtonsController.setVisible(false);
|
protected void | onDraw(android.graphics.Canvas canvas)
// if mNativeClass is 0, the WebView has been destroyed. Do nothing.
if (mNativeClass == 0) {
return;
}
if (mWebViewCore.mEndScaleZoom) {
mWebViewCore.mEndScaleZoom = false;
if (mTouchMode >= FIRST_SCROLL_ZOOM
&& mTouchMode <= LAST_SCROLL_ZOOM) {
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
mTouchMode = TOUCH_DONE_MODE;
}
}
int sc = canvas.save();
if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
scrollZoomDraw(canvas);
} else {
nativeRecomputeFocus();
// Update the buttons in the picture, so when we draw the picture
// to the screen, they are in the correct state.
// Tell the native side if user is a) touching the screen,
// b) pressing the trackball down, or c) pressing the enter key
// If the focus is a button, we need to draw it in the pressed
// state.
// If mNativeClass is 0, we should not reach here, so we do not
// need to check it again.
nativeRecordButtons(hasFocus() && hasWindowFocus(),
mTouchMode == TOUCH_SHORTPRESS_START_MODE
|| mTrackballDown || mGotEnterDown, false);
drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing);
}
canvas.restoreToCount(sc);
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
|
protected void | onFocusChanged(boolean focused, int direction, android.graphics.Rect previouslyFocusedRect)
if (LOGV_ENABLED) {
Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction);
}
if (focused) {
// When we regain focus, if we have window focus, resume drawing
// the focus ring, and add the TextView if necessary.
if (hasWindowFocus()) {
mDrawFocusRing = true;
if (mNeedsUpdateTextEntry) {
updateTextEntry();
mNeedsUpdateTextEntry = false;
}
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
}
//} else {
// The WebView has gained focus while we do not have
// windowfocus. When our window lost focus, we should have
// called nativeRecordButtons(false...)
}
} else {
// When we lost focus, unless focus went to the TextView (which is
// true if we are in editing mode), stop drawing the focus ring.
if (!inEditingMode()) {
mDrawFocusRing = false;
if (mNativeClass != 0) {
nativeRecordButtons(false, false, true);
}
}
mGotKeyDown = false;
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
public void | onGlobalFocusChanged(android.view.View oldFocus, android.view.View newFocus)
|
public boolean | onKeyDown(int keyCode, android.view.KeyEvent event)
if (LOGV_ENABLED) {
Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
+ ", " + event);
}
if (mNativeClass == 0) {
return false;
}
// do this hack up front, so it always works, regardless of touch-mode
if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) {
mAutoRedraw = !mAutoRedraw;
if (mAutoRedraw) {
invalidate();
}
return true;
}
// Bubble up the key event if
// 1. it is a system key; or
// 2. the host application wants to handle it; or
// 3. webview is in scroll-zoom state;
if (event.isSystem()
|| mCallbackProxy.uiOverrideKeyEvent(event)
|| (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM)) {
return false;
}
if (mShiftIsPressed == false && nativeFocusNodeWantsKeyEvents() == false
&& (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
mExtendSelection = false;
mShiftIsPressed = true;
if (nativeUpdateFocusNode()) {
FocusNode node = mFocusNode;
mSelectX = contentToView(node.mBounds.left);
mSelectY = contentToView(node.mBounds.top);
} else {
mSelectX = mScrollX + (int) mLastTouchX;
mSelectY = mScrollY + (int) mLastTouchY;
}
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
nativeClearFocus(contentX, contentY);
}
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
// always handle the navigation keys in the UI thread
switchOutDrawHistory();
if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
playSoundEffect(keyCodeToSoundsEffect(keyCode));
return true;
}
// Bubble up the key event as WebView doesn't handle it
return false;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
|| keyCode == KeyEvent.KEYCODE_ENTER) {
switchOutDrawHistory();
if (event.getRepeatCount() == 0) {
mGotEnterDown = true;
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT);
// Already checked mNativeClass, so we do not need to check it
// again.
nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
return true;
}
// Bubble up the key event as WebView doesn't handle it
return false;
}
if (getSettings().getNavDump()) {
switch (keyCode) {
case KeyEvent.KEYCODE_4:
// "/data/data/com.android.browser/displayTree.txt"
nativeDumpDisplayTree(getUrl());
break;
case KeyEvent.KEYCODE_5:
case KeyEvent.KEYCODE_6:
// 5: dump the dom tree to the file
// "/data/data/com.android.browser/domTree.txt"
// 6: dump the dom tree to the adb log
mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE,
(keyCode == KeyEvent.KEYCODE_5) ? 1 : 0, 0);
break;
case KeyEvent.KEYCODE_7:
case KeyEvent.KEYCODE_8:
// 7: dump the render tree to the file
// "/data/data/com.android.browser/renderTree.txt"
// 8: dump the render tree to the adb log
mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE,
(keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0);
break;
case KeyEvent.KEYCODE_9:
nativeInstrumentReport();
return true;
}
}
// TODO: should we pass all the keys to DOM or check the meta tag
if (nativeFocusNodeWantsKeyEvents() || true) {
// pass the key to DOM
mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
// return true as DOM handles the key
return true;
}
// Bubble up the key event as WebView doesn't handle it
return false;
|
public boolean | onKeyUp(int keyCode, android.view.KeyEvent event)
if (LOGV_ENABLED) {
Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
+ ", " + event);
}
if (mNativeClass == 0) {
return false;
}
// special CALL handling when focus node's href is "tel:XXX"
if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) {
FocusNode node = mFocusNode;
String text = node.mText;
if (!node.mIsTextField && !node.mIsTextArea && text != null
&& text.startsWith(SCHEME_TEL)) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
getContext().startActivity(intent);
return true;
}
}
// Bubble up the key event if
// 1. it is a system key; or
// 2. the host application wants to handle it;
if (event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event)) {
return false;
}
// special handling in scroll_zoom state
if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode
&& mTouchMode != SCROLL_ZOOM_ANIMATION_IN) {
setZoomScrollIn();
mTouchMode = SCROLL_ZOOM_ANIMATION_IN;
invalidate();
return true;
}
return false;
}
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
if (commitCopy()) {
return true;
}
}
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
// always handle the navigation keys in the UI thread
// Bubble up the key event as WebView doesn't handle it
return false;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
|| keyCode == KeyEvent.KEYCODE_ENTER) {
// remove the long press message first
mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
mGotEnterDown = false;
if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
if (mShiftIsPressed) {
return false;
}
if (getSettings().supportZoom()) {
if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
zoomScrollOut();
} else {
if (LOGV_ENABLED) {
Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
}
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT);
mTouchMode = TOUCH_DOUBLECLICK_MODE;
}
return true;
}
}
Rect visibleRect = sendOurVisibleRect();
// Note that sendOurVisibleRect calls viewToContent, so the
// coordinates should be in content coordinates.
if (nativeUpdateFocusNode()) {
if (Rect.intersects(mFocusNode.mBounds, visibleRect)) {
nativeSetFollowedLink(true);
mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
new WebViewCore.FocusData(mFocusData));
playSoundEffect(SoundEffectConstants.CLICK);
if (!mCallbackProxy.uiOverrideUrlLoading(mFocusNode.mText)) {
// use CLICK instead of KEY_DOWN/KEY_UP so that we can
// trigger mouse click events
mWebViewCore.sendMessage(EventHub.CLICK);
}
}
return true;
}
// Bubble up the key event as WebView doesn't handle it
return false;
}
// TODO: should we pass all the keys to DOM or check the meta tag
if (nativeFocusNodeWantsKeyEvents() || true) {
// pass the key to DOM
mWebViewCore.sendMessage(EventHub.KEY_UP, event);
// return true as DOM handles the key
return true;
}
// Bubble up the key event as WebView doesn't handle it
return false;
|
protected void | onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int measuredHeight = heightSize;
int measuredWidth = widthSize;
// Grab the content size from WebViewCore.
int contentHeight = mContentHeight;
int contentWidth = mContentWidth;
// Log.d(LOGTAG, "------- measure " + heightMode);
if (heightMode != MeasureSpec.EXACTLY) {
mHeightCanMeasure = true;
measuredHeight = contentHeight;
if (heightMode == MeasureSpec.AT_MOST) {
// If we are larger than the AT_MOST height, then our height can
// no longer be measured and we should scroll internally.
if (measuredHeight > heightSize) {
measuredHeight = heightSize;
mHeightCanMeasure = false;
}
}
} else {
mHeightCanMeasure = false;
}
if (mNativeClass != 0) {
nativeSetHeightCanMeasure(mHeightCanMeasure);
}
// For the width, always use the given size unless unspecified.
if (widthMode == MeasureSpec.UNSPECIFIED) {
mWidthCanMeasure = true;
measuredWidth = contentWidth;
} else {
mWidthCanMeasure = false;
}
synchronized (this) {
setMeasuredDimension(measuredWidth, measuredHeight);
}
|
boolean | onSavePassword(java.lang.String schemePlusHost, java.lang.String username, java.lang.String password, android.os.Message resumeMsg)
boolean rVal = false;
if (resumeMsg == null) {
// null resumeMsg implies saving password silently
mDatabase.setUsernamePassword(schemePlusHost, username, password);
} else {
final Message remember = mPrivateHandler.obtainMessage(
REMEMBER_PASSWORD);
remember.getData().putString("host", schemePlusHost);
remember.getData().putString("username", username);
remember.getData().putString("password", password);
remember.obj = resumeMsg;
final Message neverRemember = mPrivateHandler.obtainMessage(
NEVER_REMEMBER_PASSWORD);
neverRemember.getData().putString("host", schemePlusHost);
neverRemember.getData().putString("username", username);
neverRemember.getData().putString("password", password);
neverRemember.obj = resumeMsg;
new AlertDialog.Builder(getContext())
.setTitle(com.android.internal.R.string.save_password_label)
.setMessage(com.android.internal.R.string.save_password_message)
.setPositiveButton(com.android.internal.R.string.save_password_notnow,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
resumeMsg.sendToTarget();
}
})
.setNeutralButton(com.android.internal.R.string.save_password_remember,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
remember.sendToTarget();
}
})
.setNegativeButton(com.android.internal.R.string.save_password_never,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
neverRemember.sendToTarget();
}
})
.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
resumeMsg.sendToTarget();
}
}).show();
// Return true so that WebViewCore will pause while the dialog is
// up.
rVal = true;
}
return rVal;
|
protected void | onScrollChanged(int l, int t, int oldl, int oldt)
super.onScrollChanged(l, t, oldl, oldt);
sendOurVisibleRect();
|
protected void | onSizeChanged(int w, int h, int ow, int oh)
super.onSizeChanged(w, h, ow, oh);
// Center zooming to the center of the screen.
mZoomCenterX = getViewWidth() * .5f;
mZoomCenterY = getViewHeight() * .5f;
// update mMinZoomScale if the minimum zoom scale is not fixed
if (!mMinZoomScaleFixed) {
mMinZoomScale = (float) getViewWidth()
/ Math.max(ZOOM_OUT_WIDTH, mContentWidth);
}
// we always force, in case our height changed, in which case we still
// want to send the notification over to webkit
setNewZoomScale(mActualScale, true);
|
public boolean | onTouchEvent(android.view.MotionEvent ev)
if (mNativeClass == 0 || !isClickable() || !isLongClickable()) {
return false;
}
if (LOGV_ENABLED) {
Log.v(LOGTAG, ev + " at " + ev.getEventTime() + " mTouchMode="
+ mTouchMode);
}
int action = ev.getAction();
float x = ev.getX();
float y = ev.getY();
long eventTime = ev.getEventTime();
// Due to the touch screen edge effect, a touch closer to the edge
// always snapped to the edge. As getViewWidth() can be different from
// getWidth() due to the scrollbar, adjusting the point to match
// getViewWidth(). Same applied to the height.
if (x > getViewWidth() - 1) {
x = getViewWidth() - 1;
}
if (y > getViewHeight() - 1) {
y = getViewHeight() - 1;
}
// pass the touch events from UI thread to WebCore thread
if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT
&& mTouchMode != SCROLL_ZOOM_ANIMATION_IN
&& mTouchMode != SCROLL_ZOOM_ANIMATION_OUT
&& (action != MotionEvent.ACTION_MOVE ||
eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
ted.mX = viewToContent((int) x + mScrollX);
ted.mY = viewToContent((int) y + mScrollY);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
}
int deltaX = (int) (mLastTouchX - x);
int deltaY = (int) (mLastTouchY - y);
switch (action) {
case MotionEvent.ACTION_DOWN: {
if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN
|| mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
// no interaction while animation is in progress
break;
} else if (mTouchMode == SCROLL_ZOOM_OUT) {
mLastScrollX = mZoomScrollX;
mLastScrollY = mZoomScrollY;
// If two taps are close, ignore the first tap
} else if (!mScroller.isFinished()) {
mScroller.abortAnimation();
mTouchMode = TOUCH_DRAG_START_MODE;
mPrivateHandler.removeMessages(RESUME_WEBCORE_UPDATE);
} else if (mShiftIsPressed) {
mSelectX = mScrollX + (int) x;
mSelectY = mScrollY + (int) y;
mTouchMode = TOUCH_SELECT_MODE;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY);
}
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
(eventTime - mLastTouchUpTime), eventTime);
}
}
// Trigger the link
if (mTouchMode == TOUCH_INIT_MODE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
}
// Remember where the motion event started
mLastTouchX = x;
mLastTouchY = y;
mLastTouchTime = eventTime;
mVelocityTracker = VelocityTracker.obtain();
mSnapScrollMode = SNAP_NONE;
break;
}
case MotionEvent.ACTION_MOVE: {
if (mTouchMode == TOUCH_DONE_MODE
|| mTouchMode == SCROLL_ZOOM_ANIMATION_IN
|| mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
// no dragging during scroll zoom animation
break;
}
if (mTouchMode == SCROLL_ZOOM_OUT) {
// while fully zoomed out, move the virtual window
moveZoomScrollWindow(x, y);
break;
}
mVelocityTracker.addMovement(ev);
if (mTouchMode != TOUCH_DRAG_MODE) {
if (mTouchMode == TOUCH_SELECT_MODE) {
mSelectX = mScrollX + (int) x;
mSelectY = mScrollY + (int) y;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY);
}
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), true);
invalidate();
break;
}
if (mPreventDrag || (deltaX * deltaX + deltaY * deltaY)
< mTouchSlopSquare) {
break;
}
if (mTouchMode == TOUCH_SHORTPRESS_MODE
|| mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
} else if (mTouchMode == TOUCH_INIT_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
}
// if it starts nearly horizontal or vertical, enforce it
int ax = Math.abs(deltaX);
int ay = Math.abs(deltaY);
if (ax > MAX_SLOPE_FOR_DIAG * ay) {
mSnapScrollMode = SNAP_X;
mSnapPositive = deltaX > 0;
} else if (ay > MAX_SLOPE_FOR_DIAG * ax) {
mSnapScrollMode = SNAP_Y;
mSnapPositive = deltaY > 0;
}
mTouchMode = TOUCH_DRAG_MODE;
WebViewCore.pauseUpdate(mWebViewCore);
int contentX = viewToContent((int) x + mScrollX);
int contentY = viewToContent((int) y + mScrollY);
if (inEditingMode()) {
mTextEntry.updateCachedTextfield();
}
nativeClearFocus(contentX, contentY);
// remove the zoom anchor if there is any
if (mZoomScale != 0) {
mWebViewCore
.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
}
WebSettings settings = getSettings();
if (settings.supportZoom()
&& settings.getBuiltInZoomControls()
&& !mZoomButtonsController.isVisible()
&& (canZoomScrollOut() ||
mMinZoomScale < mMaxZoomScale)) {
mZoomButtonsController.setVisible(true);
}
}
// do pan
int newScrollX = pinLocX(mScrollX + deltaX);
deltaX = newScrollX - mScrollX;
int newScrollY = pinLocY(mScrollY + deltaY);
deltaY = newScrollY - mScrollY;
boolean done = false;
if (deltaX == 0 && deltaY == 0) {
done = true;
} else {
if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
int ax = Math.abs(deltaX);
int ay = Math.abs(deltaY);
if (mSnapScrollMode == SNAP_X) {
// radical change means getting out of snap mode
if (ay > MAX_SLOPE_FOR_DIAG * ax
&& ay > MIN_BREAK_SNAP_CROSS_DISTANCE) {
mSnapScrollMode = SNAP_NONE;
}
// reverse direction means lock in the snap mode
if ((ax > MAX_SLOPE_FOR_DIAG * ay) &&
((mSnapPositive &&
deltaX < -mMinLockSnapReverseDistance)
|| (!mSnapPositive &&
deltaX > mMinLockSnapReverseDistance))) {
mSnapScrollMode = SNAP_X_LOCK;
}
} else {
// radical change means getting out of snap mode
if ((ax > MAX_SLOPE_FOR_DIAG * ay)
&& ax > MIN_BREAK_SNAP_CROSS_DISTANCE) {
mSnapScrollMode = SNAP_NONE;
}
// reverse direction means lock in the snap mode
if ((ay > MAX_SLOPE_FOR_DIAG * ax) &&
((mSnapPositive &&
deltaY < -mMinLockSnapReverseDistance)
|| (!mSnapPositive &&
deltaY > mMinLockSnapReverseDistance))) {
mSnapScrollMode = SNAP_Y_LOCK;
}
}
}
if (mSnapScrollMode == SNAP_X
|| mSnapScrollMode == SNAP_X_LOCK) {
scrollBy(deltaX, 0);
mLastTouchX = x;
} else if (mSnapScrollMode == SNAP_Y
|| mSnapScrollMode == SNAP_Y_LOCK) {
scrollBy(0, deltaY);
mLastTouchY = y;
} else {
scrollBy(deltaX, deltaY);
mLastTouchX = x;
mLastTouchY = y;
}
mLastTouchTime = eventTime;
mUserScroll = true;
}
if (!getSettings().getBuiltInZoomControls()) {
boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
boolean showMagnify = canZoomScrollOut();
if (mZoomControls != null && (showPlusMinus || showMagnify)) {
if (mZoomControls.getVisibility() == View.VISIBLE) {
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
} else {
mZoomControls.show(showPlusMinus, showMagnify);
}
mPrivateHandler.postDelayed(mZoomControlRunnable,
ZOOM_CONTROLS_TIMEOUT);
}
}
if (done) {
// return false to indicate that we can't pan out of the
// view space
return false;
}
break;
}
case MotionEvent.ACTION_UP: {
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
case TOUCH_INIT_MODE: // tap
case TOUCH_SHORTPRESS_START_MODE:
case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mTouchMode = TOUCH_DONE_MODE;
doShortPress();
break;
case TOUCH_SELECT_MODE:
commitCopy();
mTouchSelection = false;
break;
case SCROLL_ZOOM_ANIMATION_IN:
case SCROLL_ZOOM_ANIMATION_OUT:
// no action during scroll animation
break;
case SCROLL_ZOOM_OUT:
if (LOGV_ENABLED) {
Log.v(LOGTAG, "ACTION_UP SCROLL_ZOOM_OUT"
+ " eventTime - mLastTouchTime="
+ (eventTime - mLastTouchTime));
}
// for now, always zoom back when the drag completes
if (true || eventTime - mLastTouchTime < TAP_TIMEOUT) {
// but if we tap, zoom in where we tap
if (eventTime - mLastTouchTime < TAP_TIMEOUT) {
zoomScrollTap(x, y);
}
// start zooming in back to the original view
setZoomScrollIn();
mTouchMode = SCROLL_ZOOM_ANIMATION_IN;
invalidate();
}
break;
case TOUCH_DRAG_MODE:
// if the user waits a while w/o moving before the
// up, we don't want to do a fling
if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
mVelocityTracker.addMovement(ev);
doFling();
break;
}
WebViewCore.resumeUpdate(mWebViewCore);
break;
case TOUCH_DRAG_START_MODE:
case TOUCH_DONE_MODE:
// do nothing
break;
}
// we also use mVelocityTracker == null to tell us that we are
// not "moving around", so we can take the slower/prettier
// mode in the drawing code
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
case MotionEvent.ACTION_CANCEL: {
// we also use mVelocityTracker == null to tell us that we are
// not "moving around", so we can take the slower/prettier
// mode in the drawing code
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
if (mTouchMode == SCROLL_ZOOM_OUT ||
mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
scrollTo(mZoomScrollX, mZoomScrollY);
} else if (mTouchMode == TOUCH_DRAG_MODE) {
WebViewCore.resumeUpdate(mWebViewCore);
}
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mTouchMode = TOUCH_DONE_MODE;
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
if (inEditingMode()) {
mTextEntry.updateCachedTextfield();
}
nativeClearFocus(contentX, contentY);
break;
}
}
return true;
|
public boolean | onTrackballEvent(android.view.MotionEvent ev)
long time = ev.getEventTime();
if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
if (ev.getY() > 0) pageDown(true);
if (ev.getY() < 0) pageUp(true);
return true;
}
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mPrivateHandler.removeMessages(SWITCH_TO_ENTER);
mTrackballDown = true;
if (mNativeClass != 0) {
nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
}
if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
&& !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
nativeSelectBestAt(mLastFocusBounds);
}
if (LOGV_ENABLED) {
Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
+ " time=" + time
+ " mLastFocusTime=" + mLastFocusTime);
}
if (isInTouchMode()) requestFocusFromTouch();
return false; // let common code in onKeyDown at it
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
// LONG_PRESS_ENTER is set in common onKeyDown
mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
mTrackballDown = false;
mTrackballUpTime = time;
if (mShiftIsPressed) {
if (mExtendSelection) {
commitCopy();
} else {
mExtendSelection = true;
}
}
if (LOGV_ENABLED) {
Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
+ " time=" + time
);
}
return false; // let common code in onKeyUp at it
}
if (mMapTrackballToArrowKeys && mShiftIsPressed == false) {
if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent gmail quit");
return false;
}
// no move if we're still waiting on SWITCH_TO_ENTER timeout
if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
return true;
}
if (mTrackballDown) {
if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent down quit");
return true; // discard move if trackball is down
}
if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) {
if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
return true;
}
// TODO: alternatively we can do panning as touch does
switchOutDrawHistory();
if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
if (LOGV_ENABLED) {
Log.v(LOGTAG, "onTrackballEvent time="
+ time + " last=" + mTrackballLastTime);
}
mTrackballFirstTime = time;
mTrackballXMove = mTrackballYMove = 0;
}
mTrackballLastTime = time;
if (LOGV_ENABLED) {
Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time);
}
mTrackballRemainsX += ev.getX();
mTrackballRemainsY += ev.getY();
doTrackball(time);
return true;
|
public void | onWindowFocusChanged(boolean hasWindowFocus)
if (hasWindowFocus) {
if (hasFocus()) {
// If our window regained focus, and we have focus, then begin
// drawing the focus ring, and restore the TextView if
// necessary.
mDrawFocusRing = true;
if (mNeedsUpdateTextEntry) {
updateTextEntry();
}
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
}
} else {
// If our window gained focus, but we do not have it, do not
// draw the focus ring.
mDrawFocusRing = false;
// We do not call nativeRecordButtons here because we assume
// that when we lost focus, or window focus, it got called with
// false for the first parameter
}
} else {
if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) {
/*
* The zoom controls come in their own window, so our window
* loses focus. Our policy is to not draw the focus ring if
* our window is not focused, but this is an exception since
* the user can still navigate the web page with the zoom
* controls showing.
*/
// If our window has lost focus, stop drawing the focus ring
mDrawFocusRing = false;
}
mGotKeyDown = false;
mShiftIsPressed = false;
if (mNativeClass != 0) {
nativeRecordButtons(false, false, true);
}
}
invalidate();
super.onWindowFocusChanged(hasWindowFocus);
|
public boolean | overlayHorizontalScrollbar()Return whether horizontal scrollbar has overlay style
return mOverlayHorizontalScrollbar;
|
public boolean | overlayVerticalScrollbar()Return whether vertical scrollbar has overlay style
return mOverlayVerticalScrollbar;
|
private void | overrideLoading(java.lang.String url)
mCallbackProxy.uiOverrideUrlLoading(url);
|
public boolean | pageDown(boolean bottom)Scroll the contents of the view down by half the page size
if (mNativeClass == 0) {
return false;
}
nativeClearFocus(-1, -1);
if (bottom) {
return pinScrollTo(mScrollX, mContentHeight, true, 0);
}
// Page down.
int h = getHeight();
int y;
if (h > 2 * PAGE_SCROLL_OVERLAP) {
y = h - PAGE_SCROLL_OVERLAP;
} else {
y = h / 2;
}
mUserScroll = true;
return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
|
public boolean | pageUp(boolean top)Scroll the contents of the view up by half the view size
if (mNativeClass == 0) {
return false;
}
nativeClearFocus(-1, -1);
if (top) {
// go to the top of the document
return pinScrollTo(mScrollX, 0, true, 0);
}
// Page up
int h = getHeight();
int y;
if (h > 2 * PAGE_SCROLL_OVERLAP) {
y = -h + PAGE_SCROLL_OVERLAP;
} else {
y = -h / 2;
}
mUserScroll = true;
return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
|
void | passToJavaScript(java.lang.String currentText, android.view.KeyEvent event)
HashMap arg = new HashMap();
arg.put("focusData", new WebViewCore.FocusData(mFocusData));
arg.put("event", event);
arg.put("currentText", currentText);
// Increase our text generation number, and pass it to webcore thread
mTextGeneration++;
mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
// WebKit's document state is not saved until about to leave the page.
// To make sure the host application, like Browser, has the up to date
// document state when it goes to background, we force to save the
// document state.
mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
new WebViewCore.FocusData(mFocusData), 1000);
|
public void | pauseTimers()Pause all layout, parsing, and javascript timers. This can be useful if
the WebView is not visible or the application has been paused.
mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
|
public boolean | performLongClick()
if (inEditingMode()) {
return mTextEntry.performLongClick();
} else {
return super.performLongClick();
}
|
private static int | pinLoc(int x, int viewMax, int docMax)
// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax);
if (docMax < viewMax) { // the doc has room on the sides for "blank"
// pin the short document to the top/left of the screen
x = 0;
// Log.d(LOGTAG, "--- center " + x);
} else if (x < 0) {
x = 0;
// Log.d(LOGTAG, "--- zero");
} else if (x + viewMax > docMax) {
x = docMax - viewMax;
// Log.d(LOGTAG, "--- pin " + x);
}
return x;
|
private int | pinLocX(int x)
return pinLoc(x, getViewWidth(), computeHorizontalScrollRange());
|
private int | pinLocY(int y)
return pinLoc(y, getViewHeight(), computeVerticalScrollRange());
|
private boolean | pinScrollBy(int dx, int dy, boolean animate, int animationDuration)
return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
|
private boolean | pinScrollTo(int x, int y, boolean animate, int animationDuration)
x = pinLocX(x);
y = pinLocY(y);
int dx = x - mScrollX;
int dy = y - mScrollY;
if ((dx | dy) == 0) {
return false;
}
if (true && animate) {
// Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
mScroller.startScroll(mScrollX, mScrollY, dx, dy,
animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
invalidate();
} else {
mScroller.abortAnimation(); // just in case
scrollTo(x, y);
}
return true;
|
private void | recordNewContentSize(int w, int h, boolean updateLayout)
// premature data from webkit, ignore
if ((w | h) == 0) {
return;
}
// don't abort a scroll animation if we didn't change anything
if (mContentWidth != w || mContentHeight != h) {
// record new dimensions
mContentWidth = w;
mContentHeight = h;
// If history Picture is drawn, don't update scroll. They will be
// updated when we get out of that mode.
if (!mDrawHistory) {
// repin our scroll, taking into account the new content size
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = pinLocX(mScrollX);
mScrollY = pinLocY(mScrollY);
// android.util.Log.d("skia", "recordNewContentSize -
// abortAnimation");
mScroller.abortAnimation(); // just in case
if (oldX != mScrollX || oldY != mScrollY) {
sendOurVisibleRect();
}
}
}
contentSizeChanged(updateLayout);
|
public void | refreshPlugins(boolean reloadOpenPages)Signal the WebCore thread to refresh its list of plugins. Use
this if the directory contents of one of the plugin directories
has been modified and needs its changes reflecting. May cause
plugin load and/or unload.
if (mWebViewCore != null) {
mWebViewCore.sendMessage(EventHub.REFRESH_PLUGINS, reloadOpenPages);
}
|
public void | reload()Reload the current url.
switchOutDrawHistory();
mWebViewCore.sendMessage(EventHub.RELOAD);
|
void | replaceTextfieldText(int oldStart, int oldEnd, java.lang.String replace, int newStart, int newEnd)
HashMap arg = new HashMap();
arg.put("focusData", new WebViewCore.FocusData(mFocusData));
arg.put("replace", replace);
arg.put("start", new Integer(newStart));
arg.put("end", new Integer(newEnd));
mTextGeneration++;
mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
|
public boolean | requestChildRectangleOnScreen(android.view.View child, android.graphics.Rect rect, boolean immediate)
rect.offset(child.getLeft() - child.getScrollX(),
child.getTop() - child.getScrollY());
int height = getHeight() - getHorizontalScrollbarHeight();
int screenTop = mScrollY;
int screenBottom = screenTop + height;
int scrollYDelta = 0;
if (rect.bottom > screenBottom && rect.top > screenTop) {
if (rect.height() > height) {
scrollYDelta += (rect.top - screenTop);
} else {
scrollYDelta += (rect.bottom - screenBottom);
}
} else if (rect.top < screenTop) {
scrollYDelta -= (screenTop - rect.top);
}
int width = getWidth() - getVerticalScrollbarWidth();
int screenLeft = mScrollX;
int screenRight = screenLeft + width;
int scrollXDelta = 0;
if (rect.right > screenRight && rect.left > screenLeft) {
if (rect.width() > width) {
scrollXDelta += (rect.left - screenLeft);
} else {
scrollXDelta += (rect.right - screenRight);
}
} else if (rect.left < screenLeft) {
scrollXDelta -= (screenLeft - rect.left);
}
if ((scrollYDelta | scrollXDelta) != 0) {
return pinScrollBy(scrollXDelta, scrollYDelta, !immediate, 0);
}
return false;
|
public boolean | requestFocus(int direction, android.graphics.Rect previouslyFocusedRect)
boolean result = false;
if (inEditingMode()) {
result = mTextEntry.requestFocus(direction, previouslyFocusedRect);
} else {
result = super.requestFocus(direction, previouslyFocusedRect);
if (mWebViewCore.getSettings().getNeedInitialFocus()) {
// For cases such as GMail, where we gain focus from a direction,
// we want to move to the first available link.
// FIXME: If there are no visible links, we may not want to
int fakeKeyDirection = 0;
switch(direction) {
case View.FOCUS_UP:
fakeKeyDirection = KeyEvent.KEYCODE_DPAD_UP;
break;
case View.FOCUS_DOWN:
fakeKeyDirection = KeyEvent.KEYCODE_DPAD_DOWN;
break;
case View.FOCUS_LEFT:
fakeKeyDirection = KeyEvent.KEYCODE_DPAD_LEFT;
break;
case View.FOCUS_RIGHT:
fakeKeyDirection = KeyEvent.KEYCODE_DPAD_RIGHT;
break;
default:
return result;
}
if (mNativeClass != 0 && !nativeUpdateFocusNode()) {
navHandledKey(fakeKeyDirection, 1, true, 0);
}
}
}
return result;
|
public void | requestFocusNodeHref(android.os.Message hrefMsg)Request the href of an anchor element due to getFocusNodePath returning
"href." If hrefMsg is null, this method returns immediately and does not
dispatch hrefMsg to its target.
if (hrefMsg == null || mNativeClass == 0) {
return;
}
if (nativeUpdateFocusNode()) {
FocusNode node = mFocusNode;
if (node.mIsAnchor) {
// NOTE: We may already have the url of the anchor stored in
// node.mText but it may be out of date or the caller may want
// to know about javascript urls.
mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
node.mFramePointer, node.mNodePointer, hrefMsg);
}
}
|
public void | requestImageRef(android.os.Message msg)Request the url of the image last touched by the user. msg will be sent
to its target with a String representing the url as its object.
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
String ref = nativeImageURI(contentX, contentY);
Bundle data = msg.getData();
data.putString("url", ref);
msg.setData(data);
msg.sendToTarget();
|
void | requestListBox(java.lang.String[] array, boolean[] enabledArray, int[] selectedArray)
mPrivateHandler.post(
new InvokeListBox(array, enabledArray, selectedArray));
|
void | requestListBox(java.lang.String[] array, boolean[] enabledArray, int selection)
mPrivateHandler.post(
new InvokeListBox(array, enabledArray, selection));
|
void | resetTrackballTime()
mTrackballLastTime = 0;
|
public boolean | restorePicture(android.os.Bundle b, java.io.File src)Restore the display data that was save in {@link #savePicture}. Used in
conjunction with {@link #restoreState}.
if (src == null || b == null) {
return false;
}
if (src.exists()) {
Picture p = null;
try {
final FileInputStream in = new FileInputStream(src);
p = Picture.createFromStream(in);
in.close();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (p != null) {
int sx = b.getInt("scrollX", 0);
int sy = b.getInt("scrollY", 0);
float scale = b.getFloat("scale", 1.0f);
mDrawHistory = true;
mHistoryPicture = p;
mScrollX = sx;
mScrollY = sy;
mHistoryWidth = Math.round(p.getWidth() * scale);
mHistoryHeight = Math.round(p.getHeight() * scale);
// as getWidth() / getHeight() of the view are not
// available yet, set up mActualScale, so that when
// onSizeChanged() is called, the rest will be set
// correctly
mActualScale = scale;
invalidate();
return true;
}
}
return false;
|
public WebBackForwardList | restoreState(android.os.Bundle inState)Restore the state of this WebView from the given map used in
{@link android.app.Activity#onRestoreInstanceState}. This method should
be called to restore the state of the WebView before using the object. If
it is called after the WebView has had a chance to build state (load
pages, create a back/forward list, etc.) there may be undesirable
side-effects. Please note that this method no longer restores the
display data for this WebView. See {@link #savePicture} and {@link
#restorePicture} for saving and restoring the display data.
WebBackForwardList returnList = null;
if (inState == null) {
return returnList;
}
if (inState.containsKey("index") && inState.containsKey("history")) {
mCertificate = SslCertificate.restoreState(
inState.getBundle("certificate"));
final WebBackForwardList list = mCallbackProxy.getBackForwardList();
final int index = inState.getInt("index");
// We can't use a clone of the list because we need to modify the
// shared copy, so synchronize instead to prevent concurrent
// modifications.
synchronized (list) {
final List<byte[]> history =
(List<byte[]>) inState.getSerializable("history");
final int size = history.size();
// Check the index bounds so we don't crash in native code while
// restoring the history index.
if (index < 0 || index >= size) {
return null;
}
for (int i = 0; i < size; i++) {
byte[] data = history.remove(0);
if (data == null) {
// If we somehow have null data, we cannot reconstruct
// the item and thus our history list cannot be rebuilt.
return null;
}
WebHistoryItem item = new WebHistoryItem(data);
list.addHistoryItem(item);
}
// Grab the most recent copy to return to the caller.
returnList = copyBackForwardList();
// Update the copy to have the correct index.
returnList.setCurrentIndex(index);
}
// Remove all pending messages because we are restoring previous
// state.
mWebViewCore.removeMessages();
// Send a restore state message.
mWebViewCore.sendMessage(EventHub.RESTORE_STATE, index);
}
return returnList;
|
public void | resumeTimers()Resume all layout, parsing, and javascript timers. This will resume
dispatching all timers.
mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
|
public void | savePassword(java.lang.String host, java.lang.String username, java.lang.String password)Save the username and password for a particular host in the WebView's
internal database.
mDatabase.setUsernamePassword(host, username, password);
|
public boolean | savePicture(android.os.Bundle b, java.io.File dest)Save the current display data to the Bundle given. Used in conjunction
with {@link #saveState}.
if (dest == null || b == null) {
return false;
}
final Picture p = capturePicture();
try {
final FileOutputStream out = new FileOutputStream(dest);
p.writeToStream(out);
out.close();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
}
if (dest.length() > 0) {
b.putInt("scrollX", mScrollX);
b.putInt("scrollY", mScrollY);
b.putFloat("scale", mActualScale);
return true;
}
return false;
|
public WebBackForwardList | saveState(android.os.Bundle outState)Save the state of this WebView used in
{@link android.app.Activity#onSaveInstanceState}. Please note that this
method no longer stores the display data for this WebView. The previous
behavior could potentially leak files if {@link #restoreState} was never
called. See {@link #savePicture} and {@link #restorePicture} for saving
and restoring the display data.
if (outState == null) {
return null;
}
// We grab a copy of the back/forward list because a client of WebView
// may have invalidated the history list by calling clearHistory.
WebBackForwardList list = copyBackForwardList();
final int currentIndex = list.getCurrentIndex();
final int size = list.getSize();
// We should fail saving the state if the list is empty or the index is
// not in a valid range.
if (currentIndex < 0 || currentIndex >= size || size == 0) {
return null;
}
outState.putInt("index", currentIndex);
// FIXME: This should just be a byte[][] instead of ArrayList but
// Parcel.java does not have the code to handle multi-dimensional
// arrays.
ArrayList<byte[]> history = new ArrayList<byte[]>(size);
for (int i = 0; i < size; i++) {
WebHistoryItem item = list.getItemAtIndex(i);
byte[] data = item.getFlattenedData();
if (data == null) {
// It would be very odd to not have any data for a given history
// item. And we will fail to rebuild the history list without
// flattened data.
return null;
}
history.add(data);
}
outState.putSerializable("history", history);
if (mCertificate != null) {
outState.putBundle("certificate",
SslCertificate.saveState(mCertificate));
}
return list;
|
private int | scaleTrackballX(float xRate, int width)
int xMove = (int) (xRate / TRACKBALL_SCALE * width);
int nextXMove = xMove;
if (xMove > 0) {
if (xMove > mTrackballXMove) {
xMove -= mTrackballXMove;
}
} else if (xMove < mTrackballXMove) {
xMove -= mTrackballXMove;
}
mTrackballXMove = nextXMove;
return xMove;
|
private int | scaleTrackballY(float yRate, int height)
int yMove = (int) (yRate / TRACKBALL_SCALE * height);
int nextYMove = yMove;
if (yMove > 0) {
if (yMove > mTrackballYMove) {
yMove -= mTrackballYMove;
}
} else if (yMove < mTrackballYMove) {
yMove -= mTrackballYMove;
}
mTrackballYMove = nextYMove;
return yMove;
|
private void | scrollZoomDraw(android.graphics.Canvas canvas)
float invScale = mZoomScrollInvLimit;
int elapsed = 0;
if (mTouchMode != SCROLL_ZOOM_OUT) {
elapsed = (int) Math.min(System.currentTimeMillis()
- mZoomScrollStart, SCROLL_ZOOM_DURATION);
float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
* elapsed / SCROLL_ZOOM_DURATION;
if (mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
invScale = mInvActualScale + transitionScale;
} else { /* if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) */
invScale = mZoomScrollInvLimit - transitionScale;
}
}
float scale = scrollZoomGridScale(invScale);
invScale = 1.0f / scale;
int width = getViewWidth();
int height = getViewHeight();
float halfScale = scrollZoomMagScale(invScale);
Rect scrollFrame = scrollZoomFrame(width, height, halfScale);
if (elapsed == SCROLL_ZOOM_DURATION) {
if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
updateTextEntry();
scrollTo((int) (scrollFrame.centerX() * mActualScale)
- (width >> 1), (int) (scrollFrame.centerY()
* mActualScale) - (height >> 1));
mTouchMode = TOUCH_DONE_MODE;
} else {
mTouchMode = SCROLL_ZOOM_OUT;
}
}
float newX = scrollZoomX(scale);
float newY = scrollZoomY(scale);
if (LOGV_ENABLED) {
Log.v(LOGTAG, "scrollZoomDraw scale=" + scale + " + (" + newX
+ ", " + newY + ") mZoomScroll=(" + mZoomScrollX + ", "
+ mZoomScrollY + ")" + " invScale=" + invScale + " scale="
+ scale);
}
canvas.translate(newX, newY);
canvas.scale(scale, scale);
boolean animating = mTouchMode != SCROLL_ZOOM_OUT;
if (mDrawHistory) {
int sc = canvas.save(Canvas.CLIP_SAVE_FLAG);
Rect clip = new Rect(0, 0, mHistoryPicture.getWidth(),
mHistoryPicture.getHeight());
canvas.clipRect(clip, Region.Op.DIFFERENCE);
canvas.drawColor(mBackgroundColor);
canvas.restoreToCount(sc);
canvas.drawPicture(mHistoryPicture);
} else {
mWebViewCore.drawContentPicture(canvas, mBackgroundColor,
animating, true);
}
if (mTouchMode == TOUCH_DONE_MODE) {
return;
}
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(30.0f);
paint.setARGB(0x50, 0, 0, 0);
int maxX = mContentWidth - width;
int maxY = mContentHeight - height;
if (true) { // experiment: draw hint to place finger off magnify area
drawMagnifyFrame(canvas, scrollFrame, paint);
} else {
canvas.drawRect(scrollFrame, paint);
}
int sc = canvas.save();
canvas.clipRect(scrollFrame);
float halfX = (float) mZoomScrollX / maxX;
if (mContentWidth * mZoomScrollLimit < width) {
halfX = zoomFrameScaleX(width, 0.5f, halfX);
}
float halfY = (float) mZoomScrollY / maxY;
if (mContentHeight * mZoomScrollLimit < height) {
halfY = zoomFrameScaleY(height, 0.5f, halfY);
}
canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX
, mZoomScrollY + height * halfY);
if (LOGV_ENABLED) {
Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
+ width + ", " + height + ") half=(" + halfX + ", "
+ halfY + ")");
}
if (mDrawHistory) {
canvas.drawPicture(mHistoryPicture);
} else {
mWebViewCore.drawContentPicture(canvas, mBackgroundColor,
animating, false);
}
canvas.restoreToCount(sc);
if (mTouchMode != SCROLL_ZOOM_OUT) {
invalidate();
}
|
private android.graphics.Rect | scrollZoomFrame(int width, int height, float halfScale)
Rect scrollFrame = new Rect();
scrollFrame.set(mZoomScrollX, mZoomScrollY,
mZoomScrollX + width, mZoomScrollY + height);
if (mContentWidth * mZoomScrollLimit < width) {
float scale = zoomFrameScaleX(width, halfScale, 1.0f);
float offsetX = (width * scale - width) * 0.5f;
scrollFrame.left -= offsetX;
scrollFrame.right += offsetX;
}
if (mContentHeight * mZoomScrollLimit < height) {
float scale = zoomFrameScaleY(height, halfScale, 1.0f);
float offsetY = (height * scale - height) * 0.5f;
scrollFrame.top -= offsetY;
scrollFrame.bottom += offsetY;
}
return scrollFrame;
|
private float | scrollZoomGridScale(float invScale)
float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
/ (float) SCROLL_ZOOM_GRID;
return 1.0f / griddedInvScale;
|
private float | scrollZoomMagScale(float invScale)
return (invScale * 2 + mInvActualScale) / 3;
|
private float | scrollZoomX(float scale)
int width = getViewWidth();
float maxScrollZoomX = mContentWidth * scale - width;
int maxX = mContentWidth - width;
return -(maxScrollZoomX > 0 ? mZoomScrollX * maxScrollZoomX / maxX
: maxScrollZoomX / 2);
|
private float | scrollZoomY(float scale)
int height = getViewHeight();
float maxScrollZoomY = mContentHeight * scale - height;
int maxY = mContentHeight - height;
return -(maxScrollZoomY > 0 ? mZoomScrollY * maxScrollZoomY / maxY
: maxScrollZoomY / 2);
|
private void | sendFinalFocus(int frame, int node, int x, int y)
WebViewCore.FocusData focusData = new WebViewCore.FocusData();
focusData.mFrame = frame;
focusData.mNode = node;
focusData.mX = x;
focusData.mY = y;
mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
EventHub.NO_FOCUS_CHANGE_BLOCK, 0, focusData);
|
private void | sendKitFocus()
WebViewCore.FocusData focusData = new WebViewCore.FocusData(mFocusData);
mWebViewCore.sendMessage(EventHub.SET_KIT_FOCUS, focusData);
|
private void | sendMotionUp(int touchGeneration, int buildGeneration, int frame, int node, int x, int y, int size, boolean isClick, boolean retry)
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
touchUpData.mMoveGeneration = touchGeneration;
touchUpData.mBuildGeneration = buildGeneration;
touchUpData.mSize = size;
touchUpData.mIsClick = isClick;
touchUpData.mRetry = retry;
mFocusData.mFrame = touchUpData.mFrame = frame;
mFocusData.mNode = touchUpData.mNode = node;
mFocusData.mX = touchUpData.mX = x;
mFocusData.mY = touchUpData.mY = y;
mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
|
private android.graphics.Rect | sendOurVisibleRect()
Rect rect = new Rect();
calcOurContentVisibleRect(rect);
if (mFindIsUp) {
rect.bottom -= viewToContent(FIND_HEIGHT);
}
// Rect.equals() checks for null input.
if (!rect.equals(mLastVisibleRectSent)) {
mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
rect.left, rect.top);
mLastVisibleRectSent = rect;
}
Rect globalRect = new Rect();
if (getGlobalVisibleRect(globalRect)
&& !globalRect.equals(mLastGlobalRect)) {
// TODO: the global offset is only used by windowRect()
// in ChromeClientAndroid ; other clients such as touch
// and mouse events could return view + screen relative points.
mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, globalRect);
mLastGlobalRect = globalRect;
}
return rect;
|
private boolean | sendViewSizeZoom()Compute unzoomed width and height, and if they differ from the last
values we sent, send them to webkit (to be used has new viewport)
int newWidth = Math.round(getViewWidth() * mInvActualScale);
int newHeight = Math.round(getViewHeight() * mInvActualScale);
/*
* Because the native side may have already done a layout before the
* View system was able to measure us, we have to send a height of 0 to
* remove excess whitespace when we grow our width. This will trigger a
* layout and a change in content size. This content size change will
* mean that contentSizeChanged will either call this method directly or
* indirectly from onSizeChanged.
*/
if (newWidth > mLastWidthSent && mWrapContent) {
newHeight = 0;
}
// Avoid sending another message if the dimensions have not changed.
if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED,
newWidth, newHeight, new Float(mActualScale));
mLastWidthSent = newWidth;
mLastHeightSent = newHeight;
return true;
}
return false;
|
public void | setBackgroundColor(int color)Set the background color. It's white by default. Pass
zero to make the view transparent.
mBackgroundColor = color;
mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color);
|
public void | setCertificate(android.net.http.SslCertificate certificate)Sets the SSL certificate for the main top-level page.
// here, the certificate can be null (if the site is not secure)
mCertificate = certificate;
|
private void | setContentScrollBy(int cx, int cy, boolean animate)
if (mDrawHistory) {
// disallow WebView to change the scroll position as History Picture
// is used in the view system.
// TODO: as we switchOutDrawHistory when trackball or navigation
// keys are hit, this should be safe. Right?
return;
}
cx = contentToView(cx);
cy = contentToView(cy);
if (mHeightCanMeasure) {
// move our visible rect according to scroll request
if (cy != 0) {
Rect tempRect = new Rect();
calcOurVisibleRect(tempRect);
tempRect.offset(cx, cy);
requestRectangleOnScreen(tempRect);
}
// FIXME: We scroll horizontally no matter what because currently
// ScrollView and ListView will not scroll horizontally.
// FIXME: Why do we only scroll horizontally if there is no
// vertical scroll?
// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
if (cy == 0 && cx != 0) {
pinScrollBy(cx, 0, animate, 0);
}
} else {
pinScrollBy(cx, cy, animate, 0);
}
|
private boolean | setContentScrollTo(int cx, int cy)
if (mDrawHistory) {
// disallow WebView to change the scroll position as History Picture
// is used in the view system.
// One known case where this is called is that WebCore tries to
// restore the scroll position. As history Picture already uses the
// saved scroll position, it is ok to skip this.
return false;
}
int vx = contentToView(cx);
int vy = contentToView(cy);
// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
// vx + " " + vy + "]");
pinScrollTo(vx, vy, false, 0);
if (mScrollX != vx || mScrollY != vy) {
return true;
} else {
return false;
}
|
public void | setDownloadListener(DownloadListener listener)Register the interface to be used when content can not be handled by
the rendering engine, and should be downloaded instead. This will replace
the current handler.
mCallbackProxy.setDownloadListener(listener);
|
private void | setFocusData(int moveGeneration, int buildGeneration, int frame, int node, int x, int y, boolean ignoreNullFocus)
mFocusData.mMoveGeneration = moveGeneration;
mFocusData.mBuildGeneration = buildGeneration;
mFocusData.mFrame = frame;
mFocusData.mNode = node;
mFocusData.mX = x;
mFocusData.mY = y;
mFocusData.mIgnoreNullFocus = ignoreNullFocus;
|
public void | setHorizontalScrollbarOverlay(boolean overlay)Specify whether the horizontal scrollbar has overlay style.
mOverlayHorizontalScrollbar = overlay;
|
public void | setHttpAuthUsernamePassword(java.lang.String host, java.lang.String realm, java.lang.String username, java.lang.String password)Set the HTTP authentication credentials for a given host and realm.
mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
|
public void | setInitialScale(int scaleInPercent)Set the initial scale for the WebView. 0 means default. If
{@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
way. Otherwise it starts with 100%. If initial scale is greater than 0,
WebView starts will this value as initial scale.
mInitialScale = scaleInPercent;
|
public void | setLayoutParams(ViewGroup.LayoutParams params)
if (params.height == LayoutParams.WRAP_CONTENT) {
mWrapContent = true;
}
super.setLayoutParams(params);
|
public void | setMapTrackballToArrowKeys(boolean setMap)
mMapTrackballToArrowKeys = setMap;
|
public void | setNetworkAvailable(boolean networkUp)Inform WebView of the network state. This is used to set
the javascript property window.navigator.isOnline and
generates the online/offline event as specified in HTML5, sec. 5.7.7
mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE,
networkUp ? 1 : 0, 0);
|
private void | setNewZoomScale(float scale, boolean force)
if (scale < mMinZoomScale) {
scale = mMinZoomScale;
} else if (scale > mMaxZoomScale) {
scale = mMaxZoomScale;
}
if (scale != mActualScale || force) {
if (mDrawHistory) {
// If history Picture is drawn, don't update scroll. They will
// be updated when we get out of that mode.
if (scale != mActualScale && !mPreviewZoomOnly) {
mCallbackProxy.onScaleChanged(mActualScale, scale);
}
mActualScale = scale;
mInvActualScale = 1 / scale;
if (!mPreviewZoomOnly) {
sendViewSizeZoom();
}
} else {
// update our scroll so we don't appear to jump
// i.e. keep the center of the doc in the center of the view
int oldX = mScrollX;
int oldY = mScrollY;
float ratio = scale * mInvActualScale; // old inverse
float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
float sy = ratio * oldY + (ratio - 1) * mZoomCenterY;
// now update our new scale and inverse
if (scale != mActualScale && !mPreviewZoomOnly) {
mCallbackProxy.onScaleChanged(mActualScale, scale);
}
mActualScale = scale;
mInvActualScale = 1 / scale;
// as we don't have animation for scaling, don't do animation
// for scrolling, as it causes weird intermediate state
// pinScrollTo(Math.round(sx), Math.round(sy));
mScrollX = pinLocX(Math.round(sx));
mScrollY = pinLocY(Math.round(sy));
if (!mPreviewZoomOnly) {
sendViewSizeZoom();
sendOurVisibleRect();
}
}
}
|
public void | setPictureListener(android.webkit.WebView$PictureListener listener)Set the Picture listener. This is an interface used to receive
notifications of a new Picture.
mPictureListener = listener;
|
public void | setScrollBarStyle(int style)
if (style == View.SCROLLBARS_INSIDE_INSET
|| style == View.SCROLLBARS_OUTSIDE_INSET) {
mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
} else {
mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
}
super.setScrollBarStyle(style);
|
void | setSelection(int start, int end)Set the selection to (start, end) in the focused textfield. If start and
end are out of order, swap them.
mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end,
new WebViewCore.FocusData(mFocusData));
|
private void | setTextEntryRect(int x, int y, int width, int height)
x = contentToView(x);
y = contentToView(y);
width = contentToView(width);
height = contentToView(height);
mTextEntry.setRect(x, y, width, height);
|
public void | setVerticalScrollbarOverlay(boolean overlay)Specify whether the vertical scrollbar has overlay style.
mOverlayVerticalScrollbar = overlay;
|
public void | setWebChromeClient(WebChromeClient client)Set the chrome handler. This is an implementation of WebChromeClient for
use in handling Javascript dialogs, favicons, titles, and the progress.
This will replace the current handler.
mCallbackProxy.setWebChromeClient(client);
|
public void | setWebViewClient(WebViewClient client)Set the WebViewClient that will receive various notifications and
requests. This will replace the current handler.
mCallbackProxy.setWebViewClient(client);
|
private void | setZoomScrollIn()
mZoomScrollStart = System.currentTimeMillis();
|
void | shortPressOnTextField()
if (inEditingMode()) {
View v = mTextEntry;
int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
nativeMotionUp(x, y, mNavSlop, true);
}
|
private void | spawnContentScrollTo(int cx, int cy)
if (mDrawHistory) {
// disallow WebView to change the scroll position as History Picture
// is used in the view system.
return;
}
int vx = contentToView(cx);
int vy = contentToView(cy);
pinScrollTo(vx, vy, true, 0);
|
private void | startZoomScrollOut()
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
if (getSettings().getBuiltInZoomControls()) {
if (mZoomButtonsController.isVisible()) {
mZoomButtonsController.setVisible(false);
}
} else {
if (mZoomControlRunnable != null) {
mPrivateHandler.removeCallbacks(mZoomControlRunnable);
}
if (mZoomControls != null) {
mZoomControls.hide();
}
}
int width = getViewWidth();
int height = getViewHeight();
int halfW = width >> 1;
mLastTouchX = halfW;
int halfH = height >> 1;
mLastTouchY = halfH;
mScroller.abortAnimation();
mZoomScrollStart = System.currentTimeMillis();
Rect zoomFrame = scrollZoomFrame(width, height
, scrollZoomMagScale(mZoomScrollInvLimit));
mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
- (zoomFrame.width() >> 1));
mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
- (zoomFrame.height() >> 1));
scrollTo(0, 0); // triggers inval, starts animation
clearTextEntry();
if (LOGV_ENABLED) {
Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
+ mZoomScrollX + ", " + mZoomScrollY +")");
}
|
public void | stopLoading()Stop the current load.
// TODO: should we clear all the messages in the queue before sending
// STOP_LOADING?
switchOutDrawHistory();
mWebViewCore.sendMessage(EventHub.STOP_LOADING);
|
void | switchOutDrawHistory()
if (null == mWebViewCore) return; // CallbackProxy may trigger this
if (mDrawHistory) {
mDrawHistory = false;
invalidate();
int oldScrollX = mScrollX;
int oldScrollY = mScrollY;
mScrollX = pinLocX(mScrollX);
mScrollY = pinLocY(mScrollY);
if (oldScrollX != mScrollX || oldScrollY != mScrollY) {
mUserScroll = false;
mWebViewCore.sendMessage(EventHub.SYNC_SCROLL, oldScrollX,
oldScrollY);
}
sendOurVisibleRect();
}
|
void | updateCachedTextfield(java.lang.String updatedText)Update our cache with updatedText.
// Also place our generation number so that when we look at the cache
// we recognize that it is up to date.
nativeUpdateCachedTextfield(updatedText, mTextGeneration);
|
private void | updateSelection()
if (mNativeClass == 0) {
return;
}
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
contentX + mNavSlop, contentY + mNavSlop);
// If we were already focused on a textfield, update its cache.
if (inEditingMode()) {
mTextEntry.updateCachedTextfield();
}
nativeSelectBestAt(rect);
|
private void | updateTextEntry()
if (mTextEntry == null) {
mTextEntry = new TextDialog(mContext, WebView.this);
// Initialize our generation number.
mTextGeneration = 0;
}
// If we do not have focus, do nothing until we gain focus.
if (!hasFocus() && !mTextEntry.hasFocus()
|| (mTouchMode >= FIRST_SCROLL_ZOOM
&& mTouchMode <= LAST_SCROLL_ZOOM)) {
mNeedsUpdateTextEntry = true;
return;
}
boolean alreadyThere = inEditingMode();
if (0 == mNativeClass || !nativeUpdateFocusNode()) {
if (alreadyThere) {
mTextEntry.remove();
}
return;
}
FocusNode node = mFocusNode;
if (!node.mIsTextField && !node.mIsTextArea) {
if (alreadyThere) {
mTextEntry.remove();
}
return;
}
mTextEntry.setTextSize(contentToView(node.mTextSize));
Rect visibleRect = sendOurVisibleRect();
// Note that sendOurVisibleRect calls viewToContent, so the coordinates
// should be in content coordinates.
if (!Rect.intersects(node.mBounds, visibleRect)) {
// Node is not on screen, so do not bother.
return;
}
int x = node.mBounds.left;
int y = node.mBounds.top;
int width = node.mBounds.width();
int height = node.mBounds.height();
if (alreadyThere && mTextEntry.isSameTextField(node.mNodePointer)) {
// It is possible that we have the same textfield, but it has moved,
// i.e. In the case of opening/closing the screen.
// In that case, we need to set the dimensions, but not the other
// aspects.
// We also need to restore the selection, which gets wrecked by
// calling setTextEntryRect.
Spannable spannable = (Spannable) mTextEntry.getText();
int start = Selection.getSelectionStart(spannable);
int end = Selection.getSelectionEnd(spannable);
setTextEntryRect(x, y, width, height);
// If the text has been changed by webkit, update it. However, if
// there has been more UI text input, ignore it. We will receive
// another update when that text is recognized.
if (node.mText != null && !node.mText.equals(spannable.toString())
&& node.mRootTextGeneration == mTextGeneration) {
mTextEntry.setTextAndKeepSelection(node.mText);
} else {
Selection.setSelection(spannable, start, end);
}
} else {
String text = node.mText;
setTextEntryRect(x, y, width, height);
mTextEntry.setGravity(node.mIsRtlText ? Gravity.RIGHT :
Gravity.NO_GRAVITY);
// this needs to be called before update adapter thread starts to
// ensure the mTextEntry has the same node pointer
mTextEntry.setNodePointer(node.mNodePointer);
int maxLength = -1;
if (node.mIsTextField) {
maxLength = node.mMaxLength;
if (mWebViewCore.getSettings().getSaveFormData()
&& node.mName != null) {
HashMap data = new HashMap();
data.put("text", node.mText);
Message update = mPrivateHandler.obtainMessage(
UPDATE_TEXT_ENTRY_ADAPTER, node.mNodePointer, 0,
data);
UpdateTextEntryAdapter updater = new UpdateTextEntryAdapter(
node.mName, getUrl(), update);
Thread t = new Thread(updater);
t.start();
}
}
mTextEntry.setMaxLength(maxLength);
AutoCompleteAdapter adapter = null;
mTextEntry.setAdapterCustom(adapter);
mTextEntry.setSingleLine(node.mIsTextField);
mTextEntry.setInPassword(node.mIsPassword);
if (null == text) {
mTextEntry.setText("", 0, 0);
} else {
// Change to true to enable the old style behavior, where
// entering a textfield/textarea always set the selection to the
// whole field. This was desirable for the case where the user
// intends to scroll past the field using the trackball.
// However, it causes a problem when replying to emails - the
// user expects the cursor to be at the beginning of the
// textarea. Testing out a new behavior, where textfields set
// selection at the end, and textareas at the beginning.
if (false) {
mTextEntry.setText(text, 0, text.length());
} else if (node.mIsTextField) {
int length = text.length();
mTextEntry.setText(text, length, length);
} else {
mTextEntry.setText(text, 0, 0);
}
}
mTextEntry.requestFocus();
}
|
private void | updateZoomButtonsEnabled()
boolean canZoomIn = mActualScale < mMaxZoomScale;
boolean canZoomOut = mActualScale > mMinZoomScale;
if (!canZoomIn && !canZoomOut) {
// Hide the zoom in and out buttons, as well as the fit to page
// button, if the page cannot zoom
mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
mZoomFitPageButton.setVisibility(View.GONE);
} else {
// Bring back the hidden zoom controls.
mZoomButtonsController.getZoomControls()
.setVisibility(View.VISIBLE);
mZoomFitPageButton.setVisibility(View.VISIBLE);
// Set each one individually, as a page may be able to zoom in
// or out.
mZoomButtonsController.setZoomInEnabled(canZoomIn);
mZoomButtonsController.setZoomOutEnabled(canZoomOut);
mZoomFitPageButton.setEnabled(mActualScale != 1);
}
mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE:
View.GONE);
|
private void | viewInvalidate()Called by JNI to invalidate view
invalidate();
|
private void | viewInvalidate(int l, int t, int r, int b)
invalidate(contentToView(l), contentToView(t), contentToView(r),
contentToView(b));
|
private void | viewInvalidateDelayed(long delay, int l, int t, int r, int b)
postInvalidateDelayed(delay, contentToView(l), contentToView(t),
contentToView(r), contentToView(b));
|
int | viewToContent(int x)
return Math.round(x * mInvActualScale);
|
private float | zoomFrameScaleX(int width, float halfScale, float noScale)
// mContentWidth > width > mContentWidth * mZoomScrollLimit
if (mContentWidth <= width) {
return halfScale;
}
float part = (width - mContentWidth * mZoomScrollLimit)
/ (width * (1 - mZoomScrollLimit));
return halfScale * part + noScale * (1.0f - part);
|
private float | zoomFrameScaleY(int height, float halfScale, float noScale)
if (mContentHeight <= height) {
return halfScale;
}
float part = (height - mContentHeight * mZoomScrollLimit)
/ (height * (1 - mZoomScrollLimit));
return halfScale * part + noScale * (1.0f - part);
|
public boolean | zoomIn()Perform zoom in in the webview
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
return zoomWithPreview(mActualScale * 1.25f);
|
public boolean | zoomOut()Perform zoom out in the webview
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
return zoomWithPreview(mActualScale * 0.8f);
|
private void | zoomScrollOut()
if (canZoomScrollOut() == false) {
mTouchMode = TOUCH_DONE_MODE;
return;
}
startZoomScrollOut();
mTouchMode = SCROLL_ZOOM_ANIMATION_OUT;
invalidate();
|
private void | zoomScrollTap(float x, float y)
float scale = scrollZoomGridScale(mZoomScrollInvLimit);
float left = scrollZoomX(scale);
float top = scrollZoomY(scale);
int width = getViewWidth();
int height = getViewHeight();
x -= width * scale / 2;
y -= height * scale / 2;
mZoomScrollX = Math.min(mContentWidth - width
, Math.max(0, (int) ((x - left) / scale)));
mZoomScrollY = Math.min(mContentHeight - height
, Math.max(0, (int) ((y - top) / scale)));
if (LOGV_ENABLED) {
Log.v(LOGTAG, "zoomScrollTap scale=" + scale + " + (" + left
+ ", " + top + ") mZoomScroll=(" + mZoomScrollX + ", "
+ mZoomScrollY + ")" + " x=" + x + " y=" + y);
}
|
private boolean | zoomWithPreview(float scale)
float oldScale = mActualScale;
// snap to 100% if it is close
if (scale > 0.95f && scale < 1.05f) {
scale = 1.0f;
}
setNewZoomScale(scale, false);
if (oldScale != mActualScale) {
// use mZoomPickerScale to see zoom preview first
mZoomStart = SystemClock.uptimeMillis();
mInvInitialZoomScale = 1.0f / oldScale;
mInvFinalZoomScale = 1.0f / mActualScale;
mZoomScale = mActualScale;
invalidate();
return true;
} else {
return false;
}
|