Merge "Do not send the not-modified response when validating the cache."
diff --git a/common/java/com/android/common/speech/Recognition.java b/common/java/com/android/common/speech/Recognition.java
index a79a19b..1970179 100644
--- a/common/java/com/android/common/speech/Recognition.java
+++ b/common/java/com/android/common/speech/Recognition.java
@@ -55,6 +55,7 @@
public static final int HINT_CONTEXT_UNKNOWN = 0;
public static final int HINT_CONTEXT_VOICE_SEARCH_HELP = 1;
public static final int HINT_CONTEXT_CAR_HOME = 2;
+ public static final int HINT_CONTEXT_LAUNCHER = 3;
private Recognition() { } // don't instantiate
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7c49bb7..b0a59c7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -39,6 +39,7 @@
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDebug;
+import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Bundle;
@@ -1441,6 +1442,7 @@
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%17s %8d";
private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
+ private static final String DB_INFO_FORMAT = " %8d %8d %10d %s";
// Formatting for checkin service - update version if row format changes
private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
@@ -1760,8 +1762,7 @@
int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
int openSslSocketCount = OpenSSLSocketImpl.getInstanceCount();
long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
- SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
- SQLiteDebug.getPagerStats(stats);
+ SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
// Check to see if we were called by checkin server. If so, print terse format.
boolean doCheckinFormat = false;
@@ -1835,10 +1836,15 @@
// SQL
pw.print(sqliteAllocated); pw.print(',');
- pw.print(stats.databaseBytes / 1024); pw.print(',');
- pw.print(stats.numPagers); pw.print(',');
- pw.print((stats.totalBytes - stats.referencedBytes) / 1024); pw.print(',');
- pw.print(stats.referencedBytes / 1024); pw.print('\n');
+ pw.print(stats.memoryUsed / 1024); pw.print(',');
+ pw.print(stats.pageCacheOverflo / 1024); pw.print(',');
+ pw.print(stats.largestMemAlloc / 1024); pw.print(',');
+ for (int i = 0; i < stats.dbStats.size(); i++) {
+ DbStats dbStats = stats.dbStats.get(i);
+ printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
+ dbStats.lookaside, dbStats.dbName);
+ pw.print(',');
+ }
return;
}
@@ -1879,11 +1885,21 @@
// SQLite mem info
pw.println(" ");
pw.println(" SQL");
- printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "dbFiles:",
- stats.databaseBytes / 1024);
- printRow(pw, TWO_COUNT_COLUMNS, "numPagers:", stats.numPagers, "inactivePageKB:",
- (stats.totalBytes - stats.referencedBytes) / 1024);
- printRow(pw, ONE_COUNT_COLUMN, "activePageKB:", stats.referencedBytes / 1024);
+ printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "memoryUsed:",
+ stats.memoryUsed / 1024);
+ printRow(pw, TWO_COUNT_COLUMNS, "pageCacheOverflo:", stats.pageCacheOverflo / 1024,
+ "largestMemAlloc:", stats.largestMemAlloc / 1024);
+ pw.println(" ");
+ int N = stats.dbStats.size();
+ if (N > 0) {
+ pw.println(" DATABASES");
+ printRow(pw, " %8s %8s %10s %s", "Pagesize", "Dbsize", "Lookaside", "Dbname");
+ for (int i = 0; i < N; i++) {
+ DbStats dbStats = stats.dbStats.get(i);
+ printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
+ dbStats.lookaside, dbStats.dbName);
+ }
+ }
// Asset details.
String assetAlloc = AssetManager.getAssetAllocations();
diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java
index 71fa2c2..1830f6c 100644
--- a/core/java/android/database/sqlite/SQLiteClosable.java
+++ b/core/java/android/database/sqlite/SQLiteClosable.java
@@ -32,7 +32,7 @@
synchronized(mLock) {
if (mReferenceCount <= 0) {
throw new IllegalStateException(
- "attempt to acquire a reference on an already-closed " + getObjInfo());
+ "attempt to re-open an already-closed object: " + getObjInfo());
}
mReferenceCount++;
}
@@ -59,7 +59,6 @@
private String getObjInfo() {
StringBuilder buff = new StringBuilder();
buff.append(this.getClass().getName());
- buff.append(" Obj");
buff.append(" (");
if (this instanceof SQLiteDatabase) {
buff.append("database = ");
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index dfd4024..b232ff9 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -23,6 +23,7 @@
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.SQLException;
+import android.database.sqlite.SQLiteDebug.DbStats;
import android.os.Debug;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -30,10 +31,14 @@
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import java.io.File;
+import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
@@ -787,25 +792,27 @@
* @throws SQLiteException if the database cannot be opened
*/
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
- SQLiteDatabase db = null;
+ SQLiteDatabase sqliteDatabase = null;
try {
// Open the database.
- SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags);
+ sqliteDatabase = new SQLiteDatabase(path, factory, flags);
if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
sqliteDatabase.enableSqlTracing(path);
}
if (SQLiteDebug.DEBUG_SQL_TIME) {
sqliteDatabase.enableSqlProfiling(path);
}
- return sqliteDatabase;
} catch (SQLiteDatabaseCorruptException e) {
// Try to recover from this, if we can.
// TODO: should we do this for other open failures?
Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
EventLog.writeEvent(EVENT_DB_CORRUPT, path);
new File(path).delete();
- return new SQLiteDatabase(path, factory, flags);
+ sqliteDatabase = new SQLiteDatabase(path, factory, flags);
}
+ ActiveDatabases.getInstance().mActiveDatabases.add(
+ new WeakReference<SQLiteDatabase>(sqliteDatabase));
+ return sqliteDatabase;
}
/**
@@ -2040,6 +2047,88 @@
mMaxSqlCacheSize = cacheSize;
}
+ static class ActiveDatabases {
+ private static final ActiveDatabases activeDatabases = new ActiveDatabases();
+ private HashSet<WeakReference<SQLiteDatabase>> mActiveDatabases =
+ new HashSet<WeakReference<SQLiteDatabase>>();
+ private ActiveDatabases() {} // disable instantiation of this class
+ static ActiveDatabases getInstance() {return activeDatabases;}
+ }
+
+ /* package */ static ArrayList<DbStats> getDbStats() {
+ ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
+ for (WeakReference<SQLiteDatabase> w : ActiveDatabases.getInstance().mActiveDatabases) {
+ SQLiteDatabase db = w.get();
+ if (db == null || !db.isOpen()) {
+ continue;
+ }
+ // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
+ int lookasideUsed = db.native_getDbLookaside();
+
+ // get the lastnode of the dbname
+ String path = db.getPath();
+ int indx = path.lastIndexOf("/");
+ String lastnode = path.substring((indx != -1) ? ++indx : 0);
+
+ // get list of attached dbs and for each db, get its size and pagesize
+ ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs(db);
+ for (int i = 0; i < attachedDbs.size(); i++) {
+ Pair<String, String> p = attachedDbs.get(i);
+ long pageCount = getPragmaVal(db, p.first + ".page_count;");
+
+ // first entry in the attached db list is always the main database
+ // don't worry about prefixing the dbname with "main"
+ String dbName;
+ if (i == 0) {
+ dbName = lastnode;
+ } else {
+ // lookaside is only relevant for the main db
+ lookasideUsed = 0;
+ dbName = " (attached) " + p.first;
+ // if the attached db has a path, attach the lastnode from the path to above
+ if (p.second.trim().length() > 0) {
+ int idx = p.second.lastIndexOf("/");
+ dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
+ }
+ }
+ dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), lookasideUsed));
+ }
+ }
+ return dbStatsList;
+ }
+
+ /**
+ * get the specified pragma value from sqlite for the specified database.
+ * only handles pragma's that return int/long.
+ * NO JAVA locks are held in this method.
+ * TODO: use this to do all pragma's in this class
+ */
+ private static long getPragmaVal(SQLiteDatabase db, String pragma) {
+ SQLiteStatement prog = null;
+ try {
+ prog = new SQLiteStatement(db, "PRAGMA " + pragma);
+ long val = prog.simpleQueryForLong();
+ return val;
+ } finally {
+ if (prog != null) prog.close();
+ }
+ }
+
+ /**
+ * returns list of full pathnames of all attached databases
+ * including the main database
+ * TODO: move this to {@link DatabaseUtils}
+ */
+ private static ArrayList<Pair<String, String>> getAttachedDbs(SQLiteDatabase dbObj) {
+ ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
+ Cursor c = dbObj.rawQuery("pragma database_list;", null);
+ while (c.moveToNext()) {
+ attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
+ }
+ c.close();
+ return attachedDbs;
+ }
+
/**
* Native call to open the database.
*
@@ -2093,4 +2182,11 @@
* @return the number of changes made in the last statement executed.
*/
/* package */ native int lastChangeCount();
+
+ /**
+ * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here
+ * http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html
+ * @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED
+ */
+ private native int native_getDbLookaside();
}
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index 4ea680e..a4db6d9 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import java.util.ArrayList;
+
import android.util.Log;
/**
@@ -68,14 +70,87 @@
* @see #getPagerStats(PagerStats)
*/
public static class PagerStats {
- /** The total number of bytes in all pagers in the current process */
+ /** The total number of bytes in all pagers in the current process
+ * @deprecated not used any longer
+ */
+ @Deprecated
public long totalBytes;
- /** The number of bytes in referenced pages in all pagers in the current process */
+ /** The number of bytes in referenced pages in all pagers in the current process
+ * @deprecated not used any longer
+ * */
+ @Deprecated
public long referencedBytes;
- /** The number of bytes in all database files opened in the current process */
+ /** The number of bytes in all database files opened in the current process
+ * @deprecated not used any longer
+ */
+ @Deprecated
public long databaseBytes;
- /** The number of pagers opened in the current process */
+ /** The number of pagers opened in the current process
+ * @deprecated not used any longer
+ */
+ @Deprecated
public int numPagers;
+
+ /** the current amount of memory checked out by sqlite using sqlite3_malloc().
+ * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
+ */
+ public int memoryUsed;
+
+ /** the number of bytes of page cache allocation which could not be sattisfied by the
+ * SQLITE_CONFIG_PAGECACHE buffer and where forced to overflow to sqlite3_malloc().
+ * The returned value includes allocations that overflowed because they where too large
+ * (they were larger than the "sz" parameter to SQLITE_CONFIG_PAGECACHE) and allocations
+ * that overflowed because no space was left in the page cache.
+ * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
+ */
+ public int pageCacheOverflo;
+
+ /** records the largest memory allocation request handed to sqlite3.
+ * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
+ */
+ public int largestMemAlloc;
+
+ /** a list of {@link DbStats} - one for each main database opened by the applications
+ * running on the android device
+ */
+ public ArrayList<DbStats> dbStats;
+ }
+
+ /**
+ * contains statistics about a database
+ * @author vnori@google.com (Your Name Here)
+ *
+ */
+ public static class DbStats {
+ /** name of the database */
+ public String dbName;
+
+ /** the page size for the database */
+ public long pageSize;
+
+ /** the database size */
+ public long dbSize;
+
+ /** documented here http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
+ public int lookaside;
+
+ public DbStats(String dbName, long pageCount, long pageSize, int lookaside) {
+ this.dbName = dbName;
+ this.pageSize = pageSize;
+ dbSize = (pageCount * pageSize) / 1024;
+ this.lookaside = lookaside;
+ }
+ }
+
+ /**
+ * return all pager and database stats for the current process.
+ * @return {@link PagerStats}
+ */
+ public static PagerStats getDatabaseInfo() {
+ PagerStats stats = new PagerStats();
+ getPagerStats(stats);
+ stats.dbStats = SQLiteDatabase.getDbStats();
+ return stats;
}
/**
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 3dd3918..b827af8 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -117,7 +117,10 @@
* exception.
*
* Verification of a package can take significant time, so this
- * function should not be called from a UI thread.
+ * function should not be called from a UI thread. Interrupting
+ * the thread while this function is in progress will result in a
+ * SecurityException being thrown (and the thread's interrupt flag
+ * will be cleared).
*
* @param packageFile the package to be verified
* @param listener an object to receive periodic progress
@@ -259,7 +262,10 @@
long soFar = 0;
raf.seek(0);
byte[] buffer = new byte[4096];
+ boolean interrupted = false;
while (soFar < toRead) {
+ interrupted = Thread.interrupted();
+ if (interrupted) break;
int size = buffer.length;
if (soFar + size > toRead) {
size = (int)(toRead - soFar);
@@ -283,6 +289,10 @@
listener.onProgress(100);
}
+ if (interrupted) {
+ throw new SignatureException("verification was interrupted");
+ }
+
if (!sig.verify(sigInfo.getEncryptedDigest())) {
throw new SignatureException("signature digest verification failed");
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 2b78d2d..acdfc28 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -105,7 +105,7 @@
* Distance a touch can wander before we think the user is attempting a paged scroll
* (in dips)
*/
- private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 3;
+ private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2;
/**
* Distance between the first touch and second touch to still be considered a double tap
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
index 75db0a0..47e7791 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -176,4 +176,19 @@
}
});
}
+
+ ChildView hitTest(int contentX, int contentY) {
+ if (mHidden) {
+ return null;
+ }
+ for (ChildView v : mChildren) {
+ if (v.mView.getVisibility() == View.VISIBLE) {
+ if (contentX >= v.x && contentX < (v.x + v.width)
+ && contentY >= v.y && contentY < (v.y + v.height)) {
+ return v;
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5099cd4..825ea46 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -479,8 +479,6 @@
private boolean mSupportMultiTouch;
// use the framework's ScaleGestureDetector to handle multi-touch
private ScaleGestureDetector mScaleDetector;
- // minimum scale change during multi-touch zoom
- private static float PREVIEW_SCALE_INCREMENT = 0.01f;
// the anchor point in the document space where VIEW_SIZE_CHANGED should
// apply to
@@ -619,6 +617,8 @@
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;
@@ -2306,7 +2306,8 @@
boolean clampedY) {
mInOverScrollMode = false;
int maxX = computeMaxScrollX();
- if (maxX == 0 && (Math.abs(mMinZoomScale - mMaxZoomScale) < 0.01f)
+ if (maxX == 0 && (Math.abs(mMinZoomScale - mMaxZoomScale)
+ < MINIMUM_SCALE_INCREMENT)
|| !getSettings().supportZoom()
|| !getSettings().getUseWideViewPort()) {
// do not over scroll x if the page just fits the screen and it
@@ -4466,7 +4467,8 @@
mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
// don't reflow when zoom in; when zoom out, do reflow if the
// new scale is almost minimum scale;
- boolean reflowNow = (mActualScale - mMinZoomScale <= 0.01f)
+ boolean reflowNow = (mActualScale - mMinZoomScale
+ <= MINIMUM_SCALE_INCREMENT)
|| ((mActualScale <= 0.8 * mTextWrapScale));
// force zoom after mPreviewZoomOnly is set to false so that the
// new view size will be passed to the WebKit
@@ -4493,7 +4495,7 @@
public boolean onScale(ScaleGestureDetector detector) {
float scale = (float) (Math.round(detector.getScaleFactor()
* mActualScale * 100) / 100.0);
- if (Math.abs(scale - mActualScale) >= PREVIEW_SCALE_INCREMENT) {
+ if (Math.abs(scale - mActualScale) >= MINIMUM_SCALE_INCREMENT) {
mPreviewZoomOnly = true;
// limit the scale change per step
if (scale > mActualScale) {
@@ -5430,17 +5432,17 @@
invalidate();
}
- private boolean zoomWithPreview(float scale) {
+ private boolean zoomWithPreview(float scale, boolean updateTextWrapScale) {
float oldScale = mActualScale;
mInitialScrollX = mScrollX;
mInitialScrollY = mScrollY;
// snap to DEFAULT_SCALE if it is close
- if (scale > (mDefaultScale - 0.05) && scale < (mDefaultScale + 0.05)) {
+ if (Math.abs(scale - mDefaultScale) < MINIMUM_SCALE_INCREMENT) {
scale = mDefaultScale;
}
- setNewZoomScale(scale, true, false);
+ setNewZoomScale(scale, updateTextWrapScale, false);
if (oldScale != mActualScale) {
// use mZoomPickerScale to see zoom preview first
@@ -5552,7 +5554,7 @@
mZoomCenterY = getViewHeight() * .5f;
mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- return zoomWithPreview(mActualScale * 1.25f);
+ return zoomWithPreview(mActualScale * 1.25f, true);
}
/**
@@ -5567,7 +5569,7 @@
mZoomCenterY = getViewHeight() * .5f;
mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
- return zoomWithPreview(mActualScale * 0.8f);
+ return zoomWithPreview(mActualScale * 0.8f, true);
}
private void updateSelection() {
@@ -5692,6 +5694,84 @@
}
}
+ /*
+ * Return true if the view (Plugin) is fully visible and maximized inside
+ * the WebView.
+ */
+ private boolean isPluginFitOnScreen(ViewManager.ChildView view) {
+ int viewWidth = getViewWidth();
+ int viewHeight = getViewHeightWithTitle();
+ float scale = Math.min((float) viewWidth / view.width,
+ (float) viewHeight / view.height);
+ if (scale < mMinZoomScale) {
+ scale = mMinZoomScale;
+ } else if (scale > mMaxZoomScale) {
+ scale = mMaxZoomScale;
+ }
+ if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
+ if (contentToViewX(view.x) >= mScrollX
+ && contentToViewX(view.x + view.width) <= mScrollX
+ + viewWidth
+ && contentToViewY(view.y) >= mScrollY
+ && contentToViewY(view.y + view.height) <= mScrollY
+ + viewHeight) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Maximize and center the view inside the WebView. If the zoom doesn't need
+ * to be changed, do an animated scroll to center it. If the zoom needs to
+ * be changed, find the zoom center and do a smooth zoom transition.
+ */
+ private void centerPluginOnScreen(ViewManager.ChildView child) {
+ int viewWidth = getViewWidth();
+ int viewHeight = getViewHeightWithTitle();
+ float scale = Math.min((float) viewWidth / child.width,
+ (float) viewHeight / child.height);
+ if (scale < mMinZoomScale) {
+ scale = mMinZoomScale;
+ } else if (scale > mMaxZoomScale) {
+ scale = mMaxZoomScale;
+ }
+ if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
+ pinScrollTo(
+ contentToViewX(child.x + child.width / 2) - viewWidth / 2,
+ contentToViewY(child.y + child.height / 2) - viewHeight / 2,
+ true, 0);
+ } else {
+ int oldScreenX = contentToViewX(child.x) - mScrollX;
+ int newPluginX = (int) (child.x * scale);
+ int newPluginWidth = (int) (child.width * scale);
+ int newMaxWidth = (int) (mContentWidth * scale);
+ int newScreenX = (viewWidth - newPluginWidth) / 2;
+ // pin the newX to the WebView
+ if (newScreenX > newPluginX) {
+ newScreenX = newPluginX;
+ } else if (newScreenX > (newMaxWidth - newPluginX - newPluginWidth)) {
+ newScreenX = viewWidth - (newMaxWidth - newPluginX);
+ }
+ mZoomCenterX = (oldScreenX * scale - newScreenX * mActualScale)
+ / (scale - mActualScale);
+ int oldScreenY = contentToViewY(child.y) - mScrollY;
+ int newPluginY = (int) (child.y * scale) + getTitleHeight();
+ int newPluginHeight = (int) (child.height * scale);
+ int newMaxHeight = (int) (mContentHeight * scale) + getTitleHeight();
+ int newScreenY = (viewHeight - newPluginHeight) / 2;
+ // pin the newY to the WebView
+ if (newScreenY > newPluginY) {
+ newScreenY = newPluginY;
+ } else if (newScreenY > (newMaxHeight - newPluginY - newPluginHeight)) {
+ newScreenY = viewHeight - (newMaxHeight - newPluginY);
+ }
+ mZoomCenterY = (oldScreenY * scale - newScreenY * mActualScale)
+ / (scale - mActualScale);
+ zoomWithPreview(scale, false);
+ }
+ }
+
// Rule for double tap:
// 1. if the current scale is not same as the text wrap scale and layout
// algorithm is NARROW_COLUMNS, fit to column;
@@ -5720,22 +5800,36 @@
}
}
settings.setDoubleTapToastCount(0);
+ ViewManager.ChildView plugin = mViewManager.hitTest(mAnchorX, mAnchorY);
+ if (plugin != null) {
+ if (isPluginFitOnScreen(plugin)) {
+ mInZoomOverview = true;
+ // Force the titlebar fully reveal in overview mode
+ if (mScrollY < getTitleHeight()) mScrollY = 0;
+ zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth,
+ true);
+ } else {
+ mInZoomOverview = false;
+ centerPluginOnScreen(plugin);
+ }
+ return;
+ }
boolean zoomToDefault = false;
if ((settings.getLayoutAlgorithm() == WebSettings.LayoutAlgorithm.NARROW_COLUMNS)
- && (Math.abs(mActualScale - mTextWrapScale) >= 0.01f)) {
+ && (Math.abs(mActualScale - mTextWrapScale) >= MINIMUM_SCALE_INCREMENT)) {
setNewZoomScale(mActualScale, true, true);
float overviewScale = (float) getViewWidth() / mZoomOverviewWidth;
- if (Math.abs(mActualScale - overviewScale) < 0.01f) {
+ if (Math.abs(mActualScale - overviewScale) < MINIMUM_SCALE_INCREMENT) {
mInZoomOverview = true;
}
} else if (!mInZoomOverview) {
float newScale = (float) getViewWidth() / mZoomOverviewWidth;
- if (Math.abs(mActualScale - newScale) >= 0.01f) {
+ if (Math.abs(mActualScale - newScale) >= MINIMUM_SCALE_INCREMENT) {
mInZoomOverview = true;
// Force the titlebar fully reveal in overview mode
if (mScrollY < getTitleHeight()) mScrollY = 0;
- zoomWithPreview(newScale);
- } else if (Math.abs(mActualScale - mDefaultScale) >= 0.01f) {
+ zoomWithPreview(newScale, true);
+ } else if (Math.abs(mActualScale - mDefaultScale) >= MINIMUM_SCALE_INCREMENT) {
zoomToDefault = true;
}
} else {
@@ -5758,7 +5852,7 @@
mZoomCenterX = 0;
}
}
- zoomWithPreview(mDefaultScale);
+ zoomWithPreview(mDefaultScale, true);
}
}
@@ -6103,7 +6197,8 @@
scale = restoreState.mTextWrapScale;
}
setNewZoomScale(scale, Math.abs(scale
- - mTextWrapScale) >= 0.01f, false);
+ - mTextWrapScale) >= MINIMUM_SCALE_INCREMENT,
+ false);
}
setContentScrollTo(restoreState.mScrollX,
restoreState.mScrollY);
@@ -6156,7 +6251,8 @@
- mZoomOverviewWidth) > 1) {
setNewZoomScale((float) viewWidth
/ mZoomOverviewWidth, Math.abs(mActualScale
- - mTextWrapScale) < 0.01f, false);
+ - mTextWrapScale) < MINIMUM_SCALE_INCREMENT,
+ false);
}
}
if (draw.mFocusSizeChanged && inEditingMode()) {
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 44e091d..fb93014 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -306,6 +306,16 @@
return sqlite3_changes(handle);
}
+/* native int native_getDbLookaside(); */
+static jint native_getDbLookaside(JNIEnv* env, jobject object)
+{
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+ int pCur = -1;
+ int unused;
+ sqlite3_db_status(handle, SQLITE_DBSTATUS_LOOKASIDE_USED, &pCur, &unused, 0);
+ return pCur;
+}
+
/* set locale in the android_metadata table, install localized collators, and rebuild indexes */
static void native_setLocale(JNIEnv* env, jobject object, jstring localeString, jint flags)
{
@@ -442,6 +452,7 @@
{"lastInsertRow", "()J", (void *)lastInsertRow},
{"lastChangeCount", "()I", (void *)lastChangeCount},
{"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
+ {"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
{"releaseMemory", "()I", (void *)native_releaseMemory},
};
diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp
index 916df35..873b2a1 100644
--- a/core/jni/android_database_SQLiteDebug.cpp
+++ b/core/jni/android_database_SQLiteDebug.cpp
@@ -29,36 +29,28 @@
// From mem_mspace.c in libsqlite
extern "C" mspace sqlite3_get_mspace();
-// From sqlite.c, hacked in for Android
-extern "C" void sqlite3_get_pager_stats(sqlite3_int64 * totalBytesOut,
- sqlite3_int64 * referencedBytesOut,
- sqlite3_int64 * dbBytesOut,
- int * numPagersOut);
-
namespace android {
-static jfieldID gTotalBytesField;
-static jfieldID gReferencedBytesField;
-static jfieldID gDbBytesField;
-static jfieldID gNumPagersField;
+static jfieldID gMemoryUsedField;
+static jfieldID gPageCacheOverfloField;
+static jfieldID gLargestMemAllocField;
#define USE_MSPACE 0
static void getPagerStats(JNIEnv *env, jobject clazz, jobject statsObj)
{
- sqlite3_int64 totalBytes;
- sqlite3_int64 referencedBytes;
- sqlite3_int64 dbBytes;
- int numPagers;
+ int memoryUsed;
+ int pageCacheOverflo;
+ int largestMemAlloc;
+ int unused;
- sqlite3_get_pager_stats(&totalBytes, &referencedBytes, &dbBytes,
- &numPagers);
-
- env->SetLongField(statsObj, gTotalBytesField, totalBytes);
- env->SetLongField(statsObj, gReferencedBytesField, referencedBytes);
- env->SetLongField(statsObj, gDbBytesField, dbBytes);
- env->SetIntField(statsObj, gNumPagersField, numPagers);
+ sqlite3_status(SQLITE_STATUS_MEMORY_USED, &memoryUsed, &unused, 0);
+ sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &unused, &largestMemAlloc, 0);
+ sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &pageCacheOverflo, &unused, 0);
+ env->SetIntField(statsObj, gMemoryUsedField, memoryUsed);
+ env->SetIntField(statsObj, gPageCacheOverfloField, pageCacheOverflo);
+ env->SetIntField(statsObj, gLargestMemAllocField, largestMemAlloc);
}
static jlong getHeapSize(JNIEnv *env, jobject clazz)
@@ -213,27 +205,21 @@
return -1;
}
- gTotalBytesField = env->GetFieldID(clazz, "totalBytes", "J");
- if (gTotalBytesField == NULL) {
- LOGE("Can't find totalBytes");
+ gMemoryUsedField = env->GetFieldID(clazz, "memoryUsed", "I");
+ if (gMemoryUsedField == NULL) {
+ LOGE("Can't find memoryUsed");
return -1;
}
- gReferencedBytesField = env->GetFieldID(clazz, "referencedBytes", "J");
- if (gReferencedBytesField == NULL) {
- LOGE("Can't find referencedBytes");
+ gLargestMemAllocField = env->GetFieldID(clazz, "largestMemAlloc", "I");
+ if (gLargestMemAllocField == NULL) {
+ LOGE("Can't find largestMemAlloc");
return -1;
}
- gDbBytesField = env->GetFieldID(clazz, "databaseBytes", "J");
- if (gDbBytesField == NULL) {
- LOGE("Can't find databaseBytes");
- return -1;
- }
-
- gNumPagersField = env->GetFieldID(clazz, "numPagers", "I");
- if (gNumPagersField == NULL) {
- LOGE("Can't find numPagers");
+ gPageCacheOverfloField = env->GetFieldID(clazz, "pageCacheOverflo", "I");
+ if (gPageCacheOverfloField == NULL) {
+ LOGE("Can't find pageCacheOverflo");
return -1;
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f5e2f1d..06e9bbf 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1748,9 +1748,9 @@
The default value is true. -->
<attr name="footerDividersEnabled" format="boolean" />
<!-- Drawable to draw above list content. -->
- <attr name="overscrollHeader" format="reference" />
+ <attr name="overscrollHeader" format="reference|color" />
<!-- Drawable to draw below list content. -->
- <attr name="overscrollFooter" format="reference" />
+ <attr name="overscrollFooter" format="reference|color" />
</declare-styleable>
<declare-styleable name="MenuView">
<!-- Default appearance of menu item text. -->
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index f623295b..c6bbbcc 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -159,8 +159,10 @@
status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
{
Mutex::Autolock _l(mLock);
- if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED ))
- {
+ const bool hasBeenInitialized =
+ (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
+ ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
+ if ((mPlayer != NULL) && hasBeenInitialized) {
LOGV("invoke %d", request.dataSize());
return mPlayer->invoke(request, reply);
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 78d8c49..da9232b 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -53,6 +53,7 @@
import android.os.SystemProperties;
import android.os.Vibrator;
import android.provider.Settings;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
@@ -106,6 +107,7 @@
// for enabling and disabling notification pulse behavior
private boolean mScreenOn = true;
+ private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
// for adb connected notifications
@@ -362,6 +364,9 @@
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
updateNotificationPulse();
+ } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
+ mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK));
+ updateNotificationPulse();
}
}
};
@@ -444,6 +449,7 @@
filter.addAction(Intent.ACTION_UMS_DISCONNECTED);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
mContext.registerReceiver(mIntentReceiver, filter);
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -1064,7 +1070,8 @@
}
// we only flash if screen is off and persistent pulsing is enabled
- if (mLedNotification == null || mScreenOn) {
+ // and we are not currently in a call
+ if (mLedNotification == null || mScreenOn || mInCall) {
mNotificationLight.turnOff();
} else {
int ledARGB = mLedNotification.notification.ledARGB;