summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/Activity.java30
-rw-r--r--core/java/android/app/ActivityManager.java8
-rw-r--r--core/java/android/app/ActivityManagerNative.java23
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/webkit/BrowserFrame.java11
-rw-r--r--core/java/android/webkit/WebSettings.java55
-rw-r--r--core/java/android/webkit/WebViewClassic.java12
-rw-r--r--core/java/android/webkit/WebViewDatabase.java596
-rw-r--r--core/java/android/webkit/WebViewDatabaseClassic.java624
-rw-r--r--core/java/android/webkit/WebViewFactoryProvider.java19
-rw-r--r--core/java/android/widget/RemoteViews.java4
-rw-r--r--media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java21
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml2
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java82
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java26
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java45
19 files changed, 963 insertions, 629 deletions
diff --git a/api/current.txt b/api/current.txt
index 882503d..9303937 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2601,6 +2601,7 @@ package android.app {
method public void finish();
method public void finishActivity(int);
method public void finishActivityFromChild(android.app.Activity, int);
+ method public void finishAffinity();
method public void finishFromChild(android.app.Activity);
method public android.app.ActionBar getActionBar();
method public final android.app.Application getApplication();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 35bc7ff..4add7f4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4093,6 +4093,36 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Finish this activity as well as all activities immediately below it
+ * in the current task that have the same affinity. This is typically
+ * used when an application can be launched on to another task (such as
+ * from an ACTION_VIEW of a content type it understands) and the user
+ * has used the up navigation to switch out of the current task and in
+ * to its own task. In this case, if the user has navigated down into
+ * any other activities of the second application, all of those should
+ * be removed from the original task as part of the task switch.
+ *
+ * <p>Note that this finish does <em>not</em> allow you to deliver results
+ * to the previous activity, and an exception will be thrown if you are trying
+ * to do so.</p>
+ */
+ public void finishAffinity() {
+ if (mParent != null) {
+ throw new IllegalStateException("Can not be called from an embedded activity");
+ }
+ if (mResultCode != RESULT_CANCELED || mResultData != null) {
+ throw new IllegalStateException("Can not be called to deliver a result");
+ }
+ try {
+ if (ActivityManagerNative.getDefault().finishActivityAffinity(mToken)) {
+ mFinished = true;
+ }
+ } catch (RemoteException e) {
+ // Empty
+ }
+ }
+
+ /**
* This is called when a child activity of this one calls its
* {@link #finish} method. The default implementation simply calls
* finish() on this activity (the parent), finishing the entire group.
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7dce2d3..7746ca9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1687,6 +1687,8 @@ public class ActivityManager {
return DisplayMetrics.DENSITY_MEDIUM;
case DisplayMetrics.DENSITY_MEDIUM:
return DisplayMetrics.DENSITY_HIGH;
+ case DisplayMetrics.DENSITY_TV:
+ return DisplayMetrics.DENSITY_XHIGH;
case DisplayMetrics.DENSITY_HIGH:
return DisplayMetrics.DENSITY_XHIGH;
case DisplayMetrics.DENSITY_XHIGH:
@@ -1696,7 +1698,7 @@ public class ActivityManager {
default:
// The density is some abnormal value. Return some other
// abnormal value that is a reasonable scaling of it.
- return (int)(density*1.5f);
+ return (int)((density*1.5f)+.5f);
}
}
@@ -1723,6 +1725,8 @@ public class ActivityManager {
return (size * DisplayMetrics.DENSITY_MEDIUM) / DisplayMetrics.DENSITY_LOW;
case DisplayMetrics.DENSITY_MEDIUM:
return (size * DisplayMetrics.DENSITY_HIGH) / DisplayMetrics.DENSITY_MEDIUM;
+ case DisplayMetrics.DENSITY_TV:
+ return (size * DisplayMetrics.DENSITY_XHIGH) / DisplayMetrics.DENSITY_HIGH;
case DisplayMetrics.DENSITY_HIGH:
return (size * DisplayMetrics.DENSITY_XHIGH) / DisplayMetrics.DENSITY_HIGH;
case DisplayMetrics.DENSITY_XHIGH:
@@ -1732,7 +1736,7 @@ public class ActivityManager {
default:
// The density is some abnormal value. Return some other
// abnormal value that is a reasonable scaling of it.
- return (int)(size*1.5f);
+ return (int)((size*1.5f) + .5f);
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7e1589f..2f2918d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -218,7 +218,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeInt(result ? 1 : 0);
return true;
}
-
+
case FINISH_ACTIVITY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -243,6 +243,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case FINISH_ACTIVITY_AFFINITY_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ boolean res = finishActivityAffinity(token);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
case WILL_ACTIVITY_BE_VISIBLE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -1866,6 +1875,18 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+ public boolean finishActivityAffinity(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(FINISH_ACTIVITY_AFFINITY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public boolean willActivityBeVisible(IBinder token) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3fc2280..a2c7fa4 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -72,6 +72,7 @@ public interface IActivityManager extends IInterface {
public boolean finishActivity(IBinder token, int code, Intent data)
throws RemoteException;
public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
+ public boolean finishActivityAffinity(IBinder token) throws RemoteException;
public boolean willActivityBeVisible(IBinder token) throws RemoteException;
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter,
@@ -590,4 +591,5 @@ public interface IActivityManager extends IInterface {
int TARGET_TASK_AFFINITY_MATCHES_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+145;
int NAVIGATE_UP_TO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+146;
int SET_LOCK_SCREEN_SHOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+147;
+ int FINISH_ACTIVITY_AFFINITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+148;
}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 7b6b54c..c169de4 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -72,7 +72,7 @@ class BrowserFrame extends Handler {
private final CallbackProxy mCallbackProxy;
private final WebSettingsClassic mSettings;
private final Context mContext;
- private final WebViewDatabase mDatabase;
+ private final WebViewDatabaseClassic mDatabase;
private final WebViewCore mWebViewCore;
/* package */ boolean mLoadInitFromJava;
private int mLoadType;
@@ -241,7 +241,7 @@ class BrowserFrame extends Handler {
mSettings = settings;
mContext = context;
mCallbackProxy = proxy;
- mDatabase = WebViewDatabase.getInstance(appContext);
+ mDatabase = WebViewDatabaseClassic.getInstance(appContext);
mWebViewCore = w;
mSearchBox = new SearchBoxImpl(mWebViewCore, mCallbackProxy);
@@ -496,8 +496,8 @@ class BrowserFrame extends Handler {
if (item != null) {
WebAddress uri = new WebAddress(item.getUrl());
String schemePlusHost = uri.getScheme() + uri.getHost();
- String[] up =
- mDatabase.getUsernamePassword(schemePlusHost);
+ String[] up = mDatabase.getUsernamePassword(
+ schemePlusHost);
if (up != null && up[0] != null) {
setUsernamePassword(up[0], up[1]);
}
@@ -809,8 +809,7 @@ class BrowserFrame extends Handler {
// non-null username implies that user has
// chosen to save password, so update the
// recorded password
- mDatabase.setUsernamePassword(
- schemePlusHost, username, password);
+ mDatabase.setUsernamePassword(schemePlusHost, username, password);
}
} else {
// CallbackProxy will handle creating the resume
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 901372b..fa3cb20 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -848,25 +848,37 @@ public abstract class WebSettings {
}
/**
- * Configures scripting (such as XmlHttpRequest) access from file scheme URLs
- * to any origin. Note, calling this method with a true argument value also
- * implies calling setAllowFileAccessFromFileURLs with a true. The default
- * value is false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
- * and higher and true otherwise.
+ * Sets whether JavaScript running in the context of a file scheme URL
+ * should be allowed to access content from any origin. This includes
+ * access to content from other file scheme URLs. See
+ * {@link #setAllowFileAccessFromFileURLs}. To enable the most restrictive,
+ * and therefore secure policy, this setting should be disabled.
+ * <p>
+ * The default value is true for API level
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
+ * and false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
+ * and above.
*
- * @param flag true if the WebView should allow scripting access from file
- * scheme URLs to any origin
+ * @param flag whether JavaScript running in the context of a file scheme
+ * URL should be allowed to access content from any origin
*/
public abstract void setAllowUniversalAccessFromFileURLs(boolean flag);
/**
- * Configures scripting (such as XmlHttpRequest) access from file scheme URLs
- * to file origin. The default value is false for API level
- * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} and higher and true
- * otherwise.
+ * Sets whether JavaScript running in the context of a file scheme URL
+ * should be allowed to access content from other file scheme URLs. To
+ * enable the most restrictive, and therefore secure policy, this setting
+ * should be disabled. Note that the value of this setting is ignored if
+ * the value of {@link #getAllowUniversalAccessFromFileURLs} is true.
+ * <p>
+ * The default value is true for API level
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
+ * and false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
+ * and above.
*
- * @param flag true if the WebView should allow scripting access from file
- * scheme URLs to file origin
+ * @param flag whether JavaScript running in the context of a file scheme
+ * URL should be allowed to access content from other file
+ * scheme URLs
*/
public abstract void setAllowFileAccessFromFileURLs(boolean flag);
@@ -1028,21 +1040,22 @@ public abstract class WebSettings {
}
/**
- * Gets whether scripting access {see @setAllowUniversalAccessFromFileURLs} from
- * file URLs to any origin is enabled.
+ * Gets whether JavaScript running in the context of a file scheme URL can
+ * access content from any origin. This includes access to content from
+ * other file scheme URLs.
*
- * @return true if the WebView allows scripting access from file scheme requests
- * to any origin
+ * @return whether JavaScript running in the context of a file scheme URL
+ * can access content from any origin
* @see #setAllowUniversalAccessFromFileURLs
*/
public abstract boolean getAllowUniversalAccessFromFileURLs();
/**
- * Gets whether scripting access {see @setAllowFileAccessFromFileURLs} from file
- * URLs to file origin is enabled.
+ * Gets whether JavaScript running in the context of a file scheme URL can
+ * access content from other file scheme URLs.
*
- * @return true if the WebView allows scripting access from file scheme requests
- * to file origin
+ * @return whether JavaScript running in the context of a file scheme URL
+ * can access content from other file scheme URLs
* @see #setAllowFileAccessFromFileURLs
*/
public abstract boolean getAllowFileAccessFromFileURLs();
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 9cf0d54..ca17d31 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -701,7 +701,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// A final CallbackProxy shared by WebViewCore and BrowserFrame.
private CallbackProxy mCallbackProxy;
- private WebViewDatabase mDatabase;
+ private WebViewDatabaseClassic mDatabase;
// SSL certificate for the main top-level page (if secure)
private SslCertificate mCertificate;
@@ -1230,7 +1230,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
mViewManager = new ViewManager(this);
L10nUtils.setApplicationContext(context.getApplicationContext());
mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces);
- mDatabase = WebViewDatabase.getInstance(context);
+ mDatabase = WebViewDatabaseClassic.getInstance(context);
mScroller = new OverScroller(context, null, 0, 0, false); //TODO Use OverScroller's flywheel
mZoomManager = new ZoomManager(this, mCallbackProxy);
@@ -1294,6 +1294,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
public WebStorage getWebStorage() {
return WebStorageClassic.getInstance();
}
+
+ @Override
+ public WebViewDatabase getWebViewDatabase(Context context) {
+ return WebViewDatabaseClassic.getInstance(context);
+ }
}
private void onHandleUiEvent(MotionEvent event, int eventType, int flags) {
@@ -7192,8 +7197,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
break;
}
case NEVER_REMEMBER_PASSWORD: {
- mDatabase.setUsernamePassword(
- msg.getData().getString("host"), null, null);
+ mDatabase.setUsernamePassword(msg.getData().getString("host"), null, null);
((Message) msg.obj).sendToTarget();
break;
}
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 6c35f19..9d10d67 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -16,611 +16,79 @@
package android.webkit;
-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;
-
-import android.content.ContentValues;
import android.content.Context;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteStatement;
-import android.util.Log;
+/**
+ * This class allows developers to determine whether any WebView used in the
+ * application has stored any of the following types of browsing data and
+ * to clear any such stored data for all WebViews in the application.
+ * <ul>
+ * <li>Username/password pairs entered into web forms</li>
+ * <li>HTTP authentication username/password pairs</li>
+ * <li>Data entered into text fields (e.g. for autocomplete suggestions)</li>
+ * </ul>
+ */
public class WebViewDatabase {
- private static final String DATABASE_FILE = "webview.db";
- private static final String CACHE_DATABASE_FILE = "webviewCache.db";
-
- // log tag
+ // TODO: deprecate/hide this.
protected static final String LOGTAG = "webviewdatabase";
- private static final int DATABASE_VERSION = 11;
- // 2 -> 3 Modified Cache table to allow cache of redirects
- // 3 -> 4 Added Oma-Downloads table
- // 4 -> 5 Modified Cache table to support persistent contentLength
- // 5 -> 4 Removed Oma-Downoads table
- // 5 -> 6 Add INDEX for cache table
- // 6 -> 7 Change cache localPath from int to String
- // 7 -> 8 Move cache to its own db
- // 8 -> 9 Store both scheme and host when storing passwords
- // 9 -> 10 Update httpauth table UNIQUE
- // 10 -> 11 Drop cookies and cache now managed by the chromium stack,
- // and update the form data table to use the new format
- // implemented for b/5265606.
-
- private static WebViewDatabase mInstance = null;
-
- private static SQLiteDatabase mDatabase = null;
-
- // synchronize locks
- private final Object mPasswordLock = new Object();
- private final Object mFormLock = new Object();
- private final Object mHttpAuthLock = new Object();
-
- private static final String mTableNames[] = {
- "password", "formurl", "formdata", "httpauth"
- };
-
- // Table ids (they are index to mTableNames)
- private static final int TABLE_PASSWORD_ID = 0;
- private static final int TABLE_FORMURL_ID = 1;
- private static final int TABLE_FORMDATA_ID = 2;
- private static final int TABLE_HTTPAUTH_ID = 3;
-
- // column id strings for "_id" which can be used by any table
- private static final String ID_COL = "_id";
-
- private static final String[] ID_PROJECTION = new String[] {
- "_id"
- };
-
- // column id strings for "password" table
- private static final String PASSWORD_HOST_COL = "host";
- private static final String PASSWORD_USERNAME_COL = "username";
- private static final String PASSWORD_PASSWORD_COL = "password";
-
- // column id strings for "formurl" table
- private static final String FORMURL_URL_COL = "url";
-
- // column id strings for "formdata" table
- private static final String FORMDATA_URLID_COL = "urlid";
- private static final String FORMDATA_NAME_COL = "name";
- private static final String FORMDATA_VALUE_COL = "value";
-
- // column id strings for "httpauth" table
- private static final String HTTPAUTH_HOST_COL = "host";
- private static final String HTTPAUTH_REALM_COL = "realm";
- private static final String HTTPAUTH_USERNAME_COL = "username";
- private static final String HTTPAUTH_PASSWORD_COL = "password";
-
- // Initially true until the background thread completes.
- private boolean mInitialized = false;
-
- private WebViewDatabase(final Context context) {
- new Thread() {
- @Override
- public void run() {
- init(context);
- }
- }.start();
-
- // Singleton only, use getInstance()
- }
-
- public static synchronized WebViewDatabase getInstance(Context context) {
- if (mInstance == null) {
- mInstance = new WebViewDatabase(context);
- }
- return mInstance;
- }
-
- private synchronized void init(Context context) {
- if (mInitialized) {
- return;
- }
-
- initDatabase(context);
- // Before using the Chromium HTTP stack, we stored the WebKit cache in
- // our own DB. Clean up the DB file if it's still around.
- context.deleteDatabase(CACHE_DATABASE_FILE);
-
- // Thread done, notify.
- mInitialized = true;
- notify();
- }
-
- private void initDatabase(Context context) {
- try {
- mDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0, null);
- } catch (SQLiteException e) {
- // try again by deleting the old db and create a new one
- if (context.deleteDatabase(DATABASE_FILE)) {
- mDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0,
- null);
- }
- }
-
- // mDatabase should not be null,
- // the only case is RequestAPI test has problem to create db
- if (mDatabase == null) {
- mInitialized = true;
- notify();
- return;
- }
-
- if (mDatabase.getVersion() != DATABASE_VERSION) {
- mDatabase.beginTransactionNonExclusive();
- try {
- upgradeDatabase();
- mDatabase.setTransactionSuccessful();
- } finally {
- mDatabase.endTransaction();
- }
- }
- }
-
- private static void upgradeDatabase() {
- upgradeDatabaseToV10();
- upgradeDatabaseFromV10ToV11();
- // Add future database upgrade functions here, one version at a
- // time.
- mDatabase.setVersion(DATABASE_VERSION);
- }
-
- private static void upgradeDatabaseFromV10ToV11() {
- int oldVersion = mDatabase.getVersion();
-
- if (oldVersion >= 11) {
- // Nothing to do.
- return;
- }
-
- // Clear out old java stack cookies - this data is now stored in
- // a separate database managed by the Chrome stack.
- mDatabase.execSQL("DROP TABLE IF EXISTS cookies");
-
- // Likewise for the old cache table.
- mDatabase.execSQL("DROP TABLE IF EXISTS cache");
-
- // Update form autocomplete URLs to match new ICS formatting.
- Cursor c = mDatabase.query(mTableNames[TABLE_FORMURL_ID], null, null,
- null, null, null, null);
- while (c.moveToNext()) {
- String urlId = Long.toString(c.getLong(c.getColumnIndex(ID_COL)));
- String url = c.getString(c.getColumnIndex(FORMURL_URL_COL));
- ContentValues cv = new ContentValues(1);
- cv.put(FORMURL_URL_COL, WebTextView.urlForAutoCompleteData(url));
- mDatabase.update(mTableNames[TABLE_FORMURL_ID], cv, ID_COL + "=?",
- new String[] { urlId });
- }
- c.close();
- }
-
- private static void upgradeDatabaseToV10() {
- int oldVersion = mDatabase.getVersion();
-
- if (oldVersion >= 10) {
- // Nothing to do.
- return;
- }
-
- if (oldVersion != 0) {
- Log.i(LOGTAG, "Upgrading database from version "
- + oldVersion + " to "
- + DATABASE_VERSION + ", which will destroy old data");
- }
-
- if (9 == oldVersion) {
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_HTTPAUTH_ID]);
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
- + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
- + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
- + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
- + ") ON CONFLICT REPLACE);");
- return;
- }
-
- mDatabase.execSQL("DROP TABLE IF EXISTS cookies");
- mDatabase.execSQL("DROP TABLE IF EXISTS cache");
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_FORMURL_ID]);
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_FORMDATA_ID]);
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_HTTPAUTH_ID]);
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_PASSWORD_ID]);
-
- // formurl
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMURL_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, " + FORMURL_URL_COL
- + " TEXT" + ");");
-
- // formdata
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMDATA_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + FORMDATA_URLID_COL + " INTEGER, " + FORMDATA_NAME_COL
- + " TEXT, " + FORMDATA_VALUE_COL + " TEXT," + " UNIQUE ("
- + FORMDATA_URLID_COL + ", " + FORMDATA_NAME_COL + ", "
- + FORMDATA_VALUE_COL + ") ON CONFLICT IGNORE);");
-
- // httpauth
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
- + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
- + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
- + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
- + ") ON CONFLICT REPLACE);");
- // passwords
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL
- + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE ("
- + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL
- + ") ON CONFLICT REPLACE);");
- }
-
- // Wait for the background initialization thread to complete and check the
- // database creation status.
- private boolean checkInitialized() {
- synchronized (this) {
- while (!mInitialized) {
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG, "Caught exception while checking " +
- "initialization");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- }
- return mDatabase != null;
- }
-
- private boolean hasEntries(int tableId) {
- if (!checkInitialized()) {
- return false;
- }
-
- Cursor cursor = null;
- boolean ret = false;
- try {
- cursor = mDatabase.query(mTableNames[tableId], ID_PROJECTION,
- null, null, null, null, null);
- ret = cursor.moveToFirst() == true;
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "hasEntries", e);
- } finally {
- if (cursor != null) cursor.close();
- }
- return ret;
- }
-
- //
- // password functions
- //
-
/**
- * Set password. Tuple (PASSWORD_HOST_COL, PASSWORD_USERNAME_COL) is unique.
- *
- * @param schemePlusHost The scheme and host for the password
- * @param username The username for the password. If it is null, it means
- * password can't be saved.
- * @param password The password
+ * @hide Only for use by WebViewProvider implementations.
*/
- void setUsernamePassword(String schemePlusHost, String username,
- String password) {
- if (schemePlusHost == null || !checkInitialized()) {
- return;
- }
-
- synchronized (mPasswordLock) {
- final ContentValues c = new ContentValues();
- c.put(PASSWORD_HOST_COL, schemePlusHost);
- c.put(PASSWORD_USERNAME_COL, username);
- c.put(PASSWORD_PASSWORD_COL, password);
- mDatabase.insert(mTableNames[TABLE_PASSWORD_ID], PASSWORD_HOST_COL,
- c);
- }
+ protected WebViewDatabase() {
}
- /**
- * Retrieve the username and password for a given host
- *
- * @param schemePlusHost The scheme and host which passwords applies to
- * @return String[] if found, String[0] is username, which can be null and
- * String[1] is password. Return null if it can't find anything.
- */
- String[] getUsernamePassword(String schemePlusHost) {
- if (schemePlusHost == null || !checkInitialized()) {
- return null;
- }
-
- final String[] columns = new String[] {
- PASSWORD_USERNAME_COL, PASSWORD_PASSWORD_COL
- };
- final String selection = "(" + PASSWORD_HOST_COL + " == ?)";
- synchronized (mPasswordLock) {
- String[] ret = null;
- Cursor cursor = null;
- try {
- cursor = mDatabase.query(mTableNames[TABLE_PASSWORD_ID],
- columns, selection, new String[] { schemePlusHost }, null,
- null, null);
- if (cursor.moveToFirst()) {
- ret = new String[2];
- ret[0] = cursor.getString(
- cursor.getColumnIndex(PASSWORD_USERNAME_COL));
- ret[1] = cursor.getString(
- cursor.getColumnIndex(PASSWORD_PASSWORD_COL));
- }
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "getUsernamePassword", e);
- } finally {
- if (cursor != null) cursor.close();
- }
- return ret;
- }
+ public static synchronized WebViewDatabase getInstance(Context context) {
+ return WebViewFactory.getProvider().getWebViewDatabase(context);
}
/**
- * Find out if there are any passwords saved.
+ * Gets whether there are any username/password combinations
+ * from web pages saved.
*
- * @return TRUE if there is passwords saved
+ * @return true if there are any username/passwords used in web
+ * forms saved
*/
public boolean hasUsernamePassword() {
- synchronized (mPasswordLock) {
- return hasEntries(TABLE_PASSWORD_ID);
- }
+ throw new MustOverrideException();
}
/**
- * Clear password database
+ * Clears any username/password combinations saved from web forms.
*/
public void clearUsernamePassword() {
- if (!checkInitialized()) {
- return;
- }
-
- synchronized (mPasswordLock) {
- mDatabase.delete(mTableNames[TABLE_PASSWORD_ID], null, null);
- }
- }
-
- //
- // http authentication password functions
- //
-
- /**
- * Set HTTP authentication password. Tuple (HTTPAUTH_HOST_COL,
- * HTTPAUTH_REALM_COL, HTTPAUTH_USERNAME_COL) is unique.
- *
- * @param host The host for the password
- * @param realm The realm for the password
- * @param username The username for the password. If it is null, it means
- * password can't be saved.
- * @param password The password
- */
- void setHttpAuthUsernamePassword(String host, String realm, String username,
- String password) {
- if (host == null || realm == null || !checkInitialized()) {
- return;
- }
-
- synchronized (mHttpAuthLock) {
- final ContentValues c = new ContentValues();
- c.put(HTTPAUTH_HOST_COL, host);
- c.put(HTTPAUTH_REALM_COL, realm);
- c.put(HTTPAUTH_USERNAME_COL, username);
- c.put(HTTPAUTH_PASSWORD_COL, password);
- mDatabase.insert(mTableNames[TABLE_HTTPAUTH_ID], HTTPAUTH_HOST_COL,
- c);
- }
+ throw new MustOverrideException();
}
/**
- * Retrieve the HTTP authentication username and password for a given
- * host+realm pair
+ * Gets whether there are any HTTP authentication username/password combinations saved.
*
- * @param host The host the password applies to
- * @param realm The realm the password applies to
- * @return String[] if found, String[0] is username, which can be null and
- * String[1] is password. Return null if it can't find anything.
- */
- String[] getHttpAuthUsernamePassword(String host, String realm) {
- if (host == null || realm == null || !checkInitialized()){
- return null;
- }
-
- final String[] columns = new String[] {
- HTTPAUTH_USERNAME_COL, HTTPAUTH_PASSWORD_COL
- };
- final String selection = "(" + HTTPAUTH_HOST_COL + " == ?) AND ("
- + HTTPAUTH_REALM_COL + " == ?)";
- synchronized (mHttpAuthLock) {
- String[] ret = null;
- Cursor cursor = null;
- try {
- cursor = mDatabase.query(mTableNames[TABLE_HTTPAUTH_ID],
- columns, selection, new String[] { host, realm }, null,
- null, null);
- if (cursor.moveToFirst()) {
- ret = new String[2];
- ret[0] = cursor.getString(
- cursor.getColumnIndex(HTTPAUTH_USERNAME_COL));
- ret[1] = cursor.getString(
- cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL));
- }
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "getHttpAuthUsernamePassword", e);
- } finally {
- if (cursor != null) cursor.close();
- }
- return ret;
- }
- }
-
- /**
- * Find out if there are any HTTP authentication passwords saved.
- *
- * @return TRUE if there are passwords saved
+ * @return true if there are any HTTP authentication username/passwords saved
*/
public boolean hasHttpAuthUsernamePassword() {
- synchronized (mHttpAuthLock) {
- return hasEntries(TABLE_HTTPAUTH_ID);
- }
+ throw new MustOverrideException();
}
/**
- * Clear HTTP authentication password database
+ * Clears any HTTP authentication username/passwords that are saved.
*/
public void clearHttpAuthUsernamePassword() {
- if (!checkInitialized()) {
- return;
- }
-
- synchronized (mHttpAuthLock) {
- mDatabase.delete(mTableNames[TABLE_HTTPAUTH_ID], null, null);
- }
- }
-
- //
- // form data functions
- //
-
- /**
- * Set form data for a site. Tuple (FORMDATA_URLID_COL, FORMDATA_NAME_COL,
- * FORMDATA_VALUE_COL) is unique
- *
- * @param url The url of the site
- * @param formdata The form data in HashMap
- */
- void setFormData(String url, HashMap<String, String> formdata) {
- if (url == null || formdata == null || !checkInitialized()) {
- return;
- }
-
- final String selection = "(" + FORMURL_URL_COL + " == ?)";
- synchronized (mFormLock) {
- long urlid = -1;
- Cursor cursor = null;
- try {
- cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
- ID_PROJECTION, selection, new String[] { url }, null, null,
- null);
- if (cursor.moveToFirst()) {
- urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
- } else {
- ContentValues c = new ContentValues();
- c.put(FORMURL_URL_COL, url);
- urlid = mDatabase.insert(
- mTableNames[TABLE_FORMURL_ID], null, c);
- }
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "setFormData", e);
- } finally {
- if (cursor != null) cursor.close();
- }
- if (urlid >= 0) {
- Set<Entry<String, String>> set = formdata.entrySet();
- Iterator<Entry<String, String>> iter = set.iterator();
- ContentValues map = new ContentValues();
- map.put(FORMDATA_URLID_COL, urlid);
- while (iter.hasNext()) {
- Entry<String, String> entry = iter.next();
- map.put(FORMDATA_NAME_COL, entry.getKey());
- map.put(FORMDATA_VALUE_COL, entry.getValue());
- mDatabase.insert(mTableNames[TABLE_FORMDATA_ID], null, map);
- }
- }
- }
+ throw new MustOverrideException();
}
/**
- * Get all the values for a form entry with "name" in a given site
+ * Gets whether there is any previously-entered form data saved.
*
- * @param url The url of the site
- * @param name The name of the form entry
- * @return A list of values. Return empty list if nothing is found.
- */
- ArrayList<String> getFormData(String url, String name) {
- ArrayList<String> values = new ArrayList<String>();
- if (url == null || name == null || !checkInitialized()) {
- return values;
- }
-
- final String urlSelection = "(" + FORMURL_URL_COL + " == ?)";
- final String dataSelection = "(" + FORMDATA_URLID_COL + " == ?) AND ("
- + FORMDATA_NAME_COL + " == ?)";
- synchronized (mFormLock) {
- Cursor cursor = null;
- try {
- cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
- ID_PROJECTION, urlSelection, new String[] { url }, null,
- null, null);
- while (cursor.moveToNext()) {
- long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
- Cursor dataCursor = null;
- try {
- dataCursor = mDatabase.query(
- mTableNames[TABLE_FORMDATA_ID],
- new String[] { ID_COL, FORMDATA_VALUE_COL },
- dataSelection,
- new String[] { Long.toString(urlid), name },
- null, null, null);
- if (dataCursor.moveToFirst()) {
- int valueCol = dataCursor.getColumnIndex(
- FORMDATA_VALUE_COL);
- do {
- values.add(dataCursor.getString(valueCol));
- } while (dataCursor.moveToNext());
- }
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "getFormData dataCursor", e);
- } finally {
- if (dataCursor != null) dataCursor.close();
- }
- }
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "getFormData cursor", e);
- } finally {
- if (cursor != null) cursor.close();
- }
- return values;
- }
- }
-
- /**
- * Find out if there is form data saved.
- *
- * @return TRUE if there is form data in the database
+ * @return true if there is form data saved
*/
public boolean hasFormData() {
- synchronized (mFormLock) {
- return hasEntries(TABLE_FORMURL_ID);
- }
+ throw new MustOverrideException();
}
/**
- * Clear form database
+ * Clears any stored previously-entered form data.
*/
public void clearFormData() {
- if (!checkInitialized()) {
- return;
- }
-
- synchronized (mFormLock) {
- mDatabase.delete(mTableNames[TABLE_FORMURL_ID], null, null);
- mDatabase.delete(mTableNames[TABLE_FORMDATA_ID], null, null);
- }
+ throw new MustOverrideException();
}
}
diff --git a/core/java/android/webkit/WebViewDatabaseClassic.java b/core/java/android/webkit/WebViewDatabaseClassic.java
new file mode 100644
index 0000000..9b1d4cb
--- /dev/null
+++ b/core/java/android/webkit/WebViewDatabaseClassic.java
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2012 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.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.database.sqlite.SQLiteStatement;
+import android.util.Log;
+
+final class WebViewDatabaseClassic extends WebViewDatabase {
+ private static final String LOGTAG = "WebViewDatabaseClassic";
+ private static final String DATABASE_FILE = "webview.db";
+ private static final String CACHE_DATABASE_FILE = "webviewCache.db";
+
+ private static final int DATABASE_VERSION = 11;
+ // 2 -> 3 Modified Cache table to allow cache of redirects
+ // 3 -> 4 Added Oma-Downloads table
+ // 4 -> 5 Modified Cache table to support persistent contentLength
+ // 5 -> 4 Removed Oma-Downoads table
+ // 5 -> 6 Add INDEX for cache table
+ // 6 -> 7 Change cache localPath from int to String
+ // 7 -> 8 Move cache to its own db
+ // 8 -> 9 Store both scheme and host when storing passwords
+ // 9 -> 10 Update httpauth table UNIQUE
+ // 10 -> 11 Drop cookies and cache now managed by the chromium stack,
+ // and update the form data table to use the new format
+ // implemented for b/5265606.
+
+ private static WebViewDatabaseClassic sInstance = null;
+
+ private static SQLiteDatabase sDatabase = null;
+
+ // synchronize locks
+ private final Object mPasswordLock = new Object();
+ private final Object mFormLock = new Object();
+ private final Object mHttpAuthLock = new Object();
+
+ private static final String mTableNames[] = {
+ "password", "formurl", "formdata", "httpauth"
+ };
+
+ // Table ids (they are index to mTableNames)
+ private static final int TABLE_PASSWORD_ID = 0;
+ private static final int TABLE_FORMURL_ID = 1;
+ private static final int TABLE_FORMDATA_ID = 2;
+ private static final int TABLE_HTTPAUTH_ID = 3;
+
+ // column id strings for "_id" which can be used by any table
+ private static final String ID_COL = "_id";
+
+ private static final String[] ID_PROJECTION = new String[] {
+ "_id"
+ };
+
+ // column id strings for "password" table
+ private static final String PASSWORD_HOST_COL = "host";
+ private static final String PASSWORD_USERNAME_COL = "username";
+ private static final String PASSWORD_PASSWORD_COL = "password";
+
+ // column id strings for "formurl" table
+ private static final String FORMURL_URL_COL = "url";
+
+ // column id strings for "formdata" table
+ private static final String FORMDATA_URLID_COL = "urlid";
+ private static final String FORMDATA_NAME_COL = "name";
+ private static final String FORMDATA_VALUE_COL = "value";
+
+ // column id strings for "httpauth" table
+ private static final String HTTPAUTH_HOST_COL = "host";
+ private static final String HTTPAUTH_REALM_COL = "realm";
+ private static final String HTTPAUTH_USERNAME_COL = "username";
+ private static final String HTTPAUTH_PASSWORD_COL = "password";
+
+ // Initially true until the background thread completes.
+ private boolean mInitialized = false;
+
+ WebViewDatabaseClassic(final Context context) {
+ new Thread() {
+ @Override
+ public void run() {
+ init(context);
+ }
+ }.start();
+
+ // Singleton only, use getInstance()
+ }
+
+ public static synchronized WebViewDatabaseClassic getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new WebViewDatabaseClassic(context);
+ }
+ return sInstance;
+ }
+
+ private synchronized void init(Context context) {
+ if (mInitialized) {
+ return;
+ }
+
+ initDatabase(context);
+ // Before using the Chromium HTTP stack, we stored the WebKit cache in
+ // our own DB. Clean up the DB file if it's still around.
+ context.deleteDatabase(CACHE_DATABASE_FILE);
+
+ // Thread done, notify.
+ mInitialized = true;
+ notify();
+ }
+
+ private void initDatabase(Context context) {
+ try {
+ sDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0, null);
+ } catch (SQLiteException e) {
+ // try again by deleting the old db and create a new one
+ if (context.deleteDatabase(DATABASE_FILE)) {
+ sDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0,
+ null);
+ }
+ }
+
+ // sDatabase should not be null,
+ // the only case is RequestAPI test has problem to create db
+ if (sDatabase == null) {
+ mInitialized = true;
+ notify();
+ return;
+ }
+
+ if (sDatabase.getVersion() != DATABASE_VERSION) {
+ sDatabase.beginTransactionNonExclusive();
+ try {
+ upgradeDatabase();
+ sDatabase.setTransactionSuccessful();
+ } finally {
+ sDatabase.endTransaction();
+ }
+ }
+ }
+
+ private static void upgradeDatabase() {
+ upgradeDatabaseToV10();
+ upgradeDatabaseFromV10ToV11();
+ // Add future database upgrade functions here, one version at a
+ // time.
+ sDatabase.setVersion(DATABASE_VERSION);
+ }
+
+ private static void upgradeDatabaseFromV10ToV11() {
+ int oldVersion = sDatabase.getVersion();
+
+ if (oldVersion >= 11) {
+ // Nothing to do.
+ return;
+ }
+
+ // Clear out old java stack cookies - this data is now stored in
+ // a separate database managed by the Chrome stack.
+ sDatabase.execSQL("DROP TABLE IF EXISTS cookies");
+
+ // Likewise for the old cache table.
+ sDatabase.execSQL("DROP TABLE IF EXISTS cache");
+
+ // Update form autocomplete URLs to match new ICS formatting.
+ Cursor c = sDatabase.query(mTableNames[TABLE_FORMURL_ID], null, null,
+ null, null, null, null);
+ while (c.moveToNext()) {
+ String urlId = Long.toString(c.getLong(c.getColumnIndex(ID_COL)));
+ String url = c.getString(c.getColumnIndex(FORMURL_URL_COL));
+ ContentValues cv = new ContentValues(1);
+ cv.put(FORMURL_URL_COL, WebTextView.urlForAutoCompleteData(url));
+ sDatabase.update(mTableNames[TABLE_FORMURL_ID], cv, ID_COL + "=?",
+ new String[] { urlId });
+ }
+ c.close();
+ }
+
+ private static void upgradeDatabaseToV10() {
+ int oldVersion = sDatabase.getVersion();
+
+ if (oldVersion >= 10) {
+ // Nothing to do.
+ return;
+ }
+
+ if (oldVersion != 0) {
+ Log.i(LOGTAG, "Upgrading database from version "
+ + oldVersion + " to "
+ + DATABASE_VERSION + ", which will destroy old data");
+ }
+
+ if (9 == oldVersion) {
+ sDatabase.execSQL("DROP TABLE IF EXISTS "
+ + mTableNames[TABLE_HTTPAUTH_ID]);
+ sDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID]
+ + " (" + ID_COL + " INTEGER PRIMARY KEY, "
+ + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
+ + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
+ + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
+ + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
+ + ") ON CONFLICT REPLACE);");
+ return;
+ }
+
+ sDatabase.execSQL("DROP TABLE IF EXISTS cookies");
+ sDatabase.execSQL("DROP TABLE IF EXISTS cache");
+ sDatabase.execSQL("DROP TABLE IF EXISTS "
+ + mTableNames[TABLE_FORMURL_ID]);
+ sDatabase.execSQL("DROP TABLE IF EXISTS "
+ + mTableNames[TABLE_FORMDATA_ID]);
+ sDatabase.execSQL("DROP TABLE IF EXISTS "
+ + mTableNames[TABLE_HTTPAUTH_ID]);
+ sDatabase.execSQL("DROP TABLE IF EXISTS "
+ + mTableNames[TABLE_PASSWORD_ID]);
+
+ // formurl
+ sDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMURL_ID]
+ + " (" + ID_COL + " INTEGER PRIMARY KEY, " + FORMURL_URL_COL
+ + " TEXT" + ");");
+
+ // formdata
+ sDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMDATA_ID]
+ + " (" + ID_COL + " INTEGER PRIMARY KEY, "
+ + FORMDATA_URLID_COL + " INTEGER, " + FORMDATA_NAME_COL
+ + " TEXT, " + FORMDATA_VALUE_COL + " TEXT," + " UNIQUE ("
+ + FORMDATA_URLID_COL + ", " + FORMDATA_NAME_COL + ", "
+ + FORMDATA_VALUE_COL + ") ON CONFLICT IGNORE);");
+
+ // httpauth
+ sDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID]
+ + " (" + ID_COL + " INTEGER PRIMARY KEY, "
+ + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
+ + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
+ + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
+ + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
+ + ") ON CONFLICT REPLACE);");
+ // passwords
+ sDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID]
+ + " (" + ID_COL + " INTEGER PRIMARY KEY, "
+ + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL
+ + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE ("
+ + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL
+ + ") ON CONFLICT REPLACE);");
+ }
+
+ // Wait for the background initialization thread to complete and check the
+ // database creation status.
+ private boolean checkInitialized() {
+ synchronized (this) {
+ while (!mInitialized) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ Log.e(LOGTAG, "Caught exception while checking " +
+ "initialization");
+ Log.e(LOGTAG, Log.getStackTraceString(e));
+ }
+ }
+ }
+ return sDatabase != null;
+ }
+
+ private boolean hasEntries(int tableId) {
+ if (!checkInitialized()) {
+ return false;
+ }
+
+ Cursor cursor = null;
+ boolean ret = false;
+ try {
+ cursor = sDatabase.query(mTableNames[tableId], ID_PROJECTION,
+ null, null, null, null, null);
+ ret = cursor.moveToFirst() == true;
+ } catch (IllegalStateException e) {
+ Log.e(LOGTAG, "hasEntries", e);
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ return ret;
+ }
+
+ //
+ // password functions
+ //
+
+ /**
+ * Set password. Tuple (PASSWORD_HOST_COL, PASSWORD_USERNAME_COL) is unique.
+ *
+ * @param schemePlusHost The scheme and host for the password
+ * @param username The username for the password. If it is null, it means
+ * password can't be saved.
+ * @param password The password
+ */
+ void setUsernamePassword(String schemePlusHost, String username,
+ String password) {
+ if (schemePlusHost == null || !checkInitialized()) {
+ return;
+ }
+
+ synchronized (mPasswordLock) {
+ final ContentValues c = new ContentValues();
+ c.put(PASSWORD_HOST_COL, schemePlusHost);
+ c.put(PASSWORD_USERNAME_COL, username);
+ c.put(PASSWORD_PASSWORD_COL, password);
+ sDatabase.insert(mTableNames[TABLE_PASSWORD_ID], PASSWORD_HOST_COL,
+ c);
+ }
+ }
+
+ /**
+ * Retrieve the username and password for a given host
+ *
+ * @param schemePlusHost The scheme and host which passwords applies to
+ * @return String[] if found, String[0] is username, which can be null and
+ * String[1] is password. Return null if it can't find anything.
+ */
+ String[] getUsernamePassword(String schemePlusHost) {
+ if (schemePlusHost == null || !checkInitialized()) {
+ return null;
+ }
+
+ final String[] columns = new String[] {
+ PASSWORD_USERNAME_COL, PASSWORD_PASSWORD_COL
+ };
+ final String selection = "(" + PASSWORD_HOST_COL + " == ?)";
+ synchronized (mPasswordLock) {
+ String[] ret = null;
+ Cursor cursor = null;
+ try {
+ cursor = sDatabase.query(mTableNames[TABLE_PASSWORD_ID],
+ columns, selection, new String[] { schemePlusHost }, null,
+ null, null);
+ if (cursor.moveToFirst()) {
+ ret = new String[2];
+ ret[0] = cursor.getString(
+ cursor.getColumnIndex(PASSWORD_USERNAME_COL));
+ ret[1] = cursor.getString(
+ cursor.getColumnIndex(PASSWORD_PASSWORD_COL));
+ }
+ } catch (IllegalStateException e) {
+ Log.e(LOGTAG, "getUsernamePassword", e);
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * @see WebViewDatabase#hasUsernamePassword
+ */
+ @Override
+ public boolean hasUsernamePassword() {
+ synchronized (mPasswordLock) {
+ return hasEntries(TABLE_PASSWORD_ID);
+ }
+ }
+
+ /**
+ * @see WebViewDatabase#clearUsernamePassword
+ */
+ @Override
+ public void clearUsernamePassword() {
+ if (!checkInitialized()) {
+ return;
+ }
+
+ synchronized (mPasswordLock) {
+ sDatabase.delete(mTableNames[TABLE_PASSWORD_ID], null, null);
+ }
+ }
+
+ //
+ // http authentication password functions
+ //
+
+ /**
+ * Set HTTP authentication password. Tuple (HTTPAUTH_HOST_COL,
+ * HTTPAUTH_REALM_COL, HTTPAUTH_USERNAME_COL) is unique.
+ *
+ * @param host The host for the password
+ * @param realm The realm for the password
+ * @param username The username for the password. If it is null, it means
+ * password can't be saved.
+ * @param password The password
+ */
+ void setHttpAuthUsernamePassword(String host, String realm, String username,
+ String password) {
+ if (host == null || realm == null || !checkInitialized()) {
+ return;
+ }
+
+ synchronized (mHttpAuthLock) {
+ final ContentValues c = new ContentValues();
+ c.put(HTTPAUTH_HOST_COL, host);
+ c.put(HTTPAUTH_REALM_COL, realm);
+ c.put(HTTPAUTH_USERNAME_COL, username);
+ c.put(HTTPAUTH_PASSWORD_COL, password);
+ sDatabase.insert(mTableNames[TABLE_HTTPAUTH_ID], HTTPAUTH_HOST_COL,
+ c);
+ }
+ }
+
+ /**
+ * Retrieve the HTTP authentication username and password for a given
+ * host+realm pair
+ *
+ * @param host The host the password applies to
+ * @param realm The realm the password applies to
+ * @return String[] if found, String[0] is username, which can be null and
+ * String[1] is password. Return null if it can't find anything.
+ */
+ String[] getHttpAuthUsernamePassword(String host, String realm) {
+ if (host == null || realm == null || !checkInitialized()){
+ return null;
+ }
+
+ final String[] columns = new String[] {
+ HTTPAUTH_USERNAME_COL, HTTPAUTH_PASSWORD_COL
+ };
+ final String selection = "(" + HTTPAUTH_HOST_COL + " == ?) AND ("
+ + HTTPAUTH_REALM_COL + " == ?)";
+ synchronized (mHttpAuthLock) {
+ String[] ret = null;
+ Cursor cursor = null;
+ try {
+ cursor = sDatabase.query(mTableNames[TABLE_HTTPAUTH_ID],
+ columns, selection, new String[] { host, realm }, null,
+ null, null);
+ if (cursor.moveToFirst()) {
+ ret = new String[2];
+ ret[0] = cursor.getString(
+ cursor.getColumnIndex(HTTPAUTH_USERNAME_COL));
+ ret[1] = cursor.getString(
+ cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL));
+ }
+ } catch (IllegalStateException e) {
+ Log.e(LOGTAG, "getHttpAuthUsernamePassword", e);
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * @see WebViewDatabase#hasHttpAuthUsernamePassword
+ */
+ @Override
+ public boolean hasHttpAuthUsernamePassword() {
+ synchronized (mHttpAuthLock) {
+ return hasEntries(TABLE_HTTPAUTH_ID);
+ }
+ }
+
+ /**
+ * @see WebViewDatabase#clearHttpAuthUsernamePassword
+ */
+ @Override
+ public void clearHttpAuthUsernamePassword() {
+ if (!checkInitialized()) {
+ return;
+ }
+
+ synchronized (mHttpAuthLock) {
+ sDatabase.delete(mTableNames[TABLE_HTTPAUTH_ID], null, null);
+ }
+ }
+
+ //
+ // form data functions
+ //
+
+ /**
+ * Set form data for a site. Tuple (FORMDATA_URLID_COL, FORMDATA_NAME_COL,
+ * FORMDATA_VALUE_COL) is unique
+ *
+ * @param url The url of the site
+ * @param formdata The form data in HashMap
+ */
+ void setFormData(String url, HashMap<String, String> formdata) {
+ if (url == null || formdata == null || !checkInitialized()) {
+ return;
+ }
+
+ final String selection = "(" + FORMURL_URL_COL + " == ?)";
+ synchronized (mFormLock) {
+ long urlid = -1;
+ Cursor cursor = null;
+ try {
+ cursor = sDatabase.query(mTableNames[TABLE_FORMURL_ID],
+ ID_PROJECTION, selection, new String[] { url }, null, null,
+ null);
+ if (cursor.moveToFirst()) {
+ urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
+ } else {
+ ContentValues c = new ContentValues();
+ c.put(FORMURL_URL_COL, url);
+ urlid = sDatabase.insert(
+ mTableNames[TABLE_FORMURL_ID], null, c);
+ }
+ } catch (IllegalStateException e) {
+ Log.e(LOGTAG, "setFormData", e);
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ if (urlid >= 0) {
+ Set<Entry<String, String>> set = formdata.entrySet();
+ Iterator<Entry<String, String>> iter = set.iterator();
+ ContentValues map = new ContentValues();
+ map.put(FORMDATA_URLID_COL, urlid);
+ while (iter.hasNext()) {
+ Entry<String, String> entry = iter.next();
+ map.put(FORMDATA_NAME_COL, entry.getKey());
+ map.put(FORMDATA_VALUE_COL, entry.getValue());
+ sDatabase.insert(mTableNames[TABLE_FORMDATA_ID], null, map);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get all the values for a form entry with "name" in a given site
+ *
+ * @param url The url of the site
+ * @param name The name of the form entry
+ * @return A list of values. Return empty list if nothing is found.
+ */
+ ArrayList<String> getFormData(String url, String name) {
+ ArrayList<String> values = new ArrayList<String>();
+ if (url == null || name == null || !checkInitialized()) {
+ return values;
+ }
+
+ final String urlSelection = "(" + FORMURL_URL_COL + " == ?)";
+ final String dataSelection = "(" + FORMDATA_URLID_COL + " == ?) AND ("
+ + FORMDATA_NAME_COL + " == ?)";
+ synchronized (mFormLock) {
+ Cursor cursor = null;
+ try {
+ cursor = sDatabase.query(mTableNames[TABLE_FORMURL_ID],
+ ID_PROJECTION, urlSelection, new String[] { url }, null,
+ null, null);
+ while (cursor.moveToNext()) {
+ long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
+ Cursor dataCursor = null;
+ try {
+ dataCursor = sDatabase.query(
+ mTableNames[TABLE_FORMDATA_ID],
+ new String[] { ID_COL, FORMDATA_VALUE_COL },
+ dataSelection,
+ new String[] { Long.toString(urlid), name },
+ null, null, null);
+ if (dataCursor.moveToFirst()) {
+ int valueCol = dataCursor.getColumnIndex(
+ FORMDATA_VALUE_COL);
+ do {
+ values.add(dataCursor.getString(valueCol));
+ } while (dataCursor.moveToNext());
+ }
+ } catch (IllegalStateException e) {
+ Log.e(LOGTAG, "getFormData dataCursor", e);
+ } finally {
+ if (dataCursor != null) dataCursor.close();
+ }
+ }
+ } catch (IllegalStateException e) {
+ Log.e(LOGTAG, "getFormData cursor", e);
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ return values;
+ }
+ }
+
+ /**
+ * @see WebViewDatabase#hasFormData
+ */
+ @Override
+ public boolean hasFormData() {
+ synchronized (mFormLock) {
+ return hasEntries(TABLE_FORMURL_ID);
+ }
+ }
+
+ /**
+ * @see WebViewDatabase#clearFormData
+ */
+ @Override
+ public void clearFormData() {
+ if (!checkInitialized()) {
+ return;
+ }
+
+ synchronized (mFormLock) {
+ sDatabase.delete(mTableNames[TABLE_FORMURL_ID], null, null);
+ sDatabase.delete(mTableNames[TABLE_FORMDATA_ID], null, null);
+ }
+ }
+}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index a832b0a..1d302f1 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.content.Context;
+
/**
* This is the main entry-point into the WebView back end implementations, which the WebView
* proxy class uses to instantiate all the other objects as needed. The backend must provide an
@@ -63,21 +65,32 @@ public interface WebViewFactoryProvider {
/**
* Gets the singleton CookieManager instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
- * @return the singleton CookieManager instance.
+ *
+ * @return the singleton CookieManager instance
*/
CookieManager getCookieManager();
/**
* Gets the singleton WebIconDatabase instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
- * @return the singleton WebIconDatabase instance.
+ *
+ * @return the singleton WebIconDatabase instance
*/
WebIconDatabase getWebIconDatabase();
/**
* Gets the singleton WebStorage instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
- * @return the singleton WebStorage instance.
+ *
+ * @return the singleton WebStorage instance
*/
WebStorage getWebStorage();
+
+ /**
+ * Gets the singleton WebViewDatabase instance for this WebView implementation. The
+ * implementation must return the same instance on subsequent calls.
+ *
+ * @return the singleton WebViewDatabase instance
+ */
+ WebViewDatabase getWebViewDatabase(Context context);
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 57a3012..e628bc1 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1058,7 +1058,9 @@ public class RemoteViews implements Parcelable, Filter {
public ViewGroupAction(int viewId, RemoteViews nestedViews) {
this.viewId = viewId;
this.nestedViews = nestedViews;
- configureRemoteViewsAsChild(nestedViews);
+ if (nestedViews != null) {
+ configureRemoteViewsAsChild(nestedViews);
+ }
}
public ViewGroupAction(Parcel parcel, BitmapCache bitmapCache) {
diff --git a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java
index 436caab..20e4b32 100644
--- a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java
+++ b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java
@@ -160,9 +160,22 @@ public class SurfaceTextureTarget extends Filter {
@Override
public void open(FilterContext context) {
// Set up SurfaceTexture internals
- mSurfaceId = context.getGLEnvironment().registerSurfaceTexture(mSurfaceTexture, mScreenWidth, mScreenHeight);
+ mSurfaceId = context.getGLEnvironment().registerSurfaceTexture(
+ mSurfaceTexture, mScreenWidth, mScreenHeight);
+ if (mSurfaceId <= 0) {
+ throw new RuntimeException("Could not register SurfaceTexture: " + mSurfaceTexture);
+ }
}
+
+ @Override
+ public void close(FilterContext context) {
+ if (mSurfaceId > 0) {
+ context.getGLEnvironment().unregisterSurfaceId(mSurfaceId);
+ }
+ }
+
+
@Override
public void process(FilterContext context) {
if (mLogVerbose) Log.v(TAG, "Starting frame processing");
@@ -173,9 +186,11 @@ public class SurfaceTextureTarget extends Filter {
Frame input = pullInput("frame");
boolean createdFrame = false;
- float currentAspectRatio = (float)input.getFormat().getWidth() / input.getFormat().getHeight();
+ float currentAspectRatio =
+ (float)input.getFormat().getWidth() / input.getFormat().getHeight();
if (currentAspectRatio != mAspectRatio) {
- if (mLogVerbose) Log.v(TAG, "New aspect ratio: " + currentAspectRatio +", previously: " + mAspectRatio);
+ if (mLogVerbose) Log.v(TAG, "New aspect ratio: " + currentAspectRatio +
+ ", previously: " + mAspectRatio);
mAspectRatio = currentAspectRatio;
updateTargetRect();
}
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 8fbab74..b905db3 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -54,6 +54,7 @@
android:src="@drawable/ic_sysbar_back"
systemui:keyCode="4"
android:layout_weight="0"
+ android:scaleType="center"
systemui:glowBackground="@drawable/ic_sysbar_highlight"
android:contentDescription="@string/accessibility_back"
/>
@@ -214,6 +215,7 @@
android:layout_height="80dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_back_land"
+ android:scaleType="center"
systemui:keyCode="4"
android:layout_weight="0"
android:contentDescription="@string/accessibility_back"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 0ba8cce..f565e75 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -29,6 +29,17 @@
android:fitsSystemWindows="true"
>
+ <ImageView
+ android:id="@+id/notification_lights_out"
+ android:layout_width="@dimen/status_bar_icon_size"
+ android:layout_height="match_parent"
+ android:paddingLeft="6dip"
+ android:paddingBottom="2dip"
+ android:src="@drawable/ic_sysbar_lights_out_dot_small"
+ android:scaleType="center"
+ android:visibility="gone"
+ />
+
<LinearLayout android:id="@+id/icons"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -38,6 +49,7 @@
>
<LinearLayout
+ android:id="@+id/notification_icon_area"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 73c5d3a..424317a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -23,6 +23,7 @@ import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
@@ -71,6 +72,8 @@ public class NavigationBarView extends LinearLayout {
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
+ private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
+
private DelegateViewHelper mDelegateHelper;
// workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
@@ -146,6 +149,11 @@ public class NavigationBarView extends LinearLayout {
mVertical = false;
mShowMenu = false;
mDelegateHelper = new DelegateViewHelper(this);
+
+ mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
+ mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land);
+ mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
+ mBackAltLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
}
View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
@@ -188,10 +196,10 @@ public class NavigationBarView extends LinearLayout {
getRecentsButton().setAlpha(
(0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f);
- ((ImageView)getBackButton()).setImageResource(
+ ((ImageView)getBackButton()).setImageDrawable(
(0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
- ? R.drawable.ic_sysbar_back_ime
- : R.drawable.ic_sysbar_back);
+ ? (mVertical ? mBackAltLandIcon : mBackAltIcon)
+ : (mVertical ? mBackLandIcon : mBackIcon));
}
public void setDisabledFlags(int disabledFlags) {
@@ -250,7 +258,7 @@ public class NavigationBarView extends LinearLayout {
} else {
navButtons.animate()
.alpha(lightsOut ? 0f : 1f)
- .setDuration(lightsOut ? 600 : 200)
+ .setDuration(lightsOut ? 750 : 250)
.start();
lowLights.setOnTouchListener(mLightsOutListener);
@@ -260,8 +268,7 @@ public class NavigationBarView extends LinearLayout {
}
lowLights.animate()
.alpha(lightsOut ? 1f : 0f)
- .setStartDelay(lightsOut ? 500 : 0)
- .setDuration(lightsOut ? 1000 : 300)
+ .setDuration(lightsOut ? 750 : 250)
.setInterpolator(new AccelerateInterpolator(2.0f))
.setListener(lightsOut ? null : new AnimatorListenerAdapter() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 80ee64f..8586185 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.phone;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -55,6 +58,7 @@ import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
+import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
@@ -207,6 +211,8 @@ public class PhoneStatusBar extends BaseStatusBar {
int[] mAbsPos = new int[2];
Runnable mPostCollapseCleanup = null;
+ private AnimatorSet mLightsOutAnimation;
+ private AnimatorSet mLightsOnAnimation;
// for disabling the status bar
int mDisabled = 0;
@@ -935,7 +941,26 @@ public class PhoneStatusBar extends BaseStatusBar {
mClearButton.setAlpha(clearable ? 1.0f : 0.0f);
}
mClearButton.setEnabled(clearable);
-
+
+ final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
+ final boolean showDot = (any&&!areLightsOn());
+ if (showDot != (nlo.getAlpha() == 1.0f)) {
+ if (showDot) {
+ nlo.setAlpha(0f);
+ nlo.setVisibility(View.VISIBLE);
+ }
+ nlo.animate()
+ .alpha(showDot?1:0)
+ .setDuration(showDot?750:250)
+ .setInterpolator(new AccelerateInterpolator(2.0f))
+ .setListener(showDot ? null : new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator _a) {
+ nlo.setVisibility(View.GONE);
+ }
+ })
+ .start();
+ }
}
public void showClock(boolean show) {
@@ -1372,6 +1397,10 @@ public class PhoneStatusBar extends BaseStatusBar {
final int hitSize = statusBarSize*2;
final int y = (int)event.getRawY();
if (action == MotionEvent.ACTION_DOWN) {
+ if (!areLightsOn()) {
+ setLightsOn(true);
+ }
+
if (!mExpanded) {
mViewDelta = statusBarSize - y;
} else {
@@ -1470,16 +1499,64 @@ public class PhoneStatusBar extends BaseStatusBar {
final boolean lightsOut = (0 != (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE));
if (lightsOut) {
animateCollapse();
+ if (mTicking) {
+ mTicker.halt();
+ }
}
+
if (mNavigationBarView != null) {
mNavigationBarView.setLowProfile(lightsOut);
}
+
+ setStatusBarLowProfile(lightsOut);
}
notifyUiVisibilityChanged();
}
}
+ private void setStatusBarLowProfile(boolean lightsOut) {
+ if (mLightsOutAnimation == null) {
+ final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
+ final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons);
+ final View signal = mStatusBarView.findViewById(R.id.signal_cluster);
+ final View battery = mStatusBarView.findViewById(R.id.battery);
+ final View clock = mStatusBarView.findViewById(R.id.clock);
+
+ mLightsOutAnimation = new AnimatorSet();
+ mLightsOutAnimation.playTogether(
+ ObjectAnimator.ofFloat(notifications, View.ALPHA, 0),
+ ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0),
+ ObjectAnimator.ofFloat(signal, View.ALPHA, 0),
+ ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f),
+ ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f)
+ );
+ mLightsOutAnimation.setDuration(750);
+
+ mLightsOnAnimation = new AnimatorSet();
+ mLightsOnAnimation.playTogether(
+ ObjectAnimator.ofFloat(notifications, View.ALPHA, 1),
+ ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1),
+ ObjectAnimator.ofFloat(signal, View.ALPHA, 1),
+ ObjectAnimator.ofFloat(battery, View.ALPHA, 1),
+ ObjectAnimator.ofFloat(clock, View.ALPHA, 1)
+ );
+ mLightsOnAnimation.setDuration(250);
+ }
+
+ mLightsOutAnimation.cancel();
+ mLightsOnAnimation.cancel();
+
+ final Animator a = lightsOut ? mLightsOutAnimation : mLightsOnAnimation;
+ a.start();
+
+ setAreThereNotifications();
+ }
+
+ private boolean areLightsOn() {
+ return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ }
+
public void setLightsOn(boolean on) {
Log.v(TAG, "setLightsOn(" + on + ")");
if (on) {
@@ -1580,6 +1657,9 @@ public class PhoneStatusBar extends BaseStatusBar {
}
private void tick(StatusBarNotification n) {
+ // no ticking in lights-out mode
+ if (!areLightsOn()) return;
+
// Show the ticker if one is requested. Also don't do this
// until status bar window is attached to the window manager,
// because... well, what's the point otherwise? And trying to
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6c99cdb..429c3c4 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2697,26 +2697,18 @@ public final class ActivityManagerService extends ActivityManagerNative
public final void finishSubActivity(IBinder token, String resultWho,
int requestCode) {
synchronized(this) {
- ActivityRecord self = mMainStack.isInStackLocked(token);
- if (self == null) {
- return;
- }
-
final long origId = Binder.clearCallingIdentity();
+ mMainStack.finishSubActivityLocked(token, resultWho, requestCode);
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
- int i;
- for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.resultTo == self && r.requestCode == requestCode) {
- if ((r.resultWho == null && resultWho == null) ||
- (r.resultWho != null && r.resultWho.equals(resultWho))) {
- mMainStack.finishActivityLocked(r, i,
- Activity.RESULT_CANCELED, null, "request-sub");
- }
- }
- }
-
+ public boolean finishActivityAffinity(IBinder token) {
+ synchronized(this) {
+ final long origId = Binder.clearCallingIdentity();
+ boolean res = mMainStack.finishActivityAffinityLocked(token);
Binder.restoreCallingIdentity(origId);
+ return res;
}
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c8e015b..25fae83 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -3497,6 +3497,51 @@ final class ActivityStack {
return true;
}
+ final void finishSubActivityLocked(IBinder token, String resultWho, int requestCode) {
+ ActivityRecord self = isInStackLocked(token);
+ if (self == null) {
+ return;
+ }
+
+ int i;
+ for (i=mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ if (r.resultTo == self && r.requestCode == requestCode) {
+ if ((r.resultWho == null && resultWho == null) ||
+ (r.resultWho != null && r.resultWho.equals(resultWho))) {
+ finishActivityLocked(r, i,
+ Activity.RESULT_CANCELED, null, "request-sub");
+ }
+ }
+ }
+ }
+
+ final boolean finishActivityAffinityLocked(IBinder token) {
+ int index = indexOfTokenLocked(token);
+ if (DEBUG_RESULTS) Slog.v(
+ TAG, "Finishing activity affinity @" + index + ": token=" + token);
+ if (index < 0) {
+ return false;
+ }
+ ActivityRecord r = mHistory.get(index);
+
+ while (index > 0) {
+ ActivityRecord cur = mHistory.get(index);
+ if (cur.task != r.task) {
+ break;
+ }
+ if (cur.taskAffinity == null && r.taskAffinity != null) {
+ break;
+ }
+ if (cur.taskAffinity != null && !cur.taskAffinity.equals(r.taskAffinity)) {
+ break;
+ }
+ finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null, "request-affinity");
+ index--;
+ }
+ return true;
+ }
+
final void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
// send the result
ActivityRecord resultTo = r.resultTo;