Merge "Add new Slog class."
diff --git a/api/current.xml b/api/current.xml
index 3b90f38..89af2ac 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -189783,7 +189783,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -189835,7 +189835,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 393bbba..211a2ae 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -819,7 +819,7 @@
}
scheduleSyncOperation(new SyncOperation(operation.account, operation.syncSource,
operation.authority, operation.extras,
- DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS));
+ DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000));
} else if (syncResult.hasSoftError()) {
if (isLoggable) {
Log.d(TAG, "retrying sync operation because it encountered a soft error: "
diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java
index 4599165..3b3f9c1 100644
--- a/core/java/android/content/SyncOperation.java
+++ b/core/java/android/content/SyncOperation.java
@@ -19,7 +19,7 @@
public SyncStorageEngine.PendingOperation pendingOperation;
public SyncOperation(Account account, int source, String authority, Bundle extras,
- long delay) {
+ long delayInMs) {
this.account = account;
this.syncSource = source;
this.authority = authority;
@@ -33,12 +33,12 @@
removeFalseExtra(ContentResolver.SYNC_EXTRAS_EXPEDITED);
removeFalseExtra(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
final long now = SystemClock.elapsedRealtime();
- if (delay < 0) {
+ if (delayInMs < 0) {
this.expedited = true;
this.earliestRunTime = now;
} else {
this.expedited = false;
- this.earliestRunTime = now + delay;
+ this.earliestRunTime = now + delayInMs;
}
this.key = toKey();
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index d96596295..0de1868 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -101,6 +101,12 @@
public static final String READ = "read";
/**
+ * Indicates whether this message has been seen by the user. The "seen" flag will be
+ * used to figure out whether we need to throw up a statusbar notification or not.
+ */
+ public static final String SEEN = "seen";
+
+ /**
* The TP-Status value for the message, or -1 if no status has
* been received
*/
@@ -646,6 +652,12 @@
public static final String READ = "read";
/**
+ * Indicates whether this message has been seen by the user. The "seen" flag will be
+ * used to figure out whether we need to throw up a statusbar notification or not.
+ */
+ public static final String SEEN = "seen";
+
+ /**
* The Message-ID of the message.
* <P>Type: TEXT</P>
*/
@@ -1097,6 +1109,7 @@
* <P>Type: INTEGER</P>
*/
public static final String READ = "read";
+
/**
* The snippet of the latest message in the thread.
* <P>Type: TEXT</P>
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index afb22ac..9589bf3 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1557,13 +1557,17 @@
* @param reqModes The modes to be checked: may be any combination of
* {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and
* {@link #CAP_MODE_SENTENCES}.
- *
+ *
* @return Returns the actual capitalization modes that can be in effect
* at the current position, which is any combination of
* {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and
* {@link #CAP_MODE_SENTENCES}.
*/
public static int getCapsMode(CharSequence cs, int off, int reqModes) {
+ if (off < 0) {
+ return 0;
+ }
+
int i;
char c;
int mode = 0;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d7f2539..0722699 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -320,8 +320,14 @@
* <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
*/
public void setZOrderOnTop(boolean onTop) {
- mWindowType = onTop ? WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
- : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ if (onTop) {
+ mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+ // ensures the surface is placed below the IME
+ mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ } else {
+ mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ }
}
/**
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 3f1672a..1c0d55f 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -407,7 +407,8 @@
}
}
}
- CacheManager.trimCacheIfNeeded();
+ WebViewWorker.getHandler().sendEmptyMessage(
+ WebViewWorker.MSG_TRIM_CACHE);
break;
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 647556b..1c59c10 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -25,10 +25,11 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
@@ -200,9 +201,9 @@
// the cache database. The directory could be recreated
// because the system flushed all the data/cache directories
// to free up disk space.
- WebViewCore.endCacheTransaction();
- mDataBase.clearCache();
- WebViewCore.startCacheTransaction();
+ // delete rows in the cache database
+ WebViewWorker.getHandler().sendEmptyMessage(
+ WebViewWorker.MSG_CLEAR_CACHE);
return true;
}
return false;
@@ -223,7 +224,6 @@
*
* @param disabled true to disable the cache
*/
- // only called from WebCore thread
static void setCacheDisabled(boolean disabled) {
if (disabled == mDisabled) {
return;
@@ -243,7 +243,7 @@
return mDisabled;
}
- // only called from WebCore thread
+ // only called from WebViewWorkerThread
// make sure to call enableTransaction/disableTransaction in pair
static boolean enableTransaction() {
if (++mRefCount == 1) {
@@ -253,12 +253,9 @@
return false;
}
- // only called from WebCore thread
+ // only called from WebViewWorkerThread
// make sure to call enableTransaction/disableTransaction in pair
static boolean disableTransaction() {
- if (mRefCount == 0) {
- Log.e(LOGTAG, "disableTransaction is out of sync");
- }
if (--mRefCount == 0) {
mDataBase.endCacheTransaction();
return true;
@@ -266,15 +263,15 @@
return false;
}
- // only called from WebCore thread
- // make sure to call startCacheTransaction/endCacheTransaction in pair
- public static boolean startCacheTransaction() {
+ // only called from WebViewWorkerThread
+ // make sure to call startTransaction/endTransaction in pair
+ static boolean startTransaction() {
return mDataBase.startCacheTransaction();
}
- // only called from WebCore thread
- // make sure to call startCacheTransaction/endCacheTransaction in pair
- public static boolean endCacheTransaction() {
+ // only called from WebViewWorkerThread
+ // make sure to call startTransaction/endTransaction in pair
+ static boolean endTransaction() {
boolean ret = mDataBase.endCacheTransaction();
if (++mTrimCacheCount >= TRIM_CACHE_INTERVAL) {
mTrimCacheCount = 0;
@@ -283,6 +280,26 @@
return ret;
}
+ // only called from WebCore Thread
+ // make sure to call startCacheTransaction/endCacheTransaction in pair
+ /**
+ * @deprecated
+ */
+ @Deprecated
+ public static boolean startCacheTransaction() {
+ return false;
+ }
+
+ // only called from WebCore Thread
+ // make sure to call startCacheTransaction/endCacheTransaction in pair
+ /**
+ * @deprecated
+ */
+ @Deprecated
+ public static boolean endCacheTransaction() {
+ return false;
+ }
+
/**
* Given a url, returns the CacheResult if exists. Otherwise returns null.
* If headers are provided and a cache needs validation,
@@ -291,13 +308,11 @@
*
* @return the CacheResult for a given url
*/
- // only called from WebCore thread
public static CacheResult getCacheFile(String url,
Map<String, String> headers) {
return getCacheFile(url, 0, headers);
}
- // only called from WebCore thread
static CacheResult getCacheFile(String url, long postIdentifier,
Map<String, String> headers) {
if (mDisabled) {
@@ -368,14 +383,12 @@
* @hide - hide createCacheFile since it has a parameter of type headers, which is
* in a hidden package.
*/
- // only called from WebCore thread
public static CacheResult createCacheFile(String url, int statusCode,
Headers headers, String mimeType, boolean forceCache) {
return createCacheFile(url, statusCode, headers, mimeType, 0,
forceCache);
}
- // only called from WebCore thread
static CacheResult createCacheFile(String url, int statusCode,
Headers headers, String mimeType, long postIdentifier,
boolean forceCache) {
@@ -435,12 +448,10 @@
* Save the info of a cache file for a given url to the CacheMap so that it
* can be reused later
*/
- // only called from WebCore thread
public static void saveCacheFile(String url, CacheResult cacheRet) {
saveCacheFile(url, 0, cacheRet);
}
- // only called from WebCore thread
static void saveCacheFile(String url, long postIdentifier,
CacheResult cacheRet) {
try {
@@ -489,7 +500,6 @@
*
* @return true if it succeeds
*/
- // only called from WebCore thread
static boolean removeAllCacheFiles() {
// Note, this is called before init() when the database is
// created or upgraded.
@@ -499,7 +509,10 @@
mClearCacheOnInit = true;
return true;
}
- // delete cache in a separate thread to not block UI.
+ // delete rows in the cache database
+ WebViewWorker.getHandler().sendEmptyMessage(
+ WebViewWorker.MSG_CLEAR_CACHE);
+ // delete cache files in a separate thread to not block UI.
final Runnable clearCache = new Runnable() {
public void run() {
// delete all cache files
@@ -517,8 +530,6 @@
} catch (SecurityException e) {
// Ignore SecurityExceptions.
}
- // delete database
- mDataBase.clearCache();
}
};
new Thread(clearCache).start();
@@ -528,15 +539,13 @@
/**
* Return true if the cache is empty.
*/
- // only called from WebCore thread
static boolean cacheEmpty() {
return mDataBase.hasCache();
}
- // only called from WebCore thread
static void trimCacheIfNeeded() {
if (mDataBase.getCacheTotalSize() > CACHE_THRESHOLD) {
- ArrayList<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT);
+ List<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT);
int size = pathList.size();
for (int i = 0; i < size; i++) {
File f = new File(mBaseDir, pathList.get(i));
@@ -544,9 +553,34 @@
Log.e(LOGTAG, f.getPath() + " delete failed.");
}
}
+ // remove the unreferenced files in the cache directory
+ final List<String> fileList = mDataBase.getAllCacheFileNames();
+ if (fileList == null) return;
+ String[] toDelete = mBaseDir.list(new FilenameFilter() {
+ public boolean accept(File dir, String filename) {
+ if (fileList.contains(filename)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ });
+ if (toDelete == null) return;
+ size = toDelete.length;
+ for (int i = 0; i < size; i++) {
+ File f = new File(mBaseDir, toDelete[i]);
+ if (!f.delete()) {
+ Log.e(LOGTAG, f.getPath() + " delete failed.");
+ }
+ }
}
}
+ static void clearCache() {
+ // delete database
+ mDataBase.clearCache();
+ }
+
private static boolean checkCacheRedirect(int statusCode) {
if (statusCode == 301 || statusCode == 302 || statusCode == 307) {
// as 303 can't be cached, we do not return true
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index b13c405..7903632 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -110,7 +110,9 @@
return false;
}
mNetwork = Network.getInstance(mListener.getContext());
- return handleHTTPLoad();
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_HTTPLOADER, this).sendToTarget();
+ return true;
} else if (handleLocalFile(url, mListener, mSettings)) {
return true;
}
@@ -142,24 +144,33 @@
}
if (URLUtil.isAssetUrl(url)) {
// load asset in a separate thread as it involves IO
- new FileLoader(url, loadListener, FileLoader.TYPE_ASSET, true)
- .enqueue();
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_STREAMLOADER,
+ new FileLoader(url, loadListener, FileLoader.TYPE_ASSET,
+ true)).sendToTarget();
return true;
} else if (URLUtil.isResourceUrl(url)) {
// load resource in a separate thread as it involves IO
- new FileLoader(url, loadListener, FileLoader.TYPE_RES, true)
- .enqueue();
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_STREAMLOADER,
+ new FileLoader(url, loadListener, FileLoader.TYPE_RES,
+ true)).sendToTarget();
return true;
} else if (URLUtil.isFileUrl(url)) {
// load file in a separate thread as it involves IO
- new FileLoader(url, loadListener, FileLoader.TYPE_FILE, settings
- .getAllowFileAccess()).enqueue();
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_STREAMLOADER,
+ new FileLoader(url, loadListener, FileLoader.TYPE_FILE,
+ settings.getAllowFileAccess())).sendToTarget();
return true;
} else if (URLUtil.isContentUrl(url)) {
// Send the raw url to the ContentLoader because it will do a
// permission check and the url has to match.
// load content in a separate thread as it involves IO
- new ContentLoader(loadListener.url(), loadListener).enqueue();
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_STREAMLOADER,
+ new ContentLoader(loadListener.url(), loadListener))
+ .sendToTarget();
return true;
} else if (URLUtil.isDataUrl(url)) {
// load data in the current thread to reduce the latency
@@ -172,8 +183,8 @@
}
return false;
}
-
- private boolean handleHTTPLoad() {
+
+ boolean handleHTTPLoad() {
if (mHeaders == null) {
mHeaders = new HashMap<String, String>();
}
@@ -229,7 +240,9 @@
CacheLoader cacheLoader =
new CacheLoader(mListener, result);
mListener.setCacheLoader(cacheLoader);
- cacheLoader.load();
+ // Load the cached file in a separate thread
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_STREAMLOADER, cacheLoader).sendToTarget();
}
/*
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index cdc6608..8bacee4 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -101,7 +101,6 @@
private boolean mCancelled; // The request has been cancelled.
private boolean mAuthFailed; // indicates that the prev. auth failed
private CacheLoader mCacheLoader;
- private CacheManager.CacheResult mCacheResult;
private boolean mFromCache = false;
private HttpAuthHeader mAuthHeader;
private int mErrorID = OK;
@@ -301,6 +300,12 @@
*/
public void headers(Headers headers) {
if (DebugFlags.LOAD_LISTENER) Log.v(LOGTAG, "LoadListener.headers");
+ // call db (setCookie) in the non-WebCore thread
+ if (mCancelled) return;
+ ArrayList<String> cookies = headers.getSetCookie();
+ for (int i = 0; i < cookies.size(); ++i) {
+ CookieManager.getInstance().setCookie(mUri, cookies.get(i));
+ }
sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS, headers));
}
@@ -316,11 +321,6 @@
if (mCancelled) return;
mHeaders = headers;
- ArrayList<String> cookies = headers.getSetCookie();
- for (int i = 0; i < cookies.size(); ++i) {
- CookieManager.getInstance().setCookie(mUri, cookies.get(i));
- }
-
long contentLength = headers.getContentLength();
if (contentLength != Headers.NO_CONTENT_LENGTH) {
mContentLength = contentLength;
@@ -454,12 +454,19 @@
if (!mFromCache && mRequestHandle != null
&& (!mRequestHandle.getMethod().equals("POST")
|| mPostIdentifier != 0)) {
- mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
- headers, mMimeType, mPostIdentifier, false);
+ WebViewWorker.CacheCreateData data = new WebViewWorker.CacheCreateData();
+ data.mListener = this;
+ data.mUrl = mUrl;
+ data.mMimeType = mMimeType;
+ data.mStatusCode = mStatusCode;
+ data.mPostId = mPostIdentifier;
+ data.mHeaders = headers;
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_CREATE_CACHE, data).sendToTarget();
}
- if (mCacheResult != null) {
- mCacheResult.encoding = mEncoding;
- }
+ WebViewWorker.CacheEncoding ce = new WebViewWorker.CacheEncoding();
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_UPDATE_CACHE_ENCODING, ce).sendToTarget();
}
commitHeadersCheckRedirect();
}
@@ -649,7 +656,10 @@
// ask for it, so make sure we have a valid CacheLoader
// before calling it.
if (mCacheLoader != null) {
- mCacheLoader.load();
+ // Load the cached file in a separate thread
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_STREAMLOADER, mCacheLoader)
+ .sendToTarget();
mFromCache = true;
if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener cache load url=" + url());
@@ -708,8 +718,10 @@
Log.v(LOGTAG, "FrameLoader: HTTP URL in cache " +
"and usable: " + url());
}
- // Load the cached file
- mCacheLoader.load();
+ // Load the cached file in a separate thread
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_ADD_STREAMLOADER, mCacheLoader)
+ .sendToTarget();
mFromCache = true;
return true;
}
@@ -934,12 +946,9 @@
* WebCore.
*/
void downloadFile() {
- // Setting the Cache Result to null ensures that this
- // content is not added to the cache
- if (mCacheResult != null) {
- CacheManager.cleanupCacheFile(mCacheResult);
- mCacheResult = null;
- }
+ // remove the cache
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_REMOVE_CACHE, this).sendToTarget();
// Inform the client that they should download a file
mBrowserFrame.getCallbackProxy().onDownloadStart(url(),
@@ -1098,24 +1107,15 @@
if (c == null) break;
if (c.mLength != 0) {
- if (mCacheResult != null) {
- mCacheResult.contentLength += c.mLength;
- if (mCacheResult.contentLength > CacheManager.CACHE_MAX_SIZE) {
- CacheManager.cleanupCacheFile(mCacheResult);
- mCacheResult = null;
- } else {
- try {
- mCacheResult.outStream
- .write(c.mArray, 0, c.mLength);
- } catch (IOException e) {
- CacheManager.cleanupCacheFile(mCacheResult);
- mCacheResult = null;
- }
- }
- }
nativeAddData(c.mArray, c.mLength);
+ WebViewWorker.CacheData data = new WebViewWorker.CacheData();
+ data.mListener = this;
+ data.mChunk = c;
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_APPEND_CACHE, data).sendToTarget();
+ } else {
+ c.release();
}
- c.release();
checker.responseAlert("res nativeAddData");
}
}
@@ -1125,18 +1125,16 @@
* cancellation or errors during the load.
*/
void tearDown() {
- if (mCacheResult != null) {
- if (getErrorID() == OK) {
- CacheManager.saveCacheFile(mUrl, mPostIdentifier, mCacheResult);
- } else {
- CacheManager.cleanupCacheFile(mCacheResult);
- }
-
- // we need to reset mCacheResult to be null
- // resource loader's tearDown will call into WebCore's
- // nativeFinish, which in turn calls loader.cancel().
- // If we don't reset mCacheFile, the file will be deleted.
- mCacheResult = null;
+ if (getErrorID() == OK) {
+ WebViewWorker.CacheSaveData data = new WebViewWorker.CacheSaveData();
+ data.mListener = this;
+ data.mUrl = mUrl;
+ data.mPostId = mPostIdentifier;
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_SAVE_CACHE, data).sendToTarget();
+ } else {
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_REMOVE_CACHE, this).sendToTarget();
}
if (mNativeLoader != 0) {
PerfChecker checker = new PerfChecker();
@@ -1194,10 +1192,8 @@
mRequestHandle = null;
}
- if (mCacheResult != null) {
- CacheManager.cleanupCacheFile(mCacheResult);
- mCacheResult = null;
- }
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_REMOVE_CACHE, this).sendToTarget();
mCancelled = true;
clearNativeLoader();
@@ -1258,14 +1254,16 @@
}
// Cache the redirect response
- if (mCacheResult != null) {
- if (getErrorID() == OK) {
- CacheManager.saveCacheFile(mUrl, mPostIdentifier,
- mCacheResult);
- } else {
- CacheManager.cleanupCacheFile(mCacheResult);
- }
- mCacheResult = null;
+ if (getErrorID() == OK) {
+ WebViewWorker.CacheSaveData data = new WebViewWorker.CacheSaveData();
+ data.mListener = this;
+ data.mUrl = mUrl;
+ data.mPostId = mPostIdentifier;
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_SAVE_CACHE, data).sendToTarget();
+ } else {
+ WebViewWorker.getHandler().obtainMessage(
+ WebViewWorker.MSG_REMOVE_CACHE, this).sendToTarget();
}
// This will strip the anchor
diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
index 4c32997..7bcd50d 100644
--- a/core/java/android/webkit/StreamLoader.java
+++ b/core/java/android/webkit/StreamLoader.java
@@ -20,8 +20,6 @@
import android.net.http.EventHandler;
import android.net.http.Headers;
import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
import android.os.Message;
import java.io.IOException;
@@ -61,11 +59,6 @@
// Handler which will be initialized in the thread where load() is called.
private Handler mHandler;
- // Handler which will be used to load StreamLoader in a separate thread
- private static StreamQueueHandler sStreamQueueHandler;
-
- private static final Object sStreamQueueLock = new Object();
-
/**
* Constructor. Although this class calls the LoadListener, it only calls
* the EventHandler Interface methods. LoadListener concrete class is used
@@ -97,26 +90,6 @@
abstract protected void buildHeaders(Headers headers);
/**
- * Calling this method to load this StreamLoader in a separate
- * "StreamLoadingThread".
- */
- final void enqueue() {
- synchronized (sStreamQueueLock) {
- if (sStreamQueueHandler == null) {
- HandlerThread thread = new HandlerThread(
- StreamQueueHandler.THREAD_NAME,
- android.os.Process.THREAD_PRIORITY_DEFAULT +
- android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
- thread.start();
- sStreamQueueHandler = new StreamQueueHandler(thread.getLooper());
- }
- }
-
- sStreamQueueHandler.obtainMessage(StreamQueueHandler.MSG_ADD_LOADER,
- this).sendToTarget();
- }
-
- /**
* Calling this method starts the load of the content for this StreamLoader.
* This method simply creates a Handler in the current thread and posts a
* message to send the status and returns immediately.
@@ -228,22 +201,4 @@
}
mLoadListener.endData();
}
-
- private static class StreamQueueHandler extends Handler {
- private static final String THREAD_NAME = "StreamLoadingThread";
-
- private static final int MSG_ADD_LOADER = 101;
-
- StreamQueueHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MSG_ADD_LOADER) {
- StreamLoader loader = (StreamLoader) msg.obj;
- loader.load();
- }
- }
- }
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index d1ad61f..db19bca 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -304,15 +304,16 @@
public void onEditorAction(int actionCode) {
switch (actionCode) {
case EditorInfo.IME_ACTION_NEXT:
- // Since the cursor will no longer be in the same place as the
- // focus, set the focus controller back to inactive
- mWebView.setFocusControllerInactive();
- mWebView.nativeMoveCursorToNextTextInput();
- // Preemptively rebuild the WebTextView, so that the action will
- // be set properly.
- mWebView.rebuildWebTextView();
- setDefaultSelection();
- mWebView.invalidate();
+ if (mWebView.nativeMoveCursorToNextTextInput()) {
+ // Since the cursor will no longer be in the same place as the
+ // focus, set the focus controller back to inactive
+ mWebView.setFocusControllerInactive();
+ // Preemptively rebuild the WebTextView, so that the action will
+ // be set properly.
+ mWebView.rebuildWebTextView();
+ setDefaultSelection();
+ mWebView.invalidate();
+ }
break;
case EditorInfo.IME_ACTION_DONE:
super.onEditorAction(actionCode);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d29d6f3..897bd75 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6807,7 +6807,7 @@
private native void nativeHideCursor();
private native String nativeImageURI(int x, int y);
private native void nativeInstrumentReport();
- /* package */ native void nativeMoveCursorToNextTextInput();
+ /* package */ native boolean nativeMoveCursorToNextTextInput();
// return true if the page has been scrolled
private native boolean nativeMotionUp(int x, int y, int slop);
// returns false if it handled the key
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4606bc6..71f69fe 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -587,13 +587,6 @@
private static final int INITIALIZE = 0;
private static final int REDUCE_PRIORITY = 1;
private static final int RESUME_PRIORITY = 2;
- private static final int CACHE_TICKER = 3;
- private static final int BLOCK_CACHE_TICKER = 4;
- private static final int RESUME_CACHE_TICKER = 5;
-
- private static final int CACHE_TICKER_INTERVAL = 60 * 1000; // 1 minute
-
- private static boolean mCacheTickersBlocked = true;
public void run() {
Looper.prepare();
@@ -619,28 +612,6 @@
Process.setThreadPriority(
Process.THREAD_PRIORITY_DEFAULT);
break;
-
- case CACHE_TICKER:
- if (!mCacheTickersBlocked) {
- CacheManager.endCacheTransaction();
- CacheManager.startCacheTransaction();
- sendMessageDelayed(
- obtainMessage(CACHE_TICKER),
- CACHE_TICKER_INTERVAL);
- }
- break;
-
- case BLOCK_CACHE_TICKER:
- if (CacheManager.endCacheTransaction()) {
- mCacheTickersBlocked = true;
- }
- break;
-
- case RESUME_CACHE_TICKER:
- if (CacheManager.startCacheTransaction()) {
- mCacheTickersBlocked = false;
- }
- break;
}
}
};
@@ -1092,23 +1063,15 @@
Process.setThreadPriority(mTid,
Process.THREAD_PRIORITY_BACKGROUND);
pauseTimers();
- if (CacheManager.disableTransaction()) {
- WebCoreThread.mCacheTickersBlocked = true;
- sWebCoreHandler.removeMessages(
- WebCoreThread.CACHE_TICKER);
- }
+ WebViewWorker.getHandler().sendEmptyMessage(
+ WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION);
break;
case RESUME_TIMERS:
Process.setThreadPriority(mTid, mSavedPriority);
resumeTimers();
- if (CacheManager.enableTransaction()) {
- WebCoreThread.mCacheTickersBlocked = false;
- sWebCoreHandler.sendMessageDelayed(
- sWebCoreHandler.obtainMessage(
- WebCoreThread.CACHE_TICKER),
- WebCoreThread.CACHE_TICKER_INTERVAL);
- }
+ WebViewWorker.getHandler().sendEmptyMessage(
+ WebViewWorker.MSG_RESUME_CACHE_TRANSACTION);
break;
case ON_PAUSE:
@@ -1851,16 +1814,6 @@
.obtainMessage(WebCoreThread.RESUME_PRIORITY));
}
- static void startCacheTransaction() {
- sWebCoreHandler.sendMessage(sWebCoreHandler
- .obtainMessage(WebCoreThread.RESUME_CACHE_TICKER));
- }
-
- static void endCacheTransaction() {
- sWebCoreHandler.sendMessage(sWebCoreHandler
- .obtainMessage(WebCoreThread.BLOCK_CACHE_TICKER));
- }
-
static void pauseUpdatePicture(WebViewCore core) {
// Note: there is one possible failure mode. If pauseUpdatePicture() is
// called from UI thread while WEBKIT_DRAW is just pulled out of the
@@ -1992,9 +1945,10 @@
sendUpdateTextEntry();
// as CacheManager can behave based on database transaction, we need to
// call tick() to trigger endTransaction
- sWebCoreHandler.removeMessages(WebCoreThread.CACHE_TICKER);
- sWebCoreHandler.sendMessage(sWebCoreHandler
- .obtainMessage(WebCoreThread.CACHE_TICKER));
+ WebViewWorker.getHandler().removeMessages(
+ WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
+ WebViewWorker.getHandler().sendEmptyMessage(
+ WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
contentDraw();
}
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 110e4f8..a870931 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
@@ -234,6 +235,13 @@
}
if (mCacheDatabase != null) {
+ // use read_uncommitted to speed up READ
+ mCacheDatabase.execSQL("PRAGMA read_uncommitted = true;");
+ // as only READ can be called in the non-WebViewWorkerThread,
+ // and read_uncommitted is used, we can turn off database lock
+ // to use transaction.
+ mCacheDatabase.setLockingEnabled(false);
+
// use InsertHelper for faster insertion
mCacheInserter = new DatabaseUtils.InsertHelper(mCacheDatabase,
"cache");
@@ -548,19 +556,33 @@
}
//
- // cache functions, can only be called from WebCoreThread
+ // cache functions
//
+ // only called from WebViewWorkerThread
boolean startCacheTransaction() {
if (++mCacheTransactionRefcount == 1) {
+ if (!Thread.currentThread().equals(
+ WebViewWorker.getHandler().getLooper().getThread())) {
+ Log.w(LOGTAG, "startCacheTransaction should be called from "
+ + "WebViewWorkerThread instead of from "
+ + Thread.currentThread().getName());
+ }
mCacheDatabase.beginTransaction();
return true;
}
return false;
}
+ // only called from WebViewWorkerThread
boolean endCacheTransaction() {
if (--mCacheTransactionRefcount == 0) {
+ if (!Thread.currentThread().equals(
+ WebViewWorker.getHandler().getLooper().getThread())) {
+ Log.w(LOGTAG, "endCacheTransaction should be called from "
+ + "WebViewWorkerThread instead of from "
+ + Thread.currentThread().getName());
+ }
try {
mCacheDatabase.setTransactionSuccessful();
} finally {
@@ -684,7 +706,7 @@
return size;
}
- ArrayList<String> trimCache(long amount) {
+ List<String> trimCache(long amount) {
ArrayList<String> pathList = new ArrayList<String>(100);
Cursor cursor = mCacheDatabase.rawQuery(
"SELECT contentlength, filepath FROM cache ORDER BY expires ASC",
@@ -727,6 +749,20 @@
return pathList;
}
+ List<String> getAllCacheFileNames() {
+ ArrayList<String> pathList = null;
+ Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath FROM cache",
+ null);
+ if (cursor != null && cursor.moveToFirst()) {
+ pathList = new ArrayList<String>(cursor.getCount());
+ do {
+ pathList.add(cursor.getString(0));
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ return pathList;
+ }
+
//
// password functions
//
diff --git a/core/java/android/webkit/WebViewWorker.java b/core/java/android/webkit/WebViewWorker.java
new file mode 100644
index 0000000..c488150
--- /dev/null
+++ b/core/java/android/webkit/WebViewWorker.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.net.http.Headers;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * WebViewWorker executes in a separate thread other than UI and WebViewCore. To
+ * avoid blocking UI or WebKit's execution, the caller can send a message to
+ * WebViewWorker.getHandler() and it will be handled in the WebViewWorkerThread.
+ */
+final class WebViewWorker extends Handler {
+
+ private static final String THREAD_NAME = "WebViewWorkerThread";
+
+ private static WebViewWorker sWorkerHandler;
+
+ private static Map<LoadListener, CacheManager.CacheResult> mCacheResultMap
+ = new HashMap<LoadListener, CacheManager.CacheResult>();
+
+ /**
+ * Package level class to be used while creating a cache entry.
+ */
+ static class CacheCreateData {
+ LoadListener mListener;
+ String mUrl;
+ String mMimeType;
+ int mStatusCode;
+ long mPostId;
+ Headers mHeaders;
+ }
+
+ /**
+ * Package level class to be used while saving a cache entry.
+ */
+ static class CacheSaveData {
+ LoadListener mListener;
+ String mUrl;
+ long mPostId;
+ }
+
+ /**
+ * Package level class to be used while updating a cache entry's encoding.
+ */
+ static class CacheEncoding {
+ LoadListener mListener;
+ String mEncoding;
+ }
+
+ /**
+ * Package level class to be used while appending data to a cache entry.
+ */
+ static class CacheData {
+ LoadListener mListener;
+ ByteArrayBuilder.Chunk mChunk;
+ }
+
+ static synchronized WebViewWorker getHandler() {
+ if (sWorkerHandler == null) {
+ HandlerThread thread = new HandlerThread(THREAD_NAME,
+ android.os.Process.THREAD_PRIORITY_DEFAULT
+ + android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
+ thread.start();
+ sWorkerHandler = new WebViewWorker(thread.getLooper());
+ }
+ return sWorkerHandler;
+ }
+
+ private WebViewWorker(Looper looper) {
+ super(looper);
+ }
+
+ // trigger transaction once a minute
+ private static final int CACHE_TRANSACTION_TICKER_INTERVAL = 60 * 1000;
+
+ private static boolean mCacheTickersBlocked = true;
+
+ // message ids
+ static final int MSG_ADD_STREAMLOADER = 101;
+ static final int MSG_ADD_HTTPLOADER = 102;
+ static final int MSG_CREATE_CACHE = 103;
+ static final int MSG_UPDATE_CACHE_ENCODING = 104;
+ static final int MSG_APPEND_CACHE = 105;
+ static final int MSG_SAVE_CACHE = 106;
+ static final int MSG_REMOVE_CACHE = 107;
+ static final int MSG_TRIM_CACHE = 108;
+ static final int MSG_CLEAR_CACHE = 109;
+ static final int MSG_CACHE_TRANSACTION_TICKER = 110;
+ static final int MSG_PAUSE_CACHE_TRANSACTION = 111;
+ static final int MSG_RESUME_CACHE_TRANSACTION = 112;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_ADD_STREAMLOADER: {
+ StreamLoader loader = (StreamLoader) msg.obj;
+ loader.load();
+ break;
+ }
+ case MSG_ADD_HTTPLOADER: {
+ FrameLoader loader = (FrameLoader) msg.obj;
+ loader.handleHTTPLoad();
+ break;
+ }
+ case MSG_CREATE_CACHE: {
+ CacheCreateData data = (CacheCreateData) msg.obj;
+ CacheManager.CacheResult cache = CacheManager.createCacheFile(
+ data.mUrl, data.mStatusCode, data.mHeaders,
+ data.mMimeType, data.mPostId, false);
+ if (cache != null) {
+ mCacheResultMap.put(data.mListener, cache);
+ } else {
+ mCacheResultMap.remove(data.mListener);
+ }
+ break;
+ }
+ case MSG_UPDATE_CACHE_ENCODING: {
+ CacheEncoding data = (CacheEncoding) msg.obj;
+ CacheManager.CacheResult cache = mCacheResultMap
+ .get(data.mListener);
+ if (cache != null) {
+ cache.encoding = data.mEncoding;
+ }
+ break;
+ }
+ case MSG_APPEND_CACHE: {
+ CacheData data = (CacheData) msg.obj;
+ CacheManager.CacheResult cache = mCacheResultMap
+ .get(data.mListener);
+ if (cache != null) {
+ cache.contentLength += data.mChunk.mLength;
+ if (cache.contentLength > CacheManager.CACHE_MAX_SIZE) {
+ CacheManager.cleanupCacheFile(cache);
+ mCacheResultMap.remove(data.mListener);
+ } else {
+ try {
+ cache.outStream.write(data.mChunk.mArray, 0,
+ data.mChunk.mLength);
+ } catch (IOException e) {
+ CacheManager.cleanupCacheFile(cache);
+ mCacheResultMap.remove(data.mListener);
+ }
+ }
+ }
+ data.mChunk.release();
+ break;
+ }
+ case MSG_SAVE_CACHE: {
+ CacheSaveData data = (CacheSaveData) msg.obj;
+ CacheManager.CacheResult cache = mCacheResultMap
+ .get(data.mListener);
+ if (cache != null) {
+ CacheManager.saveCacheFile(data.mUrl, data.mPostId, cache);
+ mCacheResultMap.remove(data.mListener);
+ }
+ break;
+ }
+ case MSG_REMOVE_CACHE: {
+ LoadListener listener = (LoadListener) msg.obj;
+ CacheManager.CacheResult cache = mCacheResultMap.get(listener);
+ if (cache != null) {
+ CacheManager.cleanupCacheFile(cache);
+ mCacheResultMap.remove(listener);
+ }
+ break;
+ }
+ case MSG_TRIM_CACHE: {
+ CacheManager.trimCacheIfNeeded();
+ break;
+ }
+ case MSG_CLEAR_CACHE: {
+ CacheManager.clearCache();
+ break;
+ }
+ case MSG_CACHE_TRANSACTION_TICKER: {
+ if (!mCacheTickersBlocked) {
+ CacheManager.endTransaction();
+ CacheManager.startTransaction();
+ sendEmptyMessageDelayed(MSG_CACHE_TRANSACTION_TICKER,
+ CACHE_TRANSACTION_TICKER_INTERVAL);
+ }
+ break;
+ }
+ case MSG_PAUSE_CACHE_TRANSACTION: {
+ if (CacheManager.disableTransaction()) {
+ mCacheTickersBlocked = true;
+ removeMessages(MSG_CACHE_TRANSACTION_TICKER);
+ }
+ break;
+ }
+ case MSG_RESUME_CACHE_TRANSACTION: {
+ if (CacheManager.enableTransaction()) {
+ mCacheTickersBlocked = false;
+ sendEmptyMessageDelayed(MSG_CACHE_TRANSACTION_TICKER,
+ CACHE_TRANSACTION_TICKER_INTERVAL);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 79abd4b..9cc8bd5 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -547,9 +547,10 @@
final int groupPos = posMetadata.position.groupPos;
final int groupFlatPos = posMetadata.position.flatListPos;
-
- smoothScrollToPosition(groupFlatPos + mAdapter.getChildrenCount(groupPos),
- groupFlatPos);
+
+ final int shiftedGroupPosition = groupFlatPos + getHeaderViewsCount();
+ smoothScrollToPosition(shiftedGroupPosition + mAdapter.getChildrenCount(groupPos),
+ shiftedGroupPosition);
}
returnValue = true;
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 394ce0a..35ea0cc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2276,6 +2276,6 @@
<!-- Strings for car mode notification -->
<!-- Shown when car mode is enabled -->
<string name="car_mode_disable_notification_title">Car mode enabled</string>
- <string name="car_mode_disable_notification_message">Select to disable car mode.</string>
+ <string name="car_mode_disable_notification_message">Select to exit car mode.</string>
</resources>
diff --git a/mms-common/java/com/android/mmscommon/mms/pdu/PduPersister.java b/mms-common/java/com/android/mmscommon/mms/pdu/PduPersister.java
index 46f28c7..d92f0e1 100644
--- a/mms-common/java/com/android/mmscommon/mms/pdu/PduPersister.java
+++ b/mms-common/java/com/android/mmscommon/mms/pdu/PduPersister.java
@@ -1145,6 +1145,10 @@
}
}
+ // mark "read" and "seen"
+ values.put(Mms.READ, 0);
+ values.put(Mms.SEEN, 0);
+
Uri res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
if (res == null) {
throw new MmsException("persist() failed: return null.");
diff --git a/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java b/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java
index 87e4758..cfc9231 100644
--- a/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java
+++ b/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java
@@ -51,37 +51,6 @@
private static final boolean DEBUG = true;
private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
-// public static final Pattern EMAIL_ADDRESS
-// = Pattern.compile(
-// "[a-zA-Z0-9\\+\\.\\_\\%\\-]{1,256}" +
-// "\\@" +
-// "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
-// "(" +
-// "\\." +
-// "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
-// ")+"
-// );
-//
-// /**
-// * This pattern is intended for searching for things that look like they
-// * might be phone numbers in arbitrary text, not for validating whether
-// * something is in fact a phone number. It will miss many things that
-// * are legitimate phone numbers.
-// *
-// * <p> The pattern matches the following:
-// * <ul>
-// * <li>Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes
-// * may follow.
-// * <li>Optionally, sets of digits in parentheses, separated by spaces, dots, or dashes.
-// * <li>A string starting and ending with a digit, containing digits, spaces, dots, and/or dashes.
-// * </ul>
-// */
-// public static final Pattern PHONE
-// = Pattern.compile( // sdd = space, dot, or dash
-// "(\\+[0-9]+[\\- \\.]*)?" // +<digits><sdd>*
-// + "(\\([0-9]+\\)[\\- \\.]*)?" // (<digits>)<sdd>*
-// + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit>
-
// Constructor
public TelephonyProvider() {
}
@@ -136,6 +105,12 @@
public static final String READ = "read";
/**
+ * Indicates whether this message has been seen by the user. The "seen" flag will be
+ * used to figure out whether we need to throw up a statusbar notification or not.
+ */
+ public static final String SEEN = "seen";
+
+ /**
* The TP-Status value for the message, or -1 if no status has
* been received
*/
@@ -706,6 +681,12 @@
public static final String READ = "read";
/**
+ * Indicates whether this message has been seen by the user. The "seen" flag will be
+ * used to figure out whether we need to throw up a statusbar notification or not.
+ */
+ public static final String SEEN = "seen";
+
+ /**
* The Message-ID of the message.
* <P>Type: TEXT</P>
*/
@@ -1157,6 +1138,7 @@
* <P>Type: INTEGER</P>
*/
public static final String READ = "read";
+
/**
* The snippet of the latest message in the thread.
* <P>Type: TEXT</P>
@@ -1697,6 +1679,13 @@
*/
public static final String LAST_TRY = "last_try";
}
+
+ public static final class WordsTable {
+ public static final String ID = "_id";
+ public static final String SOURCE_ROW_ID = "source_id";
+ public static final String TABLE_ID = "table_to_use";
+ public static final String INDEXED_TEXT = "index_text";
+ }
}
public static final class Carriers implements BaseColumns {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a404ec5..1840ecc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1860,11 +1860,16 @@
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
- if (app != null &&
- (!knownToBeDead || app.thread == null) && app.pid > 0) {
- return app;
+ if (app != null && app.pid > 0) {
+ if (!knownToBeDead || app.thread == null) {
+ return app;
+ } else {
+ // An application record is attached to a previous process,
+ // clean it up now.
+ handleAppDiedLocked(app, true);
+ }
}
-
+
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
@@ -4588,7 +4593,9 @@
mProcDeaths[0]++;
- if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
+ // Clean up already done if the process has been re-started.
+ if (app.pid == pid && app.thread != null &&
+ app.thread.asBinder() == thread.asBinder()) {
Log.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died.");
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
@@ -4636,6 +4643,11 @@
scheduleAppGcsLocked();
}
}
+ } else if (app.pid != pid) {
+ // A new process has already been started.
+ Log.i(TAG, "Process " + app.processName + " (pid " + pid
+ + ") has died and restarted (pid " + app.pid + ").");
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
} else if (DEBUG_PROCESSES) {
Log.d(TAG, "Received spurious death notification for thread "
+ thread.asBinder());
@@ -5479,6 +5491,8 @@
finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
br.resultExtras, br.resultAbort, true);
scheduleBroadcastsLocked();
+ // We need to reset the state if we fails to start the receiver.
+ br.state = BroadcastRecord.IDLE;
}
}
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index 485e45c..f093598 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -3,7 +3,11 @@
import com.google.android.collect.Lists;
import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
import android.accounts.OnAccountsUpdateListener;
+import android.accounts.OperationCanceledException;
import android.accounts.Account;
import android.content.ContextWrapper;
import android.content.ContentResolver;
@@ -16,8 +20,13 @@
import android.net.Uri;
import android.os.Handler;
-import java.util.List;
import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.List;
+
/**
* A mock context which prevents its users from talking to the rest of the device while
@@ -105,7 +114,58 @@
public Account[] getAccounts() {
return new Account[]{};
}
+
+ public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
+ final String type, final String[] features,
+ AccountManagerCallback<Account[]> callback, Handler handler) {
+ return new MockAccountManagerFuture<Account[]>(new Account[0]);
+ }
+
+ public String blockingGetAuthToken(Account account, String authTokenType,
+ boolean notifyAuthFailure)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return null;
+ }
+
+
+ /**
+ * A very simple AccountManagerFuture class
+ * that returns what ever was passed in
+ */
+ private class MockAccountManagerFuture<T>
+ implements AccountManagerFuture<T> {
+
+ T mResult;
+
+ public MockAccountManagerFuture(T result) {
+ mResult = result;
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+
+ public boolean isDone() {
+ return true;
+ }
+
+ public T getResult()
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return mResult;
+ }
+
+ public T getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return getResult();
+ }
+ }
+
}
+
@Override
public File getFilesDir() {
return new File("/dev/null");
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index c3627bb..7f3ef2d 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -26,6 +26,7 @@
--time-out-ms (default is 8000 millis) for each test
--adb-options="-e" passes option string to adb
--results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
+ --js-engine the JavaScript engine currently in use, determines which set of Android-specific expected results we should use, should be 'jsc' or 'v8'
"""
import logging
@@ -186,6 +187,16 @@
run_layout_test_cmd_postfix = " -e path \"" + path + "\" -e timeout " + timeout_ms
if options.rebaseline:
run_layout_test_cmd_postfix += " -e rebaseline true"
+
+ # If the JS engine is not specified on the command line, try reading the
+ # JS_ENGINE environment variable, which is used by the build system in
+ # external/webkit/Android.mk.
+ js_engine = options.js_engine
+ if not js_engine:
+ js_engine = os.environ['JS_ENGINE']
+ if js_engine:
+ run_layout_test_cmd_postfix += " -e jsengine " + js_engine
+
run_layout_test_cmd_postfix += " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
# Call LayoutTestsAutoTest::startLayoutTests.
@@ -297,6 +308,9 @@
default=None,
dest="ref_directory",
help="directory where reference results are stored.")
+ option_parser.add_option("", "--js-engine",
+ default=None,
+ help="The JavaScript engine currently in use, which determines which set of Android-specific expected results we should use. Should be 'jsc' or 'v8'.");
options, args = option_parser.parse_args();
main(options, args)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 6ceb0f9..191b5e9 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -84,7 +84,6 @@
// This first block of tests are for HTML5 features, for which Android
// should pass all tests. They are skipped only temporarily.
// TODO: Fix these failing tests and remove them from this list.
- ignoreResultList.add("fast/dom/Geolocation/callback-exception.html"); // exception output incorrect with V8
ignoreResultList.add("http/tests/appcache/auth.html"); // file not found
ignoreResultList.add("http/tests/appcache/deferred-events.html"); // file not found
ignoreResultList.add("http/tests/appcache/deferred-events-delete-while-raising.html"); // file not found
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
index 539d551..e058f32 100755
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
@@ -79,14 +79,17 @@
mSaveImagePath = (String) icicle.get("saveimage");
+ mJsEngine = (String) icicle.get("jsengine");
+
super.onCreate(icicle);
}
- public String mTestPath = null;
- public String mSaveImagePath = null;
- public int mTimeoutInMillis = 0;
- public int mDelay = 0;
- public boolean mRebaseline = false;
- public boolean mLogtime = false;
- public boolean mGetDrawTime = false;
+ public String mTestPath;
+ public String mSaveImagePath;
+ public int mTimeoutInMillis;
+ public int mDelay;
+ public boolean mRebaseline;
+ public boolean mLogtime;
+ public boolean mGetDrawTime;
+ public String mJsEngine;
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 634d683..d9ec3fa 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -147,6 +147,9 @@
private MyTestRecorder mResultRecorder;
private Vector<String> mTestList;
private boolean mRebaselineResults;
+ // The JavaScript engine currently in use. This determines which set of Android-specific
+ // expected test results we use.
+ private String mJsEngine;
private String mTestPathPrefix;
private boolean mFinished;
@@ -214,14 +217,24 @@
return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
}
+ // Gets the file which contains WebKit's expected results for this test.
private String getExpectedResultFile(String test) {
+ // The generic result is at <path>/<name>-expected.txt
+ // First try the Android-specific result at
+ // platform/android-<js-engine>/<path>/<name>-expected.txt
int pos = test.lastIndexOf('.');
- if(pos == -1)
+ if (pos == -1)
return null;
- String shortName = test.substring(0, pos);
- return shortName + "-expected.txt";
+ String genericExpectedResult = test.substring(0, pos) + "-expected.txt";
+ String androidExpectedResultsDir = "platform/android-" + mJsEngine + "/";
+ String androidExpectedResult =
+ genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_ROOT + androidExpectedResultsDir);
+ File f = new File(androidExpectedResult);
+ return f.exists() ? androidExpectedResult : genericExpectedResult;
}
+ // Gets the file which contains the actual results of running the test on
+ // Android, generated by a previous run which set a new baseline.
private String getAndroidExpectedResultFile(String expectedResultFile) {
return expectedResultFile.replaceFirst(LAYOUT_TESTS_ROOT, ANDROID_EXPECTED_RESULT_DIR);
}
@@ -282,8 +295,8 @@
});
String resultFile = getResultFile(test);
- if(resultFile == null) {
- //simply ignore this test
+ if (resultFile == null) {
+ // Simply ignore this test.
return;
}
if (mRebaselineResults) {
@@ -339,8 +352,10 @@
this.mTestList = new Vector<String>();
// Read settings
- this.mTestPathPrefix = (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getAbsolutePath();
- this.mRebaselineResults = runner.mRebaseline;
+ mTestPathPrefix = (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getAbsolutePath();
+ mRebaselineResults = runner.mRebaseline;
+ // JSC is the default JavaScript engine.
+ mJsEngine = runner.mJsEngine == null ? "jsc" : runner.mJsEngine;
int timeout = runner.mTimeoutInMillis;
if (timeout <= 0) {