Merge "Add KDDI/Softbank to available Shift_Jis mapping."
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 1d9e0f1..2ead976 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1657,7 +1657,7 @@
}
boolean needsProvisioning;
try {
- needsProvisioning = telephony.getCdmaNeedsProvisioning();
+ needsProvisioning = telephony.needsOtaServiceProvisioning();
} catch (RemoteException e) {
Log.w(TAG, "exception while checking provisioning", e);
// default to NOT wiping out the passwords
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index c809b5a..eb36b5d 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -28,6 +28,7 @@
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.InputFilter;
+import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextPaint;
@@ -497,9 +498,10 @@
// to big for the case of a small textfield.
int smallerSlop = slop/2;
if (dx > smallerSlop || dy > smallerSlop) {
- if (mWebView != null) {
- float maxScrollX = (float) Touch.getMaxScrollX(this,
- getLayout(), mScrollY);
+ Layout layout = getLayout();
+ if (mWebView != null && layout != null) {
+ float maxScrollX = (float) Touch.getMaxScrollX(this, layout,
+ mScrollY);
if (DebugFlags.WEB_TEXT_VIEW) {
Log.v(LOGTAG, "onTouchEvent x=" + mScrollX + " y="
+ mScrollY + " maxX=" + maxScrollX);
@@ -936,14 +938,4 @@
/* package */ void updateCachedTextfield() {
mWebView.updateCachedTextfield(getText().toString());
}
-
- @Override
- public boolean requestRectangleOnScreen(Rect rectangle) {
- // don't scroll while in zoom animation. When it is done, we will adjust
- // the WebTextView if it is in editing mode.
- if (!mWebView.inAnimateZoom()) {
- return super.requestRectangleOnScreen(rectangle);
- }
- return false;
- }
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ebcf5c5..5a7e78b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -44,7 +44,6 @@
import android.text.IClipboard;
import android.text.Selection;
import android.text.Spannable;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -61,7 +60,6 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AlphaAnimation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
@@ -77,7 +75,6 @@
import android.widget.ListView;
import android.widget.Scroller;
import android.widget.Toast;
-import android.widget.ZoomButtonsController;
import android.widget.AdapterView.OnItemClickListener;
import java.io.File;
@@ -649,32 +646,6 @@
// initial scale in percent. 0 means using default.
private int mInitialScaleInPercent = 0;
- // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
- // engadget always have wider mContentWidth no matter what viewport size is.
- int mZoomOverviewWidth = DEFAULT_VIEWPORT_WIDTH;
- float mTextWrapScale;
-
- // default scale. Depending on the display density.
- static int DEFAULT_SCALE_PERCENT;
- private float mDefaultScale;
-
- private static float MINIMUM_SCALE_INCREMENT = 0.01f;
-
- // set to true temporarily during ScaleGesture triggered zoom
- private boolean mPreviewZoomOnly = false;
-
- // computed scale and inverse, from mZoomWidth.
- private float mActualScale;
- private float mInvActualScale;
- // if this is non-zero, it is used on drawing rather than mActualScale
- private float mZoomScale;
- private float mInvInitialZoomScale;
- private float mInvFinalZoomScale;
- private int mInitialScrollX;
- private int mInitialScrollY;
- private long mZoomStart;
- private static final int ZOOM_ANIMATION_LENGTH = 500;
-
private boolean mUserScroll = false;
private int mSnapScrollMode = SNAP_NONE;
@@ -815,11 +786,6 @@
}
}
- // These keep track of the center point of the zoom. They are used to
- // determine the point around which we should zoom.
- private float mZoomCenterX;
- private float mZoomCenterY;
-
/**
* Construct a new WebView with a Context object.
* @param context A Context object used to access application assets.
@@ -875,7 +841,7 @@
mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javascriptInterfaces);
mDatabase = WebViewDatabase.getInstance(context);
mScroller = new Scroller(context);
- mZoomManager = new ZoomManager(this);
+ mZoomManager = new ZoomManager(this, mCallbackProxy);
/* The init method must follow the creation of certain member variables,
* such as the mZoomManager.
@@ -914,12 +880,6 @@
// 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 * density);
- // density adjusted scale factors
- DEFAULT_SCALE_PERCENT = (int) (100 * density);
- mDefaultScale = density;
- mActualScale = density;
- mInvActualScale = 1 / density;
- mTextWrapScale = density;
mZoomManager.init(density);
mMaximumFling = configuration.getScaledMaximumFlingVelocity();
}
@@ -945,20 +905,10 @@
}
/* package */void updateDefaultZoomDensity(int zoomDensity) {
- final float density = getContext().getResources().getDisplayMetrics().density
+ final float density = mContext.getResources().getDisplayMetrics().density
* 100 / zoomDensity;
- if (Math.abs(density - mDefaultScale) > 0.01) {
- float scaleFactor = density / mDefaultScale;
- // adjust the limits
- mNavSlop = (int) (16 * density);
- DEFAULT_SCALE_PERCENT = (int) (100 * density);
- mZoomManager.DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
- mZoomManager.DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
- mDefaultScale = density;
- mZoomManager.mMaxZoomScale *= scaleFactor;
- mZoomManager.mMinZoomScale *= scaleFactor;
- setNewZoomScale(mActualScale * scaleFactor, true, false);
- }
+ mNavSlop = (int) (16 * density);
+ mZoomManager.updateDefaultZoomDensity(density);
}
/* package */ boolean onSavePassword(String schemePlusHost, String username,
@@ -1075,7 +1025,7 @@
* returns the height of the titlebarview (if any). Does not care about
* scrolling
*/
- private int getTitleHeight() {
+ int getTitleHeight() {
return mTitleBar != null ? mTitleBar.getHeight() : 0;
}
@@ -1336,8 +1286,8 @@
// now update the bundle
b.putInt("scrollX", mScrollX);
b.putInt("scrollY", mScrollY);
- b.putFloat("scale", mActualScale);
- b.putFloat("textwrapScale", mTextWrapScale);
+ b.putFloat("scale", mZoomManager.mActualScale);
+ b.putFloat("textwrapScale", mZoomManager.mTextWrapScale);
b.putBoolean("overview", mZoomManager.mInZoomOverview);
return true;
}
@@ -1355,9 +1305,9 @@
// 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;
- mInvActualScale = 1 / scale;
- mTextWrapScale = b.getFloat("textwrapScale", scale);
+ mZoomManager.mActualScale = scale;
+ mZoomManager.mInvActualScale = 1 / scale;
+ mZoomManager.mTextWrapScale = b.getFloat("textwrapScale", scale);
mZoomManager.mInZoomOverview = b.getBoolean("overview");
invalidate();
}
@@ -1778,7 +1728,7 @@
* @return The current scale.
*/
public float getScale() {
- return mActualScale;
+ return mZoomManager.mActualScale;
}
/**
@@ -1936,12 +1886,12 @@
}
// Expects x in view coordinates
- private int pinLocX(int x) {
+ int pinLocX(int x) {
return pinLoc(x, getViewWidth(), computeHorizontalScrollRange());
}
// Expects y in view coordinates
- private int pinLocY(int y) {
+ int pinLocY(int y) {
return pinLoc(y, getViewHeightWithTitle(),
computeVerticalScrollRange() + getTitleHeight());
}
@@ -1991,7 +1941,7 @@
* height.
*/
private int viewToContentDimension(int d) {
- return Math.round(d * mInvActualScale);
+ return Math.round(d * mZoomManager.mInvActualScale);
}
/**
@@ -2017,7 +1967,7 @@
* Returns the result as a float.
*/
private float viewToContentXf(int x) {
- return x * mInvActualScale;
+ return x * mZoomManager.mInvActualScale;
}
/**
@@ -2026,7 +1976,7 @@
* embedded into the WebView. Returns the result as a float.
*/
private float viewToContentYf(int y) {
- return (y - getTitleHeight()) * mInvActualScale;
+ return (y - getTitleHeight()) * mZoomManager.mInvActualScale;
}
/**
@@ -2036,7 +1986,7 @@
* height.
*/
/*package*/ int contentToViewDimension(int d) {
- return Math.round(d * mActualScale);
+ return Math.round(d * mZoomManager.mActualScale);
}
/**
@@ -2077,7 +2027,7 @@
// Called by JNI to invalidate the View, given rectangle coordinates in
// content space
private void viewInvalidate(int l, int t, int r, int b) {
- final float scale = mActualScale;
+ final float scale = mZoomManager.mActualScale;
final int dy = getTitleHeight();
invalidate((int)Math.floor(l * scale),
(int)Math.floor(t * scale) + dy,
@@ -2088,7 +2038,7 @@
// Called by JNI to invalidate the View after a delay, given rectangle
// coordinates in content space
private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
- final float scale = mActualScale;
+ final float scale = mZoomManager.mActualScale;
final int dy = getTitleHeight();
postInvalidateDelayed(delay,
(int)Math.floor(l * scale),
@@ -2126,13 +2076,7 @@
// 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);
- if (oldX != mScrollX || oldY != mScrollY) {
- onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- }
+ updateScrollCoordinates(pinLocX(mScrollX), pinLocY(mScrollY));
if (!mScroller.isFinished()) {
// We are in the middle of a scroll. Repin the final scroll
// position.
@@ -2144,79 +2088,12 @@
contentSizeChanged(updateLayout);
}
- private void setNewZoomScale(float scale, boolean updateTextWrapScale,
- boolean force) {
- if (scale < mZoomManager.mMinZoomScale) {
- scale = mZoomManager.mMinZoomScale;
- // set mInZoomOverview for non mobile sites
- if (scale < mDefaultScale) {
- mZoomManager.mInZoomOverview = true;
- }
- } else if (scale > mZoomManager.mMaxZoomScale) {
- scale = mZoomManager.mMaxZoomScale;
- }
- if (updateTextWrapScale) {
- mTextWrapScale = scale;
- // reset mLastHeightSent to force VIEW_SIZE_CHANGED sent to WebKit
- mLastHeightSent = 0;
- }
- 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;
- 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 - getTitleHeight());
-
- // now update our new scale and inverse
- if (scale != mActualScale && !mPreviewZoomOnly) {
- mCallbackProxy.onScaleChanged(mActualScale, scale);
- }
- mActualScale = scale;
- mInvActualScale = 1 / scale;
-
- // Scale all the child views
- mViewManager.scaleAll();
-
- // 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));
-
- // update webkit
- if (oldX != mScrollX || oldY != mScrollY) {
- onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- } else {
- // the scroll position is adjusted at the beginning of the
- // zoom animation. But we want to update the WebKit at the
- // end of the zoom animation. See comments in onScaleEnd().
- sendOurVisibleRect();
- }
- sendViewSizeZoom();
- }
- }
- }
-
// Used to avoid sending many visible rect messages.
private Rect mLastVisibleRectSent;
private Rect mLastGlobalRect;
- private Rect sendOurVisibleRect() {
- if (mPreviewZoomOnly) return mLastVisibleRectSent;
+ Rect sendOurVisibleRect() {
+ if (mZoomManager.mPreviewZoomOnly) return mLastVisibleRectSent;
Rect rect = new Rect();
calcOurContentVisibleRect(rect);
@@ -2283,6 +2160,11 @@
r.bottom = Math.min(viewToContentYf(ri.bottom), (float)mContentHeight);
}
+ void setViewSizeAnchor(int x, int y) {
+ mAnchorX = x;
+ mAnchorY = y;
+ }
+
static class ViewSizeData {
int mWidth;
int mHeight;
@@ -2295,16 +2177,19 @@
/**
* 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)
+ * values we sent, send them to webkit (to be used as new viewport)
+ *
+ * @param force ensures that the message is sent to webkit even if the width
+ * or height has not changed since the last message
*
* @return true if new values were sent
*/
- private boolean sendViewSizeZoom() {
- if (mPreviewZoomOnly) return false;
+ boolean sendViewSizeZoom(boolean force) {
+ if (mZoomManager.mPreviewZoomOnly) return false;
int viewWidth = getViewWidth();
- int newWidth = Math.round(viewWidth * mInvActualScale);
- int newHeight = Math.round(getViewHeight() * mInvActualScale);
+ int newWidth = Math.round(viewWidth * mZoomManager.mInvActualScale);
+ int newHeight = Math.round(getViewHeight() * mZoomManager.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
@@ -2317,13 +2202,13 @@
newHeight = 0;
}
// Avoid sending another message if the dimensions have not changed.
- if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
+ if (newWidth != mLastWidthSent || newHeight != mLastHeightSent || force) {
ViewSizeData data = new ViewSizeData();
data.mWidth = newWidth;
data.mHeight = newHeight;
- data.mTextWrapWidth = Math.round(viewWidth / mTextWrapScale);;
- data.mScale = mActualScale;
- data.mIgnoreHeight = mZoomScale != 0 && !mHeightCanMeasure;
+ data.mTextWrapWidth = Math.round(viewWidth / mZoomManager.mTextWrapScale);
+ data.mScale = mZoomManager.mActualScale;
+ data.mIgnoreHeight = mZoomManager.isZoomAnimating() && !mHeightCanMeasure;
data.mAnchorX = mAnchorX;
data.mAnchorY = mAnchorY;
mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
@@ -2340,12 +2225,12 @@
if (mDrawHistory) {
return mHistoryWidth;
} else if (mHorizontalScrollBarMode == SCROLLBAR_ALWAYSOFF
- && (mActualScale - mZoomManager.mMinZoomScale <= MINIMUM_SCALE_INCREMENT)) {
+ && mZoomManager.isZoomedOut()) {
// only honor the scrollbar mode when it is at minimum zoom level
return computeHorizontalScrollExtent();
} else {
// to avoid rounding error caused unnecessary scrollbar, use floor
- return (int) Math.floor(mContentWidth * mActualScale);
+ return (int) Math.floor(mContentWidth * mZoomManager.mActualScale);
}
}
@@ -2354,12 +2239,12 @@
if (mDrawHistory) {
return mHistoryHeight;
} else if (mVerticalScrollBarMode == SCROLLBAR_ALWAYSOFF
- && (mActualScale - mZoomManager.mMinZoomScale <= MINIMUM_SCALE_INCREMENT)) {
+ && mZoomManager.isZoomedOut()) {
// only honor the scrollbar mode when it is at minimum zoom level
return computeVerticalScrollExtent();
} else {
// to avoid rounding error caused unnecessary scrollbar, use floor
- return (int) Math.floor(mContentHeight * mActualScale);
+ return (int) Math.floor(mContentHeight * mZoomManager.mActualScale);
}
}
@@ -2960,7 +2845,7 @@
} 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();
+ sendViewSizeZoom(false);
}
}
@@ -3263,10 +3148,6 @@
}
}
- boolean inAnimateZoom() {
- return mZoomScale != 0;
- }
-
/**
* Need to adjust the WebTextView after a change in zoom, since mActualScale
* has changed. This is especially important for password fields, which are
@@ -3316,12 +3197,12 @@
private void drawCoreAndCursorRing(Canvas canvas, int color,
boolean drawCursorRing) {
if (mDrawHistory) {
- canvas.scale(mActualScale, mActualScale);
+ canvas.scale(mZoomManager.mActualScale, mZoomManager.mActualScale);
canvas.drawPicture(mHistoryPicture);
return;
}
- boolean animateZoom = mZoomScale != 0;
+ boolean animateZoom = mZoomManager.isZoomAnimating();
boolean animateScroll = ((!mScroller.isFinished()
|| mVelocityTracker != null)
&& (mTouchMode != TOUCH_DRAG_MODE ||
@@ -3341,16 +3222,16 @@
}
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);
+ int interval = (int) (SystemClock.uptimeMillis() - mZoomManager.mZoomStart);
+ if (interval < mZoomManager.ZOOM_ANIMATION_LENGTH) {
+ float ratio = (float) interval / mZoomManager.ZOOM_ANIMATION_LENGTH;
+ zoomScale = 1.0f / (mZoomManager.mInvInitialZoomScale
+ + (mZoomManager.mInvFinalZoomScale - mZoomManager.mInvInitialZoomScale) * ratio);
invalidate();
} else {
- zoomScale = mZoomScale;
+ zoomScale = mZoomManager.mZoomScale;
// set mZoomScale to be 0 as we have done animation
- mZoomScale = 0;
+ mZoomManager.mZoomScale = 0;
WebViewCore.resumeUpdatePicture(mWebViewCore);
// call invalidate() again to draw with the final filters
invalidate();
@@ -3366,22 +3247,22 @@
}
// calculate the intermediate scroll position. As we need to use
// zoomScale, we can't use pinLocX/Y directly. Copy the logic here.
- float scale = zoomScale * mInvInitialZoomScale;
- int tx = Math.round(scale * (mInitialScrollX + mZoomCenterX)
- - mZoomCenterX);
+ float scale = zoomScale * mZoomManager.mInvInitialZoomScale;
+ int tx = Math.round(scale * (mZoomManager.mInitialScrollX + mZoomManager.mZoomCenterX)
+ - mZoomManager.mZoomCenterX);
tx = -pinLoc(tx, getViewWidth(), Math.round(mContentWidth
* zoomScale)) + mScrollX;
int titleHeight = getTitleHeight();
int ty = Math.round(scale
- * (mInitialScrollY + mZoomCenterY - titleHeight)
- - (mZoomCenterY - titleHeight));
+ * (mZoomManager.mInitialScrollY + mZoomManager.mZoomCenterY - titleHeight)
+ - (mZoomManager.mZoomCenterY - titleHeight));
ty = -(ty <= titleHeight ? Math.max(ty, 0) : pinLoc(ty
- titleHeight, getViewHeight(), Math.round(mContentHeight
* zoomScale)) + titleHeight) + mScrollY;
canvas.translate(tx, ty);
canvas.scale(zoomScale, zoomScale);
if (inEditingMode() && !mNeedToAdjustWebTextView
- && mZoomScale != 0) {
+ && mZoomManager.isZoomAnimating()) {
// The WebTextView is up. Keep track of this so we can adjust
// its size and placement when we finish zooming
mNeedToAdjustWebTextView = true;
@@ -3392,7 +3273,7 @@
}
}
} else {
- canvas.scale(mActualScale, mActualScale);
+ canvas.scale(mZoomManager.mActualScale, mZoomManager.mActualScale);
}
boolean UIAnimationsRunning = false;
@@ -3405,7 +3286,7 @@
invalidate();
}
mWebViewCore.drawContentPicture(canvas, color,
- (animateZoom || mPreviewZoomOnly || UIAnimationsRunning),
+ (animateZoom || mZoomManager.mPreviewZoomOnly || UIAnimationsRunning),
animateScroll);
if (mNativeClass == 0) return;
// decide which adornments to draw
@@ -3418,10 +3299,10 @@
}
} else if (mShiftIsPressed
&& !nativePageShouldHandleShiftAndArrows()) {
- if (!animateZoom && !mPreviewZoomOnly) {
+ if (!animateZoom && !mZoomManager.mPreviewZoomOnly) {
extras = DRAW_EXTRAS_SELECTION;
nativeSetSelectionRegion(mTouchSelection || mExtendSelection);
- nativeSetSelectionPointer(!mTouchSelection, mInvActualScale,
+ nativeSetSelectionPointer(!mTouchSelection, mZoomManager.mInvActualScale,
mSelectX, mSelectY - getTitleHeight(),
mExtendSelection);
}
@@ -3535,13 +3416,11 @@
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
// bring it back to the default scale so that user can enter text
- boolean zoom = mActualScale < mDefaultScale;
+ boolean zoom = mZoomManager.mActualScale < mZoomManager.mDefaultScale;
if (zoom) {
+ mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
mZoomManager.mInZoomOverview = false;
- mZoomCenterX = mLastTouchX;
- mZoomCenterY = mLastTouchY;
- // do not change text wrap scale so that there is no reflow
- setNewZoomScale(mDefaultScale, false, false);
+ mZoomManager.setZoomScale(mZoomManager.mDefaultScale, false);
}
if (isTextView) {
rebuildWebTextView();
@@ -4213,7 +4092,7 @@
// system won't call onSizeChanged if the dimension is not changed.
// In this case, we need to call sendViewSizeZoom() explicitly to
// notify the WebKit about the new dimensions.
- sendViewSizeZoom();
+ sendViewSizeZoom(false);
}
return changed;
}
@@ -4231,8 +4110,7 @@
if (mWebView.mWebViewCore != null) {
// we always force, in case our height changed, in which case we
// still want to send the notification over to webkit.
- mWebView.setNewZoomScale(mWebView.mActualScale,
- mUpdateTextWrap, true);
+ mWebView.mZoomManager.refreshZoomScale(mUpdateTextWrap);
// update the zoom buttons as the scale can be changed
mWebView.mZoomManager.updateZoomPicker();
}
@@ -4242,13 +4120,13 @@
@Override
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.
- if (mZoomScale == 0) { // unless we're already zooming
- // To anchor at top left corner.
- mZoomCenterX = 0;
- mZoomCenterY = getVisibleTitleHeight();
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
+ // reset zoom and anchor to the top left corner of the screen
+ // unless we are already zooming
+ if (!mZoomManager.isZoomAnimating()) {
+ int visibleTitleHeight = getVisibleTitleHeight();
+ mZoomManager.setZoomCenter(0, visibleTitleHeight);
+ mAnchorX = viewToContentX(mScrollX);
+ mAnchorY = viewToContentY(visibleTitleHeight + mScrollY);
}
// adjust the max viewport width depending on the view dimensions. This
@@ -4267,7 +4145,7 @@
// the new picture shows up.
mZoomManager.mMinZoomScale = Math.min(1.0f, (float) getViewWidth()
/ (mDrawHistory ? mHistoryPicture.getWidth()
- : mZoomOverviewWidth));
+ : mZoomManager.mZoomOverviewWidth));
if (mInitialScaleInPercent > 0) {
// limit the minZoomScale to the initialScale if it is set
float initialScale = mInitialScaleInPercent / 100.0f;
@@ -4296,7 +4174,7 @@
// as getVisibleTitleHeight.
int titleHeight = getTitleHeight();
if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
- sendViewSizeZoom();
+ sendViewSizeZoom(false);
}
}
@@ -4563,18 +4441,17 @@
}
public void onScaleEnd(ScaleGestureDetector detector) {
- if (mPreviewZoomOnly) {
- mPreviewZoomOnly = false;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
+ if (mZoomManager.mPreviewZoomOnly) {
+ mZoomManager.mPreviewZoomOnly = false;
+ mAnchorX = viewToContentX((int) mZoomManager.mZoomCenterX + mScrollX);
+ mAnchorY = viewToContentY((int) mZoomManager.mZoomCenterY + mScrollY);
// don't reflow when zoom in; when zoom out, do reflow if the
// new scale is almost minimum scale;
- boolean reflowNow = (mActualScale - mZoomManager.mMinZoomScale
- <= MINIMUM_SCALE_INCREMENT)
- || ((mActualScale <= 0.8 * mTextWrapScale));
+ boolean reflowNow = mZoomManager.isZoomedOut()
+ || (mZoomManager.mActualScale <= 0.8 * mZoomManager.mTextWrapScale);
// force zoom after mPreviewZoomOnly is set to false so that the
// new view size will be passed to the WebKit
- setNewZoomScale(mActualScale, reflowNow, true);
+ mZoomManager.refreshZoomScale(reflowNow);
// call invalidate() to draw without zoom filter
invalidate();
}
@@ -4598,18 +4475,17 @@
public boolean onScale(ScaleGestureDetector detector) {
float scale = (float) (Math.round(detector.getScaleFactor()
- * mActualScale * 100) / 100.0);
- if (Math.abs(scale - mActualScale) >= MINIMUM_SCALE_INCREMENT) {
- mPreviewZoomOnly = true;
+ * mZoomManager.mActualScale * 100) / 100.0);
+ if (mZoomManager.willScaleTriggerZoom(scale)) {
+ mZoomManager.mPreviewZoomOnly = true;
// limit the scale change per step
- if (scale > mActualScale) {
- scale = Math.min(scale, mActualScale * 1.25f);
+ if (scale > mZoomManager.mActualScale) {
+ scale = Math.min(scale, mZoomManager.mActualScale * 1.25f);
} else {
- scale = Math.max(scale, mActualScale * 0.8f);
+ scale = Math.max(scale, mZoomManager.mActualScale * 0.8f);
}
- mZoomCenterX = detector.getFocusX();
- mZoomCenterY = detector.getFocusY();
- setNewZoomScale(scale, false, false);
+ mZoomManager.setZoomCenter(detector.getFocusX(), detector.getFocusY());
+ mZoomManager.setZoomScale(scale, false);
invalidate();
return true;
}
@@ -4741,7 +4617,7 @@
contentX, contentY) : false;
}
} else { // the normal case
- mPreviewZoomOnly = false;
+ mZoomManager.mPreviewZoomOnly = false;
mTouchMode = TOUCH_INIT_MODE;
mDeferTouchProcess = (!inFullScreenMode()
&& mForwardTouchEvents) ? hitFocusedPlugin(
@@ -5487,6 +5363,19 @@
- getViewHeightWithTitle(), 0);
}
+ boolean updateScrollCoordinates(int x, int y) {
+ int oldX = mScrollX;
+ int oldY = mScrollY;
+ mScrollX = x;
+ mScrollY = y;
+ if (oldX != mScrollX || oldY != mScrollY) {
+ onScrollChanged(mScrollX, mScrollY, oldX, oldY);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public void flingScroll(int vx, int vy) {
mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
computeMaxScrollY());
@@ -5560,32 +5449,6 @@
invalidate();
}
- private boolean zoomWithPreview(float scale, boolean updateTextWrapScale) {
- float oldScale = mActualScale;
- mInitialScrollX = mScrollX;
- mInitialScrollY = mScrollY;
-
- // snap to DEFAULT_SCALE if it is close
- if (Math.abs(scale - mDefaultScale) < MINIMUM_SCALE_INCREMENT) {
- scale = mDefaultScale;
- }
-
- setNewZoomScale(scale, updateTextWrapScale, false);
-
- if (oldScale != mActualScale) {
- // use mZoomPickerScale to see zoom preview first
- mZoomStart = SystemClock.uptimeMillis();
- mInvInitialZoomScale = 1.0f / oldScale;
- mInvFinalZoomScale = 1.0f / mActualScale;
- mZoomScale = mActualScale;
- WebViewCore.pauseUpdatePicture(mWebViewCore);
- invalidate();
- return true;
- } else {
- return false;
- }
- }
-
/**
* 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
@@ -5612,20 +5475,16 @@
mZoomManager.dismissZoomPicker();
}
+ float getDefaultZoomScale() {
+ return mZoomManager.mDefaultScale;
+ }
+
/**
* Perform zoom in in the webview
* @return TRUE if zoom in succeeds. FALSE if no zoom changes.
*/
public boolean zoomIn() {
- // TODO: alternatively we can disallow this during draw history mode
- switchOutDrawHistory();
- mZoomManager.mInZoomOverview = false;
- // Center zooming to the center of the screen.
- mZoomCenterX = getViewWidth() * .5f;
- mZoomCenterY = getViewHeight() * .5f;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- return zoomWithPreview(mActualScale * 1.25f, true);
+ return mZoomManager.zoomIn();
}
/**
@@ -5633,14 +5492,7 @@
* @return TRUE if zoom out succeeds. FALSE if no zoom changes.
*/
public boolean zoomOut() {
- // TODO: alternatively we can disallow this during draw history mode
- switchOutDrawHistory();
- // Center zooming to the center of the screen.
- mZoomCenterX = getViewWidth() * .5f;
- mZoomCenterY = getViewHeight() * .5f;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- return zoomWithPreview(mActualScale * 0.8f, true);
+ return mZoomManager.zoomOut();
}
private void updateSelection() {
@@ -5779,7 +5631,7 @@
} else if (scale > mZoomManager.mMaxZoomScale) {
scale = mZoomManager.mMaxZoomScale;
}
- if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
+ if (!mZoomManager.willScaleTriggerZoom(scale)) {
if (contentToViewX(view.x) >= mScrollX
&& contentToViewX(view.x + view.width) <= mScrollX
+ viewWidth
@@ -5808,12 +5660,13 @@
} else if (scale > mZoomManager.mMaxZoomScale) {
scale = mZoomManager.mMaxZoomScale;
}
- if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
+ if (!mZoomManager.willScaleTriggerZoom(scale)) {
pinScrollTo(contentToViewX(docX + docWidth / 2) - viewWidth / 2,
contentToViewY(docY + docHeight / 2) - viewHeight / 2,
true, 0);
} else {
- float oldScreenX = docX * mActualScale - mScrollX;
+ float actualScale = mZoomManager.mActualScale;
+ float oldScreenX = docX * actualScale - mScrollX;
float rectViewX = docX * scale;
float rectViewWidth = docWidth * scale;
float newMaxWidth = mContentWidth * scale;
@@ -5824,9 +5677,9 @@
} else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) {
newScreenX = viewWidth - (newMaxWidth - rectViewX);
}
- mZoomCenterX = (oldScreenX * scale - newScreenX * mActualScale)
- / (scale - mActualScale);
- float oldScreenY = docY * mActualScale + getTitleHeight()
+ float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale)
+ / (scale - actualScale);
+ float oldScreenY = docY * actualScale + getTitleHeight()
- mScrollY;
float rectViewY = docY * scale + getTitleHeight();
float rectViewHeight = docHeight * scale;
@@ -5838,9 +5691,10 @@
} else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) {
newScreenY = viewHeight - (newMaxHeight - rectViewY);
}
- mZoomCenterY = (oldScreenY * scale - newScreenY * mActualScale)
- / (scale - mActualScale);
- zoomWithPreview(scale, false);
+ float zoomCenterY = (oldScreenY * scale - newScreenY * actualScale)
+ / (scale - actualScale);
+ mZoomManager.setZoomCenter(zoomCenterX, zoomCenterY);
+ mZoomManager.animateZoom(scale, false);
}
}
@@ -5853,10 +5707,9 @@
if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
return;
}
- mZoomCenterX = mLastTouchX;
- mZoomCenterY = mLastTouchY;
- mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
- mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
+ mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
+ mAnchorX = viewToContentX((int) mLastTouchX + mScrollX);
+ mAnchorY = viewToContentY((int) mLastTouchX + mScrollY);
WebSettings settings = getSettings();
settings.setDoubleTapToastCount(0);
// remove the zoom control after double tap
@@ -5864,11 +5717,7 @@
ViewManager.ChildView plugin = mViewManager.hitTest(mAnchorX, mAnchorY);
if (plugin != null) {
if (isPluginFitOnScreen(plugin)) {
- mZoomManager.mInZoomOverview = true;
- // Force the titlebar fully reveal in overview mode
- if (mScrollY < getTitleHeight()) mScrollY = 0;
- zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth,
- true);
+ mZoomManager.zoomToOverview();
} else {
mZoomManager.mInZoomOverview = false;
centerFitRect(plugin.x, plugin.y, plugin.width, plugin.height);
@@ -5877,28 +5726,24 @@
}
boolean zoomToDefault = false;
if ((settings.getLayoutAlgorithm() == WebSettings.LayoutAlgorithm.NARROW_COLUMNS)
- && (Math.abs(mActualScale - mTextWrapScale) >= MINIMUM_SCALE_INCREMENT)) {
- setNewZoomScale(mActualScale, true, true);
- float overviewScale = (float) getViewWidth() / mZoomOverviewWidth;
- if (Math.abs(mActualScale - overviewScale) < MINIMUM_SCALE_INCREMENT) {
+ && mZoomManager.willScaleTriggerZoom(mZoomManager.mTextWrapScale)) {
+ mZoomManager.refreshZoomScale(true);
+ float overviewScale = (float) getViewWidth() / mZoomManager.mZoomOverviewWidth;
+ if (!mZoomManager.willScaleTriggerZoom(overviewScale)) {
mZoomManager.mInZoomOverview = true;
}
} else if (!mZoomManager.mInZoomOverview) {
- float newScale = (float) getViewWidth() / mZoomOverviewWidth;
- if (Math.abs(mActualScale - newScale) >= MINIMUM_SCALE_INCREMENT) {
- mZoomManager.mInZoomOverview = true;
- // Force the titlebar fully reveal in overview mode
- if (mScrollY < getTitleHeight()) mScrollY = 0;
- zoomWithPreview(newScale, true);
- } else if (Math.abs(mActualScale - mDefaultScale) >= MINIMUM_SCALE_INCREMENT) {
+ float newScale = (float) getViewWidth() / mZoomManager.mZoomOverviewWidth;
+ if (mZoomManager.willScaleTriggerZoom(newScale)) {
+ mZoomManager.zoomToOverview();
+ } else if (mZoomManager.willScaleTriggerZoom(mZoomManager.mDefaultScale)) {
zoomToDefault = true;
}
} else {
zoomToDefault = true;
}
if (zoomToDefault) {
- mZoomManager.mInZoomOverview = false;
- int left = nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
+ int left = nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mZoomManager.mActualScale);
if (left != NO_LEFTEDGE) {
// add a 5pt padding to the left edge.
int viewLeft = contentToViewX(left < 5 ? 0 : (left - 5))
@@ -5906,14 +5751,14 @@
// Re-calculate the zoom center so that the new scroll x will be
// on the left edge.
if (viewLeft > 0) {
- mZoomCenterX = viewLeft * mDefaultScale
- / (mDefaultScale - mActualScale);
+ mZoomManager.mZoomCenterX = viewLeft * mZoomManager.mDefaultScale
+ / (mZoomManager.mDefaultScale - mZoomManager.mActualScale);
} else {
scrollBy(viewLeft, 0);
- mZoomCenterX = 0;
+ mZoomManager.mZoomCenterX = 0;
}
}
- zoomWithPreview(mDefaultScale, true);
+ mZoomManager.zoomToDefaultLevel(true);
}
}
@@ -6015,6 +5860,12 @@
public boolean requestChildRectangleOnScreen(View child,
Rect rect,
boolean immediate) {
+ // don't scroll while in zoom animation. When it is done, we will adjust
+ // the necessary components (e.g., WebTextView if it is in editing mode)
+ if(mZoomManager.isZoomAnimating()) {
+ return false;
+ }
+
rect.offset(child.getLeft() - child.getScrollX(),
child.getTop() - child.getScrollY());
@@ -6248,13 +6099,13 @@
mZoomManager.mInZoomOverview = false;
if (mInitialScaleInPercent > 0) {
- setNewZoomScale(mInitialScaleInPercent / 100.0f,
- mInitialScaleInPercent != mTextWrapScale * 100,
- false);
+ final float initialScale = mInitialScaleInPercent / 100.0f;
+ final boolean reflowText =
+ mInitialScaleInPercent != mZoomManager.mTextWrapScale * 100;
+ mZoomManager.setZoomScale(initialScale, reflowText);
} else if (restoreState.mViewScale > 0) {
- mTextWrapScale = restoreState.mTextWrapScale;
- setNewZoomScale(restoreState.mViewScale, false,
- false);
+ mZoomManager.mTextWrapScale = restoreState.mTextWrapScale;
+ mZoomManager.setZoomScale(restoreState.mViewScale, false);
} else {
mZoomManager.mInZoomOverview = useWideViewport
&& settings.getLoadWithOverviewMode();
@@ -6265,9 +6116,9 @@
} else {
scale = restoreState.mTextWrapScale;
}
- setNewZoomScale(scale, Math.abs(scale
- - mTextWrapScale) >= MINIMUM_SCALE_INCREMENT,
- false);
+ mZoomManager.setZoomScale(scale,
+ ZoomManager.exceedsMinScaleIncrement(
+ mZoomManager.mTextWrapScale, scale));
}
setContentScrollTo(restoreState.mScrollX,
restoreState.mScrollY);
@@ -6302,23 +6153,23 @@
// sMaxViewportWidth so that if the page doesn't behave
// well, the WebView won't go insane. limit the lower
// bound to match the default scale for mobile sites.
- mZoomOverviewWidth = Math.min(sMaxViewportWidth, Math
- .max((int) (viewWidth / mDefaultScale), Math
- .max(draw.mMinPrefWidth,
+ mZoomManager.mZoomOverviewWidth = Math.min(sMaxViewportWidth, Math
+ .max((int) (viewWidth / mZoomManager.mDefaultScale),
+ Math.max(draw.mMinPrefWidth,
draw.mViewPoint.x)));
}
if (!mZoomManager.mMinZoomScaleFixed) {
- mZoomManager.mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
+ mZoomManager.mMinZoomScale = (float) viewWidth /
+ mZoomManager.mZoomOverviewWidth;
}
if (!mDrawHistory && mZoomManager.mInZoomOverview) {
// fit the content width to the current view. Ignore
// the rounding error case.
- if (Math.abs((viewWidth * mInvActualScale)
- - mZoomOverviewWidth) > 1) {
- setNewZoomScale((float) viewWidth
- / mZoomOverviewWidth, Math.abs(mActualScale
- - mTextWrapScale) < MINIMUM_SCALE_INCREMENT,
- false);
+ if (Math.abs((viewWidth * mZoomManager.mInvActualScale)
+ - mZoomManager.mZoomOverviewWidth) > 1) {
+ mZoomManager.setZoomScale(
+ (float) viewWidth / mZoomManager.mZoomOverviewWidth,
+ !mZoomManager.willScaleTriggerZoom(mZoomManager.mTextWrapScale));
}
}
if (draw.mFocusSizeChanged && inEditingMode()) {
@@ -7075,7 +6926,7 @@
// 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 Math.round(height * mInvActualScale);
+ return Math.round(height * mZoomManager.mInvActualScale);
}
/**
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 974fcaaa..bb75cc7 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2064,8 +2064,10 @@
// adjust the default scale to match the densityDpi
float adjust = 1.0f;
if (mViewportDensityDpi == -1) {
- if (WebView.DEFAULT_SCALE_PERCENT != 100) {
- adjust = WebView.DEFAULT_SCALE_PERCENT / 100.0f;
+ // convert default zoom scale to a integer (percentage) to avoid any
+ // issues with floating point comparisons
+ if (mWebView != null && (int)(mWebView.getDefaultZoomScale() * 100) != 100) {
+ adjust = mWebView.getDefaultZoomScale();
}
} else if (mViewportDensityDpi > 0) {
adjust = (float) mContext.getResources().getDisplayMetrics().densityDpi
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 8ec771f..af521be 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.os.SystemClock;
import android.view.View;
class ZoomManager {
@@ -23,6 +24,7 @@
static final String LOGTAG = "webviewZoom";
private final WebView mWebView;
+ private final CallbackProxy mCallbackProxy;
// manages the on-screen zoom functions of the WebView
private ZoomControlEmbedded mEmbeddedZoomControl;
@@ -51,15 +53,219 @@
// the last zoom scale.
boolean mInZoomOverview = false;
- public ZoomManager(WebView webView) {
+ // These keep track of the center point of the zoom. They are used to
+ // determine the point around which we should zoom.
+ float mZoomCenterX;
+ float mZoomCenterY;
+
+ // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
+ // engadget always have wider mContentWidth no matter what viewport size is.
+ int mZoomOverviewWidth = WebView.DEFAULT_VIEWPORT_WIDTH;
+ float mTextWrapScale;
+
+ // the default zoom scale. This value will is initially set based on the
+ // display density, but can be changed at any time via the WebSettings.
+ float mDefaultScale;
+
+ private static float MINIMUM_SCALE_INCREMENT = 0.01f;
+
+ // set to true temporarily during ScaleGesture triggered zoom
+ boolean mPreviewZoomOnly = false;
+
+ // the current computed zoom scale and its inverse.
+ float mActualScale;
+ float mInvActualScale;
+ // if this is non-zero, it is used on drawing rather than mActualScale
+ float mZoomScale;
+ float mInvInitialZoomScale;
+ float mInvFinalZoomScale;
+ int mInitialScrollX;
+ int mInitialScrollY;
+ long mZoomStart;
+ static final int ZOOM_ANIMATION_LENGTH = 500;
+
+ public ZoomManager(WebView webView, CallbackProxy callbackProxy) {
mWebView = webView;
+ mCallbackProxy = callbackProxy;
}
public void init(float density) {
- DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
- DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
+ setDefaultZoomScale(density);
mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mActualScale = density;
+ mInvActualScale = 1 / density;
+ mTextWrapScale = density;
+ }
+
+ public void updateDefaultZoomDensity(float density) {
+ if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
+ float scaleFactor = density / mDefaultScale;
+ // set the new default density
+ setDefaultZoomScale(density);
+ // adjust the limits
+ mMaxZoomScale *= scaleFactor;
+ mMinZoomScale *= scaleFactor;
+ setZoomScale(mActualScale * scaleFactor, true);
+ }
+ }
+
+ private void setDefaultZoomScale(float defaultScale) {
+ mDefaultScale = defaultScale;
+ DEFAULT_MAX_ZOOM_SCALE = 4.0f * defaultScale;
+ DEFAULT_MIN_ZOOM_SCALE = 0.25f * defaultScale;
+ }
+
+ public void setZoomCenter(float x, float y) {
+ mZoomCenterX = x;
+ mZoomCenterY = y;
+ }
+
+ public static final boolean exceedsMinScaleIncrement(float scaleA, float scaleB) {
+ return Math.abs(scaleA - scaleB) >= MINIMUM_SCALE_INCREMENT;
+ }
+
+ public boolean willScaleTriggerZoom(float scale) {
+ return exceedsMinScaleIncrement(scale, mActualScale);
+ }
+
+ public boolean isZoomedOut() {
+ return mActualScale - mMinZoomScale <= MINIMUM_SCALE_INCREMENT;
+ }
+
+ public boolean isZoomAnimating() {
+ return mZoomScale != 0;
+ }
+
+ public boolean zoomIn() {
+ mInZoomOverview = false;
+ return zoom(1.25f);
+ }
+
+ public boolean zoomOut() {
+ return zoom(0.8f);
+ }
+
+ // returns TRUE if zoom out succeeds and FALSE if no zoom changes.
+ private boolean zoom(float zoomMultiplier) {
+ // TODO: alternatively we can disallow this during draw history mode
+ mWebView.switchOutDrawHistory();
+ // Center zooming to the center of the screen.
+ mZoomCenterX = mWebView.getViewWidth() * .5f;
+ mZoomCenterY = mWebView.getViewHeight() * .5f;
+ int anchorX = mWebView.viewToContentX((int) mZoomCenterX + mWebView.getScrollX());
+ int anchorY = mWebView.viewToContentY((int) mZoomCenterY + mWebView.getScrollY());
+ mWebView.setViewSizeAnchor(anchorX, anchorY);
+ return animateZoom(mActualScale * zoomMultiplier, true);
+ }
+
+ public void zoomToOverview() {
+ mInZoomOverview = true;
+ // Force the titlebar fully reveal in overview mode
+ int scrollY = mWebView.getScrollY();
+ if (scrollY < mWebView.getTitleHeight()) {
+ mWebView.updateScrollCoordinates(mWebView.getScrollX(), 0);
+ }
+ animateZoom((float) mWebView.getViewWidth() / mZoomOverviewWidth, true);
+ }
+
+ public void zoomToDefaultLevel(boolean reflowText) {
+ mInZoomOverview = false;
+ animateZoom(mDefaultScale, reflowText);
+ }
+
+ public boolean animateZoom(float scale, boolean reflowText) {
+ float oldScale = mActualScale;
+ mInitialScrollX = mWebView.getScrollX();
+ mInitialScrollY = mWebView.getScrollY();
+
+ // snap to DEFAULT_SCALE if it is close
+ if (!exceedsMinScaleIncrement(scale, mDefaultScale)) {
+ scale = mDefaultScale;
+ }
+
+ setZoomScale(scale, reflowText);
+
+ if (oldScale != mActualScale) {
+ // use mZoomPickerScale to see zoom preview first
+ mZoomStart = SystemClock.uptimeMillis();
+ mInvInitialZoomScale = 1.0f / oldScale;
+ mInvFinalZoomScale = 1.0f / mActualScale;
+ mZoomScale = mActualScale;
+ WebViewCore.pauseUpdatePicture(mWebView.getWebViewCore());
+ mWebView.invalidate();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void refreshZoomScale(boolean reflowText) {
+ setZoomScale(mActualScale, reflowText, true);
+ }
+
+ public void setZoomScale(float scale, boolean reflowText) {
+ setZoomScale(scale, reflowText, false);
+ }
+
+ private void setZoomScale(float scale, boolean reflowText, boolean force) {
+ if (scale < mMinZoomScale) {
+ scale = mMinZoomScale;
+ // set mInZoomOverview for non mobile sites
+ if (scale < mDefaultScale) {
+ mInZoomOverview = true;
+ }
+ } else if (scale > mMaxZoomScale) {
+ scale = mMaxZoomScale;
+ }
+
+ if (reflowText) {
+ mTextWrapScale = scale;
+ }
+
+ if (scale != mActualScale || force) {
+ float oldScale = mActualScale;
+ float oldInvScale = mInvActualScale;
+
+ if (scale != mActualScale && !mPreviewZoomOnly) {
+ mCallbackProxy.onScaleChanged(mActualScale, scale);
+ }
+
+ mActualScale = scale;
+ mInvActualScale = 1 / scale;
+
+ if (!mWebView.drawHistory()) {
+
+ // If history Picture is drawn, don't update scroll. They will
+ // be updated when we get out of that mode.
+ // 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 = mWebView.getScrollX();
+ int oldY = mWebView.getScrollY();
+ float ratio = scale * oldInvScale;
+ float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
+ float sy = ratio * oldY + (ratio - 1)
+ * (mZoomCenterY - mWebView.getTitleHeight());
+
+ // Scale all the child views
+ mWebView.mViewManager.scaleAll();
+
+ // as we don't have animation for scaling, don't do animation
+ // for scrolling, as it causes weird intermediate state
+ int scrollX = mWebView.pinLocX(Math.round(sx));
+ int scrollY = mWebView.pinLocY(Math.round(sy));
+ if(!mWebView.updateScrollCoordinates(scrollX, scrollY)) {
+ // the scroll position is adjusted at the beginning of the
+ // zoom animation. But we want to update the WebKit at the
+ // end of the zoom animation. See comments in onScaleEnd().
+ mWebView.sendOurVisibleRect();
+ }
+ }
+
+ // if the we need to reflow the text then force the VIEW_SIZE_CHANGED
+ // event to be sent to WebKit
+ mWebView.sendViewSizeZoom(reflowText);
+ }
}
private ZoomControlBase getCurrentZoomControl() {
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp
index 381a958..549d661 100644
--- a/libs/audioflinger/AudioPolicyManagerBase.cpp
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -902,7 +902,8 @@
#ifdef AUDIO_POLICY_TEST
Thread(false),
#endif //AUDIO_POLICY_TEST
- mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false)
+ mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false),
+ mLastVoiceVolume(-1.0f)
{
mpClientInterface = clientInterface;
@@ -1713,29 +1714,38 @@
}
float volume = computeVolume(stream, index, output, device);
- // do not set volume if the float value did not change
- if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || force) {
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+ force) {
mOutputs.valueFor(output)->mCurVolume[stream] = volume;
LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::DTMF ||
stream == AudioSystem::BLUETOOTH_SCO) {
- float voiceVolume = -1.0;
// offset value to reflect actual hardware volume that never reaches 0
// 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
volume = 0.01 + 0.99 * volume;
- if (stream == AudioSystem::VOICE_CALL) {
- voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
- } else if (stream == AudioSystem::BLUETOOTH_SCO) {
- voiceVolume = 1.0;
- }
- if (voiceVolume >= 0 && output == mHardwareOutput) {
- mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
- }
}
mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
}
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume;
+ // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else {
+ voiceVolume = 1.0;
+ }
+ if (voiceVolume != mLastVoiceVolume && output == mHardwareOutput) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+ }
+
return NO_ERROR;
}
diff --git a/media/libeffects/EffectEqualizer.cpp b/media/libeffects/EffectEqualizer.cpp
index 3a5da4d..c08f4f5 100644
--- a/media/libeffects/EffectEqualizer.cpp
+++ b/media/libeffects/EffectEqualizer.cpp
@@ -20,6 +20,7 @@
#include <cutils/log.h>
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include <new>
#include "AudioEqualizer.h"
#include "AudioBiquadFilter.h"
diff --git a/media/libeffects/EffectsFactory.c b/media/libeffects/EffectsFactory.c
index 07c4d80..35a10010 100644
--- a/media/libeffects/EffectsFactory.c
+++ b/media/libeffects/EffectsFactory.c
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0
#include "EffectsFactory.h"
+#include <string.h>
+#include <stdlib.h>
#include <dlfcn.h>
@@ -277,7 +279,7 @@
if (ret < 0) {
return ret;
}
- if (libPath == NULL || strnlen(libPath, PATH_MAX) >= PATH_MAX) {
+ if (libPath == NULL) {
return -EINVAL;
}
return loadLibrary(libPath, handle);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index d0d1b14..bd16db9 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -78,6 +78,8 @@
void init();
+ sp<MetaData> getFileMetaData() { return mFileMeta; }
+
private:
struct Page {
uint64_t mGranulePosition;
@@ -100,6 +102,7 @@
vorbis_comment mVc;
sp<MetaData> mMeta;
+ sp<MetaData> mFileMeta;
ssize_t readPage(off_t offset, Page *page);
status_t findNextPage(off_t startOffset, off_t *pageOffset);
@@ -107,6 +110,9 @@
void verifyHeader(
MediaBuffer *buffer, uint8_t type);
+ void parseFileMetaData();
+ void extractAlbumArt(const void *data, size_t size);
+
MyVorbisExtractor(const MyVorbisExtractor &);
MyVorbisExtractor &operator=(const MyVorbisExtractor &);
};
@@ -188,9 +194,14 @@
mNextLaceIndex(0),
mFirstDataOffset(-1) {
mCurrentPage.mNumSegments = 0;
+
+ vorbis_info_init(&mVi);
+ vorbis_comment_init(&mVc);
}
MyVorbisExtractor::~MyVorbisExtractor() {
+ vorbis_comment_clear(&mVc);
+ vorbis_info_clear(&mVi);
}
sp<MetaData> MyVorbisExtractor::getFormat() const {
@@ -305,7 +316,7 @@
tmp.append(x);
}
- LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
+ // LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
return sizeof(header) + page->mNumSegments + totalSize;
}
@@ -422,10 +433,6 @@
}
void MyVorbisExtractor::init() {
- vorbis_info_init(&mVi);
-
- vorbis_comment mVc;
-
mMeta = new MetaData;
mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
@@ -509,6 +516,8 @@
case 3:
{
CHECK_EQ(0, _vorbis_unpack_comment(&mVc, &bits));
+
+ parseFileMetaData();
break;
}
@@ -530,6 +539,192 @@
return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
}
+void MyVorbisExtractor::parseFileMetaData() {
+ mFileMeta = new MetaData;
+ mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+
+ struct {
+ const char *const mTag;
+ uint32_t mKey;
+ } kMap[] = {
+ { "TITLE", kKeyTitle },
+ { "ARTIST", kKeyArtist },
+ { "ALBUM", kKeyAlbum },
+ { "COMPOSER", kKeyComposer },
+ { "GENRE", kKeyGenre },
+ { "AUTHOR", kKeyAuthor },
+ { "TRACKNUMBER", kKeyCDTrackNumber },
+ { "DISCNUMBER", kKeyDiscNumber },
+ { "DATE", kKeyDate },
+ { "LYRICIST", kKeyWriter },
+ { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
+ };
+
+ for (int i = 0; i < mVc.comments; ++i) {
+ const char *comment = mVc.user_comments[i];
+
+ for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+ size_t tagLen = strlen(kMap[j].mTag);
+ if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+ && comment[tagLen] == '=') {
+ if (kMap[j].mKey == kKeyAlbumArt) {
+ extractAlbumArt(
+ &comment[tagLen + 1],
+ mVc.comment_lengths[i] - tagLen - 1);
+ } else {
+ mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
+ }
+ }
+ }
+
+ }
+
+#if 0
+ for (int i = 0; i < mVc.comments; ++i) {
+ LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
+ }
+#endif
+}
+
+// The returned buffer should be free()d.
+static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
+ *outSize = 0;
+
+ if ((size % 4) != 0) {
+ return NULL;
+ }
+
+ size_t n = size;
+ size_t padding = 0;
+ if (n >= 1 && s[n - 1] == '=') {
+ padding = 1;
+
+ if (n >= 2 && s[n - 2] == '=') {
+ padding = 2;
+ }
+ }
+
+ size_t outLen = 3 * size / 4 - padding;
+
+ *outSize = outLen;
+
+ void *buffer = malloc(outLen);
+
+ uint8_t *out = (uint8_t *)buffer;
+ size_t j = 0;
+ uint32_t accum = 0;
+ for (size_t i = 0; i < n; ++i) {
+ char c = s[i];
+ unsigned value;
+ if (c >= 'A' && c <= 'Z') {
+ value = c - 'A';
+ } else if (c >= 'a' && c <= 'z') {
+ value = 26 + c - 'a';
+ } else if (c >= '0' && c <= '9') {
+ value = 52 + c - '0';
+ } else if (c == '+') {
+ value = 62;
+ } else if (c == '/') {
+ value = 63;
+ } else if (c != '=') {
+ return NULL;
+ } else {
+ if (i < n - padding) {
+ return NULL;
+ }
+
+ value = 0;
+ }
+
+ accum = (accum << 6) | value;
+
+ if (((i + 1) % 4) == 0) {
+ out[j++] = (accum >> 16);
+
+ if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
+ if (j < outLen) { out[j++] = accum & 0xff; }
+
+ accum = 0;
+ }
+ }
+
+ return (uint8_t *)buffer;
+}
+
+void MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) {
+ LOGV("extractAlbumArt from '%s'", (const char *)data);
+
+ size_t flacSize;
+ uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
+
+ if (flac == NULL) {
+ LOGE("malformed base64 encoded data.");
+ return;
+ }
+
+ LOGV("got flac of size %d", flacSize);
+
+ uint32_t picType;
+ uint32_t typeLen;
+ uint32_t descLen;
+ uint32_t dataLen;
+ char type[128];
+
+ if (flacSize < 8) {
+ goto exit;
+ }
+
+ picType = U32_AT(flac);
+
+ if (picType != 3) {
+ // This is not a front cover.
+ goto exit;
+ }
+
+ typeLen = U32_AT(&flac[4]);
+ if (typeLen + 1 > sizeof(type)) {
+ goto exit;
+ }
+
+ if (flacSize < 8 + typeLen) {
+ goto exit;
+ }
+
+ memcpy(type, &flac[8], typeLen);
+ type[typeLen] = '\0';
+
+ LOGV("picType = %d, type = '%s'", picType, type);
+
+ if (!strcmp(type, "-->")) {
+ // This is not inline cover art, but an external url instead.
+ goto exit;
+ }
+
+ descLen = U32_AT(&flac[8 + typeLen]);
+
+ if (flacSize < 32 + typeLen + descLen) {
+ goto exit;
+ }
+
+ dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+ if (flacSize < 32 + typeLen + descLen + dataLen) {
+ goto exit;
+ }
+
+ LOGV("got image data, %d trailing bytes",
+ flacSize - 32 - typeLen - descLen - dataLen);
+
+ mFileMeta->setData(
+ kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+ mFileMeta->setCString(kKeyAlbumArtMIME, type);
+
+exit:
+ free(flac);
+ flac = NULL;
+}
+
////////////////////////////////////////////////////////////////////////////////
OggExtractor::OggExtractor(const sp<DataSource> &source)
@@ -570,15 +765,7 @@
}
sp<MetaData> OggExtractor::getMetaData() {
- sp<MetaData> meta = new MetaData;
-
- if (mInitCheck != OK) {
- return meta;
- }
-
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
-
- return meta;
+ return mImpl->getFileMetaData();
}
bool SniffOgg(
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index ab17b04..2829638 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -26,10 +26,6 @@
// Sonivox includes
#include <libsonivox/eas.h>
-// Ogg Vorbis includes
-#include <Tremolo/ivorbiscodec.h>
-#include <Tremolo/ivorbisfile.h>
-
namespace android {
StagefrightMediaScanner::StagefrightMediaScanner()
@@ -103,48 +99,6 @@
return OK;
}
-static status_t HandleOGG(
- const char *filename, MediaScannerClient *client) {
- int duration;
-
- FILE *file = fopen(filename,"r");
- if (!file)
- return UNKNOWN_ERROR;
-
- OggVorbis_File vf;
- if (ov_open(file, &vf, NULL, 0) < 0) {
- return UNKNOWN_ERROR;
- }
-
- char **ptr=ov_comment(&vf,-1)->user_comments;
- while(*ptr){
- char *val = strstr(*ptr, "=");
- if (val) {
- int keylen = val++ - *ptr;
- char key[keylen + 1];
- strncpy(key, *ptr, keylen);
- key[keylen] = 0;
- if (!client->addStringTag(key, val)) goto failure;
- }
- ++ptr;
- }
-
- // Duration
- duration = ov_time_total(&vf, -1);
- if (duration > 0) {
- char buffer[20];
- sprintf(buffer, "%d", duration);
- if (!client->addStringTag("duration", buffer)) goto failure;
- }
-
- ov_clear(&vf); // this also closes the FILE
- return OK;
-
-failure:
- ov_clear(&vf); // this also closes the FILE
- return UNKNOWN_ERROR;
-}
-
status_t StagefrightMediaScanner::processFile(
const char *path, const char *mimeType,
MediaScannerClient &client) {
@@ -176,10 +130,6 @@
return HandleMIDI(path, &client);
}
- if (!strcasecmp(extension, ".ogg")) {
- return HandleOGG(path, &client);
- }
-
if (mRetriever->setDataSource(path) == OK
&& mRetriever->setMode(
METADATA_MODE_METADATA_RETRIEVAL_ONLY) == OK) {
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 197ccf8..339a7b5 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -121,6 +121,29 @@
}
}
+struct BlockIterator {
+ BlockIterator(mkvparser::Segment *segment, unsigned long trackNum);
+
+ bool eos() const;
+
+ void advance();
+ void reset();
+ void seek(int64_t seekTimeUs);
+
+ const mkvparser::Block *block() const;
+ int64_t blockTimeUs() const;
+
+private:
+ mkvparser::Segment *mSegment;
+ unsigned long mTrackNum;
+
+ mkvparser::Cluster *mCluster;
+ const mkvparser::BlockEntry *mBlockEntry;
+
+ BlockIterator(const BlockIterator &);
+ BlockIterator &operator=(const BlockIterator &);
+};
+
struct MatroskaSource : public MediaSource {
MatroskaSource(
const sp<MatroskaExtractor> &extractor, size_t index);
@@ -142,10 +165,8 @@
sp<MatroskaExtractor> mExtractor;
size_t mTrackIndex;
- unsigned long mTrackNum;
Type mType;
- mkvparser::Cluster *mCluster;
- const mkvparser::BlockEntry *mBlockEntry;
+ BlockIterator mBlockIter;
status_t advance();
@@ -158,10 +179,8 @@
: mExtractor(extractor),
mTrackIndex(index),
mType(OTHER),
- mCluster(NULL),
- mBlockEntry(NULL) {
- mTrackNum = mExtractor->mTracks.itemAt(index).mTrackNum;
-
+ mBlockIter(mExtractor->mSegment,
+ mExtractor->mTracks.itemAt(index).mTrackNum) {
const char *mime;
CHECK(mExtractor->mTracks.itemAt(index).mMeta->
findCString(kKeyMIMEType, &mime));
@@ -174,8 +193,7 @@
}
status_t MatroskaSource::start(MetaData *params) {
- mCluster = NULL;
- mBlockEntry = NULL;
+ mBlockIter.reset();
return OK;
}
@@ -188,60 +206,95 @@
return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
}
-status_t MatroskaSource::advance() {
- for (;;) {
- if (mBlockEntry == NULL || mBlockEntry->EOS()) {
- if (mCluster == NULL) {
- mCluster = mExtractor->mSegment->GetFirst();
- } else {
- mCluster = mExtractor->mSegment->GetNext(mCluster);
+////////////////////////////////////////////////////////////////////////////////
+
+BlockIterator::BlockIterator(
+ mkvparser::Segment *segment, unsigned long trackNum)
+ : mSegment(segment),
+ mTrackNum(trackNum),
+ mCluster(NULL),
+ mBlockEntry(NULL) {
+ reset();
+}
+
+bool BlockIterator::eos() const {
+ return mCluster == NULL || mCluster->EOS();
+}
+
+void BlockIterator::advance() {
+ while (!eos()) {
+ if (mBlockEntry != NULL) {
+ mBlockEntry = mCluster->GetNext(mBlockEntry);
+ } else if (mCluster != NULL) {
+ mCluster = mSegment->GetNext(mCluster);
+
+ if (eos()) {
+ break;
}
- if (mCluster == NULL || mCluster->EOS()) {
- return ERROR_END_OF_STREAM;
- }
+
mBlockEntry = mCluster->GetFirst();
}
- if (mBlockEntry->GetBlock()->GetTrackNumber() != mTrackNum) {
- mBlockEntry = mCluster->GetNext(mBlockEntry);
- continue;
+ if (mBlockEntry != NULL
+ && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
+ break;
}
+ }
+}
- break;
+void BlockIterator::reset() {
+ mCluster = mSegment->GetFirst();
+ mBlockEntry = mCluster->GetFirst();
+
+ while (!eos() && block()->GetTrackNumber() != mTrackNum) {
+ advance();
+ }
+}
+
+void BlockIterator::seek(int64_t seekTimeUs) {
+ mCluster = mSegment->GetCluster(seekTimeUs * 1000ll);
+ mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL;
+
+ while (!eos() && block()->GetTrackNumber() != mTrackNum) {
+ advance();
}
- return OK;
+ while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
+ advance();
+ }
}
+const mkvparser::Block *BlockIterator::block() const {
+ CHECK(!eos());
+
+ return mBlockEntry->GetBlock();
+}
+
+int64_t BlockIterator::blockTimeUs() const {
+ return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
status_t MatroskaSource::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
- mBlockEntry = NULL;
- mCluster = mExtractor->mSegment->GetCluster(seekTimeUs * 1000ll);
-
- status_t err;
- while ((err = advance()) == OK && !mBlockEntry->GetBlock()->IsKey()) {
- mBlockEntry = mCluster->GetNext(mBlockEntry);
- }
-
- if (err != OK) {
- return ERROR_END_OF_STREAM;
- }
+ mBlockIter.seek(seekTimeUs);
}
- if (advance() != OK) {
+ if (mBlockIter.eos()) {
return ERROR_END_OF_STREAM;
}
- const mkvparser::Block *block = mBlockEntry->GetBlock();
+ const mkvparser::Block *block = mBlockIter.block();
size_t size = block->GetSize();
- long long timeNs = block->GetTime(mCluster);
+ int64_t timeUs = mBlockIter.blockTimeUs();
MediaBuffer *buffer = new MediaBuffer(size + 2);
- buffer->meta_data()->setInt64(kKeyTime, (timeNs + 500) / 1000);
+ buffer->meta_data()->setInt64(kKeyTime, timeUs);
long res = block->Read(
mExtractor->mReader, (unsigned char *)buffer->data() + 2);
@@ -280,7 +333,7 @@
buffer->range_length());
#endif
- mBlockEntry = mCluster->GetNext(mBlockEntry);
+ mBlockIter.advance();
return OK;
}
@@ -290,7 +343,8 @@
MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
: mDataSource(source),
mReader(new DataSourceReader(mDataSource)),
- mSegment(NULL) {
+ mSegment(NULL),
+ mExtractedThumbnails(false) {
mkvparser::EBMLHeader ebmlHeader;
long long pos;
if (ebmlHeader.Parse(mReader, pos) < 0) {
@@ -342,6 +396,11 @@
return NULL;
}
+ if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) {
+ findThumbnails();
+ mExtractedThumbnails = true;
+ }
+
return mTracks.itemAt(index).mMeta;
}
@@ -479,6 +538,37 @@
}
}
+void MatroskaExtractor::findThumbnails() {
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ TrackInfo *info = &mTracks.editItemAt(i);
+
+ const char *mime;
+ CHECK(info->mMeta->findCString(kKeyMIMEType, &mime));
+
+ if (strncasecmp(mime, "video/", 6)) {
+ continue;
+ }
+
+ BlockIterator iter(mSegment, info->mTrackNum);
+ int32_t i = 0;
+ int64_t thumbnailTimeUs = 0;
+ size_t maxBlockSize = 0;
+ while (!iter.eos() && i < 20) {
+ if (iter.block()->IsKey()) {
+ ++i;
+
+ size_t blockSize = iter.block()->GetSize();
+ if (blockSize > maxBlockSize) {
+ maxBlockSize = blockSize;
+ thumbnailTimeUs = iter.blockTimeUs();
+ }
+ }
+ iter.advance();
+ }
+ info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+ }
+}
+
sp<MetaData> MatroskaExtractor::getMetaData() {
sp<MetaData> meta = new MetaData;
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 7bf41a9..7471848 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -59,8 +59,10 @@
sp<DataSource> mDataSource;
DataSourceReader *mReader;
mkvparser::Segment *mSegment;
+ bool mExtractedThumbnails;
void addTracks();
+ void findThumbnails();
MatroskaExtractor(const MatroskaExtractor &);
MatroskaExtractor &operator=(const MatroskaExtractor &);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 599023c..a497b72 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -9549,7 +9549,8 @@
* Update media status on PackageManager.
*/
public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
throw new SecurityException("Media status can only be updated by the system");
}
synchronized (mPackages) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2328717..7a1587b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -239,9 +239,11 @@
String getCdmaEriText();
/**
- * Returns true if CDMA provisioning needs to run.
+ * Returns true if OTA service provisioning needs to run.
+ * Only relevant on some technologies, others will always
+ * return false.
*/
- boolean getCdmaNeedsProvisioning();
+ boolean needsOtaServiceProvisioning();
/**
* Returns the unread count of voicemails
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 23325f6..8ff38d9 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1533,6 +1533,11 @@
boolean isOtaSpNumber(String dialStr);
/**
+ * Returns true if OTA Service Provisioning needs to be performed.
+ */
+ boolean needsOtaServiceProvisioning();
+
+ /**
* Register for notifications when CDMA call waiting comes
*
* @param h Handler that receives the notification message.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 74601e6..fbb658a 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -824,9 +824,19 @@
logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady");
}
+ /**
+ * Returns true if OTA Service Provisioning needs to be performed.
+ * If not overridden return false.
+ */
+ public boolean needsOtaServiceProvisioning() {
+ return false;
+ }
+
+ /**
+ * Return true if number is an OTASP number.
+ * If not overridden return false.
+ */
public boolean isOtaSpNumber(String dialStr) {
- // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
- logUnexpectedCdmaMethodCall("isOtaSpNumber");
return false;
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index e1511e6..8c2a661 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -764,6 +764,10 @@
mActivePhone.exitEmergencyCallbackMode();
}
+ public boolean needsOtaServiceProvisioning(){
+ return mActivePhone.needsOtaServiceProvisioning();
+ }
+
public boolean isOtaSpNumber(String dialStr){
return mActivePhone.isOtaSpNumber(dialStr);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 0c591e4..8934037 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -867,26 +867,6 @@
mRuimRecords.setVoiceMessageWaiting(1, mwi);
}
- /**
- * Returns true if CDMA OTA Service Provisioning needs to be performed.
- */
- /* package */ boolean
- needsOtaServiceProvisioning() {
- String cdmaMin = getCdmaMin();
- boolean needsProvisioning;
- if (cdmaMin == null || (cdmaMin.length() < 6)) {
- if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
- + cdmaMin + "' assume provisioning needed.");
- needsProvisioning = true;
- } else {
- needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
- || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
- || SystemProperties.getBoolean("test_cdma_setup", false);
- }
- if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
- return needsProvisioning;
- }
-
@Override
public void exitEmergencyCallbackMode() {
if (mWakeLock.isHeld()) {
@@ -1180,6 +1160,26 @@
mSMS.setCellBroadcastConfig(configValuesArray, response);
}
+ /**
+ * Returns true if OTA Service Provisioning needs to be performed.
+ */
+ @Override
+ public boolean needsOtaServiceProvisioning() {
+ String cdmaMin = getCdmaMin();
+ boolean needsProvisioning;
+ if (cdmaMin == null || (cdmaMin.length() < 6)) {
+ if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
+ + cdmaMin + "' assume provisioning needed.");
+ needsProvisioning = true;
+ } else {
+ needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
+ || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
+ || SystemProperties.getBoolean("test_cdma_setup", false);
+ }
+ if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
+ return needsProvisioning;
+ }
+
private static final String IS683A_FEATURE_CODE = "*228";
private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;