Merge "move ndk headers to frameworks/native"
diff --git a/api/current.txt b/api/current.txt
index 4398ea3..8747e9a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2744,6 +2744,7 @@
method public static boolean isUserAMonkey();
method public void killBackgroundProcesses(java.lang.String);
method public void moveTaskToFront(int, int);
+ method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -2867,9 +2868,14 @@
public class ActivityOptions {
method public void join(android.app.ActivityOptions);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
+ method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int, android.app.ActivityOptions.OnAnimationStartedListener);
method public android.os.Bundle toBundle();
}
+ public static abstract interface ActivityOptions.OnAnimationStartedListener {
+ method public abstract void onAnimationStarted();
+ }
+
public class AlarmManager {
method public void cancel(android.app.PendingIntent);
method public void set(int, long, android.app.PendingIntent);
@@ -7358,6 +7364,7 @@
method public static int releaseMemory();
method public long replace(java.lang.String, java.lang.String, android.content.ContentValues);
method public long replaceOrThrow(java.lang.String, java.lang.String, android.content.ContentValues) throws android.database.SQLException;
+ method public void setForeignKeyConstraintsEnabled(boolean);
method public void setLocale(java.util.Locale);
method public deprecated void setLockingEnabled(boolean);
method public void setMaxSqlCacheSize(int);
@@ -7437,6 +7444,7 @@
method public java.lang.String getDatabaseName();
method public android.database.sqlite.SQLiteDatabase getReadableDatabase();
method public android.database.sqlite.SQLiteDatabase getWritableDatabase();
+ method public void onConfigure(android.database.sqlite.SQLiteDatabase);
method public abstract void onCreate(android.database.sqlite.SQLiteDatabase);
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
method public void onOpen(android.database.sqlite.SQLiteDatabase);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ea32745..b277efb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3639,7 +3639,7 @@
*/
public void startActivityFromChild(Activity child, Intent intent,
int requestCode) {
- startActivityFromChild(child, intent, requestCode);
+ startActivityFromChild(child, intent, requestCode, null);
}
/**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d056b17..531a695 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -31,6 +31,7 @@
import android.graphics.Bitmap;
import android.graphics.Point;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.Parcel;
@@ -816,6 +817,19 @@
public static final int MOVE_TASK_NO_USER_ACTION = 0x00000002;
/**
+ * Equivalent to calling {@link #moveTaskToFront(int, int, Bundle)}
+ * with a null options argument.
+ *
+ * @param taskId The identifier of the task to be moved, as found in
+ * {@link RunningTaskInfo} or {@link RecentTaskInfo}.
+ * @param flags Additional operational flags, 0 or more of
+ * {@link #MOVE_TASK_WITH_HOME}.
+ */
+ public void moveTaskToFront(int taskId, int flags) {
+ moveTaskToFront(taskId, flags, null);
+ }
+
+ /**
* Ask that the task associated with a given task ID be moved to the
* front of the stack, so it is now visible to the user. Requires that
* the caller hold permission {@link android.Manifest.permission#REORDER_TASKS}
@@ -825,10 +839,13 @@
* {@link RunningTaskInfo} or {@link RecentTaskInfo}.
* @param flags Additional operational flags, 0 or more of
* {@link #MOVE_TASK_WITH_HOME}.
+ * @param options Additional options for the operation, either null or
+ * as per {@link Context#startActivity(Intent, android.os.Bundle)
+ * Context.startActivity(Intent, Bundle)}.
*/
- public void moveTaskToFront(int taskId, int flags) {
+ public void moveTaskToFront(int taskId, int flags, Bundle options) {
try {
- ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags);
+ ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags, options);
} catch (RemoteException e) {
// System dead, we will be dead too soon!
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index a3cc352..c402329 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -510,7 +510,9 @@
data.enforceInterface(IActivityManager.descriptor);
int task = data.readInt();
int fl = data.readInt();
- moveTaskToFront(task, fl);
+ Bundle options = data.readInt() != 0
+ ? Bundle.CREATOR.createFromParcel(data) : null;
+ moveTaskToFront(task, fl, options);
reply.writeNoException();
return true;
}
@@ -1055,6 +1057,15 @@
return true;
}
+ case KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String reason = data.readString();
+ boolean res = killProcessesBelowForeground(reason);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
case START_RUNNING_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String pkg = data.readString();
@@ -2134,13 +2145,19 @@
reply.recycle();
return list;
}
- public void moveTaskToFront(int task, int flags) throws RemoteException
+ public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(task);
data.writeInt(flags);
+ if (options != null) {
+ data.writeInt(1);
+ options.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
mRemote.transact(MOVE_TASK_TO_FRONT_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -2902,6 +2919,18 @@
reply.recycle();
return res;
}
+ @Override
+ public boolean killProcessesBelowForeground(String reason) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(reason);
+ mRemote.transact(KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION, data, reply, 0);
+ boolean res = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public void startRunning(String pkg, String cls, String action,
String indata) throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 03bc338..c637df0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,7 +17,13 @@
package android.app;
import android.content.Context;
+import android.graphics.Bitmap;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.Message;
+import android.os.RemoteException;
+import android.view.View;
/**
* Helper class for building an options Bundle that can be used with
@@ -32,6 +38,12 @@
public static final String KEY_PACKAGE_NAME = "android:packageName";
/**
+ * Type of animation that arguments specify.
+ * @hide
+ */
+ public static final String KEY_ANIM_TYPE = "android:animType";
+
+ /**
* Custom enter animation resource ID.
* @hide
*/
@@ -43,10 +55,45 @@
*/
public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes";
+ /**
+ * Bitmap for thumbnail animation.
+ * @hide
+ */
+ public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail";
+
+ /**
+ * Start X position of thumbnail animation.
+ * @hide
+ */
+ public static final String KEY_ANIM_START_X = "android:animStartX";
+
+ /**
+ * Start Y position of thumbnail animation.
+ * @hide
+ */
+ public static final String KEY_ANIM_START_Y = "android:animStartY";
+
+ /**
+ * Callback for when animation is started.
+ * @hide
+ */
+ public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
+
+ /** @hide */
+ public static final int ANIM_NONE = 0;
+ /** @hide */
+ public static final int ANIM_CUSTOM = 1;
+ /** @hide */
+ public static final int ANIM_THUMBNAIL = 2;
+
private String mPackageName;
- private boolean mIsCustomAnimation;
+ private int mAnimationType = ANIM_NONE;
private int mCustomEnterResId;
private int mCustomExitResId;
+ private Bitmap mThumbnail;
+ private int mStartX;
+ private int mStartY;
+ private IRemoteCallback mAnimationStartedListener;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -65,22 +112,79 @@
int enterResId, int exitResId) {
ActivityOptions opts = new ActivityOptions();
opts.mPackageName = context.getPackageName();
- opts.mIsCustomAnimation = true;
+ opts.mAnimationType = ANIM_CUSTOM;
opts.mCustomEnterResId = enterResId;
opts.mCustomExitResId = exitResId;
return opts;
}
+ /**
+ * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
+ * to find out when the given animation has started running.
+ */
+ public interface OnAnimationStartedListener {
+ void onAnimationStarted();
+ }
+
+ /**
+ * Create an ActivityOptions specifying an animation where a thumbnail
+ * is scaled from a given position to the new activity window that is
+ * being started.
+ *
+ * @param source The View that this thumbnail is animating from. This
+ * defines the coordinate space for <var>startX</var> and <var>startY</var>.
+ * @param thumbnail The bitmap that will be shown as the initial thumbnail
+ * of the animation.
+ * @param startX The x starting location of the bitmap, in screen coordiantes.
+ * @param startY The y starting location of the bitmap, in screen coordinates.
+ * @param listener Optional OnAnimationStartedListener to find out when the
+ * requested animation has started running. If for some reason the animation
+ * is not executed, the callback will happen immediately.
+ * @return Returns a new ActivityOptions object that you can use to
+ * supply these options as the options Bundle when starting an activity.
+ */
+ public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
+ Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
+ ActivityOptions opts = new ActivityOptions();
+ opts.mPackageName = source.getContext().getPackageName();
+ opts.mAnimationType = ANIM_THUMBNAIL;
+ opts.mThumbnail = thumbnail;
+ int[] pts = new int[2];
+ source.getLocationOnScreen(pts);
+ opts.mStartX = pts[0] + startX;
+ opts.mStartY = pts[1] + startY;
+ if (listener != null) {
+ final Handler h = source.getHandler();
+ final OnAnimationStartedListener finalListener = listener;
+ opts.mAnimationStartedListener = new IRemoteCallback.Stub() {
+ @Override public void sendResult(Bundle data) throws RemoteException {
+ h.post(new Runnable() {
+ @Override public void run() {
+ finalListener.onAnimationStarted();
+ }
+ });
+ }
+ };
+ }
+ return opts;
+ }
+
private ActivityOptions() {
}
/** @hide */
public ActivityOptions(Bundle opts) {
mPackageName = opts.getString(KEY_PACKAGE_NAME);
- if (opts.containsKey(KEY_ANIM_ENTER_RES_ID)) {
- mIsCustomAnimation = true;
+ mAnimationType = opts.getInt(KEY_ANIM_TYPE);
+ if (mAnimationType == ANIM_CUSTOM) {
mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
+ } else if (mAnimationType == ANIM_THUMBNAIL) {
+ mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
+ mStartX = opts.getInt(KEY_ANIM_START_X, 0);
+ mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
+ mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
+ opts.getIBinder(KEY_ANIM_START_LISTENER));
}
}
@@ -90,8 +194,8 @@
}
/** @hide */
- public boolean isCustomAnimation() {
- return mIsCustomAnimation;
+ public int getAnimationType() {
+ return mAnimationType;
}
/** @hide */
@@ -104,6 +208,43 @@
return mCustomExitResId;
}
+ /** @hide */
+ public Bitmap getThumbnail() {
+ return mThumbnail;
+ }
+
+ /** @hide */
+ public int getStartX() {
+ return mStartX;
+ }
+
+ /** @hide */
+ public int getStartY() {
+ return mStartY;
+ }
+
+ /** @hide */
+ public IRemoteCallback getOnAnimationStartListener() {
+ return mAnimationStartedListener;
+ }
+
+ /** @hide */
+ public void abort() {
+ if (mAnimationStartedListener != null) {
+ try {
+ mAnimationStartedListener.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /** @hide */
+ public static void abort(Bundle options) {
+ if (options != null) {
+ (new ActivityOptions(options)).abort();
+ }
+ }
+
/**
* Join the values in <var>otherOptions</var> in to this one. Any values
* defined in <var>otherOptions</var> replace those in the base options.
@@ -112,10 +253,27 @@
if (otherOptions.mPackageName != null) {
mPackageName = otherOptions.mPackageName;
}
- if (otherOptions.mIsCustomAnimation) {
- mIsCustomAnimation = true;
- mCustomEnterResId = otherOptions.mCustomEnterResId;
- mCustomExitResId = otherOptions.mCustomExitResId;
+ switch (otherOptions.mAnimationType) {
+ case ANIM_CUSTOM:
+ mAnimationType = otherOptions.mAnimationType;
+ mCustomEnterResId = otherOptions.mCustomEnterResId;
+ mCustomExitResId = otherOptions.mCustomExitResId;
+ mThumbnail = null;
+ mAnimationStartedListener = null;
+ break;
+ case ANIM_THUMBNAIL:
+ mAnimationType = otherOptions.mAnimationType;
+ mThumbnail = otherOptions.mThumbnail;
+ mStartX = otherOptions.mStartX;
+ mStartY = otherOptions.mStartY;
+ if (otherOptions.mAnimationStartedListener != null) {
+ try {
+ otherOptions.mAnimationStartedListener.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
+ mAnimationStartedListener = otherOptions.mAnimationStartedListener;
+ break;
}
}
@@ -132,9 +290,19 @@
if (mPackageName != null) {
b.putString(KEY_PACKAGE_NAME, mPackageName);
}
- if (mIsCustomAnimation) {
- b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
- b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
+ switch (mAnimationType) {
+ case ANIM_CUSTOM:
+ b.putInt(KEY_ANIM_TYPE, mAnimationType);
+ b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
+ b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
+ break;
+ case ANIM_THUMBNAIL:
+ b.putInt(KEY_ANIM_TYPE, mAnimationType);
+ b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
+ b.putInt(KEY_ANIM_START_X, mStartX);
+ b.putInt(KEY_ANIM_START_Y, mStartY);
+ b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
+ != null ? mAnimationStartedListener.asBinder() : null);
}
return b;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 31066b5..1d994d8 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -105,7 +105,7 @@
public List getServices(int maxNum, int flags) throws RemoteException;
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
throws RemoteException;
- public void moveTaskToFront(int task, int flags) throws RemoteException;
+ public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException;
public void moveTaskToBack(int task) throws RemoteException;
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
public void moveTaskBackwards(int task) throws RemoteException;
@@ -216,9 +216,10 @@
public void enterSafeMode() throws RemoteException;
public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
-
+
public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException;
-
+ public boolean killProcessesBelowForeground(String reason) throws RemoteException;
+
// Special low-level communication with activity manager.
public void startRunning(String pkg, String cls, String action,
String data) throws RemoteException;
@@ -573,4 +574,5 @@
int GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+140;
int REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+141;
int GET_MY_MEMORY_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+142;
+ int KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+143;
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index e999316..254f652 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -211,6 +211,7 @@
SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);
setPageSize();
+ setForeignKeyModeFromConfiguration();
setWalModeFromConfiguration();
setJournalSizeLimit();
setAutoCheckpointInterval();
@@ -267,6 +268,16 @@
}
}
+ private void setForeignKeyModeFromConfiguration() {
+ if (!mIsReadOnlyConnection) {
+ final long newValue = mConfiguration.foreignKeyConstraintsEnabled ? 1 : 0;
+ long value = executeForLong("PRAGMA foreign_keys", null, null);
+ if (value != newValue) {
+ execute("PRAGMA foreign_keys=" + newValue, null, null);
+ }
+ }
+ }
+
private void setWalModeFromConfiguration() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
@@ -389,6 +400,8 @@
}
// Remember what changed.
+ boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
+ != mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
& SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
@@ -399,6 +412,11 @@
// Update prepared statement cache size.
mPreparedStatementCache.resize(configuration.maxSqlCacheSize);
+ // Update foreign key mode.
+ if (foreignKeyModeChanged) {
+ setForeignKeyModeFromConfiguration();
+ }
+
// Update WAL.
if (walModeChanged) {
setWalModeFromConfiguration();
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 0538ce4..5c8e38bf 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -277,6 +277,20 @@
assert mAvailableNonPrimaryConnections.isEmpty();
}
+ boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
+ != mConfiguration.foreignKeyConstraintsEnabled;
+ if (foreignKeyModeChanged) {
+ // Foreign key constraints can only be changed if there are no transactions
+ // in progress. To make this clear, we throw an exception if there are
+ // any acquired connections.
+ if (!mAcquiredConnections.isEmpty()) {
+ throw new IllegalStateException("Foreign Key Constraints cannot "
+ + "be enabled or disabled while there are transactions in "
+ + "progress. Finish all transactions and release all active "
+ + "database connections first.");
+ }
+ }
+
if (mConfiguration.openFlags != configuration.openFlags) {
// If we are changing open flags and WAL mode at the same time, then
// we have no choice but to close the primary connection beforehand
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 049a615..7bd0c8d 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1793,6 +1793,53 @@
}
/**
+ * Sets whether foreign key constraints are enabled for the database.
+ * <p>
+ * By default, foreign key constraints are not enforced by the database.
+ * This method allows an application to enable foreign key constraints.
+ * It must be called each time the database is opened to ensure that foreign
+ * key constraints are enabled for the session.
+ * </p><p>
+ * A good time to call this method is right after calling {@link #openOrCreateDatabase}
+ * or in the {@link SQLiteOpenHelper#onConfigure} callback.
+ * </p><p>
+ * When foreign key constraints are disabled, the database does not check whether
+ * changes to the database will violate foreign key constraints. Likewise, when
+ * foreign key constraints are disabled, the database will not execute cascade
+ * delete or update triggers. As a result, it is possible for the database
+ * state to become inconsistent. To perform a database integrity check,
+ * call {@link #isDatabaseIntegrityOk}.
+ * </p><p>
+ * This method must not be called while a transaction is in progress.
+ * </p><p>
+ * See also <a href="http://sqlite.org/foreignkeys.html">SQLite Foreign Key Constraints</a>
+ * for more details about foreign key constraint support.
+ * </p>
+ *
+ * @param enable True to enable foreign key constraints, false to disable them.
+ *
+ * @throws IllegalStateException if the are transactions is in progress
+ * when this method is called.
+ */
+ public void setForeignKeyConstraintsEnabled(boolean enable) {
+ synchronized (mLock) {
+ throwIfNotOpenLocked();
+
+ if (mConfigurationLocked.foreignKeyConstraintsEnabled == enable) {
+ return;
+ }
+
+ mConfigurationLocked.foreignKeyConstraintsEnabled = enable;
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.foreignKeyConstraintsEnabled = !enable;
+ throw ex;
+ }
+ }
+ }
+
+ /**
* This method enables parallel execution of queries from multiple threads on the
* same database. It does this by opening multiple connections to the database
* and using a different database connection for each query. The database
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 123c2c6..549ab90 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -77,6 +77,13 @@
public Locale locale;
/**
+ * True if foreign key constraints are enabled.
+ *
+ * Default is false.
+ */
+ public boolean foreignKeyConstraintsEnabled;
+
+ /**
* The custom functions to register.
*/
public final ArrayList<SQLiteCustomFunction> customFunctions =
@@ -136,6 +143,7 @@
openFlags = other.openFlags;
maxSqlCacheSize = other.maxSqlCacheSize;
locale = other.locale;
+ foreignKeyConstraintsEnabled = other.foreignKeyConstraintsEnabled;
customFunctions.clear();
customFunctions.addAll(other.customFunctions);
}
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index fe37b8f..431eca2 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -237,6 +237,8 @@
}
}
+ onConfigure(db);
+
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
@@ -261,6 +263,7 @@
db.endTransaction();
}
}
+
onOpen(db);
if (db.isReadOnly()) {
@@ -290,6 +293,25 @@
}
/**
+ * Called when the database connection is being configured, to enable features
+ * such as write-ahead logging or foreign key support.
+ * <p>
+ * This method is called before {@link #onCreate}, {@link #onUpgrade},
+ * {@link #onDowngrade}, or {@link #onOpen} are called. It should not modify
+ * the database except to configure the database connection as required.
+ * </p><p>
+ * This method should only call methods that configure the parameters of the
+ * database connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
+ * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled},
+ * {@link SQLiteDatabase#setLocale}, {@link SQLiteDatabase#setMaximumSize},
+ * or executing PRAGMA statements.
+ * </p>
+ *
+ * @param db The database.
+ */
+ public void onConfigure(SQLiteDatabase db) {}
+
+ /**
* Called when the database is created for the first time. This is where the
* creation of tables and the initial population of the tables should happen.
*
@@ -302,11 +324,16 @@
* should use this method to drop tables, add tables, or do anything else it
* needs to upgrade to the new schema version.
*
- * <p>The SQLite ALTER TABLE documentation can be found
+ * <p>
+ * The SQLite ALTER TABLE documentation can be found
* <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
* you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
* you can use ALTER TABLE to rename the old table, then create the new table and then
* populate the new table with the contents of the old table.
+ * </p><p>
+ * This method executes within a transaction. If an exception is thrown, all changes
+ * will automatically be rolled back.
+ * </p>
*
* @param db The database.
* @param oldVersion The old database version.
@@ -316,11 +343,16 @@
/**
* Called when the database needs to be downgraded. This is strictly similar to
- * onUpgrade() method, but is called whenever current version is newer than requested one.
+ * {@link #onUpgrade} method, but is called whenever current version is newer than requested one.
* However, this method is not abstract, so it is not mandatory for a customer to
* implement it. If not overridden, default implementation will reject downgrade and
* throws SQLiteException
*
+ * <p>
+ * This method executes within a transaction. If an exception is thrown, all changes
+ * will automatically be rolled back.
+ * </p>
+ *
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
@@ -334,6 +366,12 @@
* Called when the database has been opened. The implementation
* should check {@link SQLiteDatabase#isReadOnly} before updating the
* database.
+ * <p>
+ * This method is called after the database connection has been configured
+ * and after the database schema has been created, upgraded or downgraded as necessary.
+ * If the database connection must be configured in some way before the schema
+ * is created, upgraded, or downgraded, do it in {@link #onConfigure} instead.
+ * </p>
*
* @param db The database.
*/
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c54d09e..14cd48f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -89,6 +89,8 @@
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
int getPendingAppTransition();
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim);
+ void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
+ IRemoteCallback startedCallback);
void executeAppTransition();
void setAppStartingWindow(IBinder token, String pkg, int theme,
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index dc8c71b7..d92ebcd 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -875,7 +875,7 @@
* otherwise.
*
* @param currentTime Where we are in the animation. This is wall clock time.
- * @param outTransformation A tranformation object that is provided by the
+ * @param outTransformation A transformation object that is provided by the
* caller and will be filled in by the animation.
* @param scale Scaling factor to apply to any inputs to the transform operation, such
* pivot points being rotated or scaled around.
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index cf210c8..e8c1d23 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -112,6 +112,16 @@
}
/**
+ * Like {@link #compose(Transformation)} but does this.postConcat(t) of
+ * the transformation matrix.
+ * @hide
+ */
+ public void postCompose(Transformation t) {
+ mAlpha *= t.getAlpha();
+ mMatrix.postConcat(t.getMatrix());
+ }
+
+ /**
* @return The 3x3 Matrix representing the trnasformation to apply to the
* coordinates of the object being animated
*/
diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
index ef7e651..3d46cdd 100644
--- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -123,7 +123,7 @@
private OnClickListener mSwitchOldListener = new OnClickListener() {
public void onClick(View v) {
try {
- ActivityManagerNative.getDefault().moveTaskToFront(mCurTask, 0);
+ ActivityManagerNative.getDefault().moveTaskToFront(mCurTask, 0, null);
} catch (RemoteException e) {
}
finish();
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index adeeaca..a76a628 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -188,6 +188,40 @@
return getID();
}
+
+ /**
+ * Get the element of the type of the Allocation.
+ *
+ * @hide
+ * @return Element
+ *
+ */
+ public Element getElement() {
+ return mType.getElement();
+ }
+
+ /**
+ * Get the usage flags of the Allocation.
+ *
+ * @hide
+ * @return usage
+ *
+ */
+ public int getUsage() {
+ return mUsage;
+ }
+
+ /**
+ * Get the size of the Allocation in bytes.
+ *
+ * @hide
+ * @return sizeInBytes
+ *
+ */
+ public int getSizeBytes() {
+ return mType.getCount() * mType.getElement().getSizeBytes();
+ }
+
private void updateCacheInfo(Type t) {
mCurrentDimX = t.getX();
mCurrentDimY = t.getY();
@@ -294,10 +328,21 @@
}
}
+ /**
+ * Get the type of the Allocation.
+ *
+ * @return Type
+ *
+ */
public Type getType() {
return mType;
}
+ /**
+ * Propagate changes from one usage of the allocation to the
+ * remaining usages of the allocation.
+ *
+ */
public void syncAll(int srcLocation) {
switch (srcLocation) {
case USAGE_SCRIPT:
@@ -343,6 +388,11 @@
mRS.nAllocationIoReceive(getID());
}
+ /**
+ * Copy an array of RS objects to the allocation.
+ *
+ * @param d Source array.
+ */
public void copyFrom(BaseObj[] d) {
mRS.validate();
validateIsObject();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 66cb32c..564b07b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.LayoutTransition;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -615,10 +616,11 @@
if (!mFirstScreenful && tasks.size() == 0) {
return;
}
- mNumItemsWaitingForThumbnailsAndIcons =
- mFirstScreenful ? tasks.size() : mRecentTaskDescriptions.size();
+ mNumItemsWaitingForThumbnailsAndIcons = mFirstScreenful
+ ? tasks.size() : mRecentTaskDescriptions == null
+ ? 0 : mRecentTaskDescriptions.size();
if (mRecentTaskDescriptions == null) {
- mRecentTaskDescriptions = new ArrayList(tasks);
+ mRecentTaskDescriptions = new ArrayList<TaskDescription>(tasks);
} else {
mRecentTaskDescriptions.addAll(tasks);
}
@@ -656,22 +658,33 @@
}
public void handleOnClick(View view) {
- TaskDescription ad = ((ViewHolder) view.getTag()).taskDescription;
+ ViewHolder holder = (ViewHolder)view.getTag();
+ TaskDescription ad = holder.taskDescription;
final Context context = view.getContext();
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
+ holder.thumbnailViewImage.setDrawingCacheEnabled(true);
+ Bitmap bm = holder.thumbnailViewImage.getDrawingCache();
+ ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
+ holder.thumbnailViewImage, bm, 0, 0,
+ new ActivityOptions.OnAnimationStartedListener() {
+ @Override public void onAnimationStarted() {
+ hide(true);
+ }
+ });
if (ad.taskId >= 0) {
// This is an active task; it should just go to the foreground.
- am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME);
+ am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME,
+ opts.toBundle());
} else {
Intent intent = ad.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
| Intent.FLAG_ACTIVITY_NEW_TASK);
if (DEBUG) Log.v(TAG, "Starting activity " + intent);
- context.startActivity(intent);
+ context.startActivity(intent, opts.toBundle());
}
- hide(true);
+ holder.thumbnailViewImage.setDrawingCacheEnabled(false);
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b422678..60749b3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -34,6 +34,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.AlertDialog;
import android.app.AppGlobals;
@@ -2353,10 +2354,12 @@
synchronized (this) {
ActivityRecord r = mMainStack.isInStackLocked(callingActivity);
if (r == null) {
+ ActivityOptions.abort(options);
return false;
}
if (r.app == null || r.app.thread == null) {
// The caller is not running... d'oh!
+ ActivityOptions.abort(options);
return false;
}
intent = new Intent(intent);
@@ -2393,6 +2396,7 @@
if (aInfo == null) {
// Nobody who is next!
+ ActivityOptions.abort(options);
return false;
}
@@ -2422,8 +2426,6 @@
}
final long origId = Binder.clearCallingIdentity();
- // XXX we are not dealing with propagating grantedUriPermissions...
- // those are not yet exposed to user code, so there is no need.
int res = mMainStack.startActivityLocked(r.app.thread, intent,
r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null,
resultWho, requestCode, -1, r.launchedFromUid, 0,
@@ -3653,7 +3655,7 @@
}
lastTask = r.task;
if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
- null, "force-stop")) {
+ null, "force-stop", true)) {
i--;
}
}
@@ -5686,13 +5688,14 @@
/**
* TODO: Add mController hook
*/
- public void moveTaskToFront(int task, int flags) {
+ public void moveTaskToFront(int task, int flags, Bundle options) {
enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
"moveTaskToFront()");
synchronized(this) {
if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
Binder.getCallingUid(), "Task to front")) {
+ ActivityOptions.abort(options);
return;
}
final long origId = Binder.clearCallingIdentity();
@@ -5707,7 +5710,7 @@
// we'll just move the home task to the top first.
mMainStack.moveHomeToFrontLocked();
}
- mMainStack.moveTaskToFrontLocked(tr, null);
+ mMainStack.moveTaskToFrontLocked(tr, null, options);
return;
}
for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
@@ -5721,13 +5724,14 @@
// we'll just move the home task to the top first.
mMainStack.moveHomeToFrontLocked();
}
- mMainStack.moveTaskToFrontLocked(hr.task, null);
+ mMainStack.moveTaskToFrontLocked(hr.task, null, options);
return;
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
+ ActivityOptions.abort(options);
}
}
@@ -6993,7 +6997,43 @@
}
return killed;
}
-
+
+ @Override
+ public boolean killProcessesBelowForeground(String reason) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("killProcessesBelowForeground() only available to system");
+ }
+
+ return killProcessesBelowAdj(ProcessList.FOREGROUND_APP_ADJ, reason);
+ }
+
+ private boolean killProcessesBelowAdj(int belowAdj, String reason) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("killProcessesBelowAdj() only available to system");
+ }
+
+ boolean killed = false;
+ synchronized (mPidsSelfLocked) {
+ final int size = mPidsSelfLocked.size();
+ for (int i = 0; i < size; i++) {
+ final int pid = mPidsSelfLocked.keyAt(i);
+ final ProcessRecord proc = mPidsSelfLocked.valueAt(i);
+ if (proc == null) continue;
+
+ final int adj = proc.setAdj;
+ if (adj > belowAdj && !proc.killedBackground) {
+ Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
+ EventLog.writeEvent(
+ EventLogTags.AM_KILL, proc.pid, proc.processName, adj, reason);
+ killed = true;
+ proc.killedBackground = true;
+ Process.killProcessQuiet(pid);
+ }
+ }
+ }
+ return killed;
+ }
+
public final void startRunning(String pkg, String cls, String action,
String data) {
synchronized(this) {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 53cb2b0..d60ff2b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -26,7 +26,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.os.Build;
@@ -542,24 +541,38 @@
void updateOptionsLocked(Bundle options) {
if (options != null) {
+ if (pendingOptions != null) {
+ pendingOptions.abort();
+ }
pendingOptions = new ActivityOptions(options);
}
}
void applyOptionsLocked() {
if (pendingOptions != null) {
- if (pendingOptions.isCustomAnimation()) {
- service.mWindowManager.overridePendingAppTransition(
- pendingOptions.getPackageName(),
- pendingOptions.getCustomEnterResId(),
- pendingOptions.getCustomExitResId());
+ switch (pendingOptions.getAnimationType()) {
+ case ActivityOptions.ANIM_CUSTOM:
+ service.mWindowManager.overridePendingAppTransition(
+ pendingOptions.getPackageName(),
+ pendingOptions.getCustomEnterResId(),
+ pendingOptions.getCustomExitResId());
+ break;
+ case ActivityOptions.ANIM_THUMBNAIL:
+ service.mWindowManager.overridePendingAppTransitionThumb(
+ pendingOptions.getThumbnail(),
+ pendingOptions.getStartX(), pendingOptions.getStartY(),
+ pendingOptions.getOnAnimationStartListener());
+ break;
}
pendingOptions = null;
}
}
void clearOptionsLocked() {
- pendingOptions = null;
+ if (pendingOptions != null) {
+ pendingOptions.abort();
+ pendingOptions = null;
+ }
}
void removeUriPermissionsLocked() {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 48b4f4ff..a01ed25 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1695,6 +1695,7 @@
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
+ ActivityOptions.abort(options);
return;
}
break;
@@ -1797,6 +1798,7 @@
// because there is nothing for it to animate on top of.
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
+ ActivityOptions.abort(options);
}
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
@@ -2344,6 +2346,7 @@
// Transfer the result target from the source activity to the new
// one being started, including any failures.
if (requestCode >= 0) {
+ ActivityOptions.abort(options);
return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
resultRecord = sourceRecord.resultTo;
@@ -2375,6 +2378,7 @@
Activity.RESULT_CANCELED, null);
}
mDismissKeyguardOnNextActivity = false;
+ ActivityOptions.abort(options);
return err;
}
@@ -2425,6 +2429,7 @@
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
mDismissKeyguardOnNextActivity = false;
+ ActivityOptions.abort(options);
return ActivityManager.START_SUCCESS;
}
}
@@ -2447,6 +2452,7 @@
pal.startFlags = startFlags;
mService.mPendingActivityLaunches.add(pal);
mDismissKeyguardOnNextActivity = false;
+ ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
@@ -2601,8 +2607,7 @@
// We really do want to push this one into the
// user's face, right now.
moveHomeToFrontFromLaunchLocked(launchFlags);
- r.updateOptionsLocked(options);
- moveTaskToFrontLocked(taskTop.task, r);
+ moveTaskToFrontLocked(taskTop.task, r, options);
}
}
// If the caller has requested that the target task be
@@ -2618,6 +2623,7 @@
if (doResume) {
resumeTopActivityLocked(null);
}
+ ActivityOptions.abort(options);
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
}
if ((launchFlags &
@@ -2705,6 +2711,7 @@
if (doResume) {
resumeTopActivityLocked(null);
}
+ ActivityOptions.abort(options);
return ActivityManager.START_TASK_TO_FRONT;
}
}
@@ -2734,6 +2741,7 @@
if (doResume) {
resumeTopActivityLocked(null);
}
+ ActivityOptions.abort(options);
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and
// the client said not to do anything if that
@@ -2753,6 +2761,7 @@
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
}
+ ActivityOptions.abort(options);
return ActivityManager.START_CLASS_NOT_FOUND;
}
@@ -2794,6 +2803,7 @@
if (doResume) {
resumeTopActivityLocked(null);
}
+ ActivityOptions.abort(options);
return ActivityManager.START_DELIVERED_TO_TOP;
}
} else if (!addingToTask &&
@@ -2948,6 +2958,7 @@
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + realCallingPid + ") when starting: "
+ intent.toString());
+ ActivityOptions.abort(options);
return ActivityManager.START_PERMISSION_DENIED;
}
}
@@ -3480,6 +3491,15 @@
*/
final boolean finishActivityLocked(ActivityRecord r, int index,
int resultCode, Intent resultData, String reason) {
+ return finishActivityLocked(r, index, resultCode, resultData, reason, false);
+ }
+
+ /**
+ * @return Returns true if this activity has been removed from the history
+ * list, or false if it is still in the list and will be removed later.
+ */
+ final boolean finishActivityLocked(ActivityRecord r, int index,
+ int resultCode, Intent resultData, String reason, boolean immediate) {
if (r.finishing) {
Slog.w(TAG, "Duplicate finish request for " + r);
return false;
@@ -3521,7 +3541,10 @@
mService.mCancelledThumbnails.add(r);
}
- if (mResumedActivity == r) {
+ if (immediate) {
+ return finishCurrentActivityLocked(r, index,
+ FINISH_IMMEDIATELY) == null;
+ } else if (mResumedActivity == r) {
boolean endTask = index <= 0
|| (mHistory.get(index-1)).task != r.task;
if (DEBUG_TRANSITION) Slog.v(TAG,
@@ -3887,12 +3910,12 @@
}
}
if (homeTask != null) {
- moveTaskToFrontLocked(homeTask, null);
+ moveTaskToFrontLocked(homeTask, null, null);
}
}
- final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) {
+ final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
final int task = tr.taskId;
@@ -3900,6 +3923,7 @@
if (top < 0 || (mHistory.get(top)).task.taskId == task) {
// nothing to do!
+ ActivityOptions.abort(options);
return;
}
@@ -3941,7 +3965,16 @@
if (r != null) {
mNoAnimActivities.add(r);
}
+ ActivityOptions.abort(options);
} else {
+ if (options != null) {
+ ActivityRecord r = topRunningActivityLocked(null);
+ if (r != null && r.state != ActivityState.RESUMED) {
+ r.updateOptionsLocked(options);
+ } else {
+ ActivityOptions.abort(options);
+ }
+ }
mService.mWindowManager.prepareAppTransition(
WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, false);
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 95666c0..067bf28 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1587,7 +1587,16 @@
if (p != null) {
final PackageSetting ps = (PackageSetting)p.mExtras;
final SharedUserSetting suid = ps.sharedUser;
- return suid != null ? suid.gids : ps.gids;
+ int[] gids = suid != null ? suid.gids : ps.gids;
+
+ // include GIDs for any unenforced permissions
+ if (!isPermissionEnforcedLocked(READ_EXTERNAL_STORAGE)) {
+ final BasePermission basePerm = mSettings.mPermissions.get(
+ READ_EXTERNAL_STORAGE);
+ gids = appendInts(gids, basePerm.gids);
+ }
+
+ return gids;
}
}
// stupid thing to indicate an error.
@@ -8890,6 +8899,19 @@
if (mSettings.mReadExternalStorageEnforcement != enforcement) {
mSettings.mReadExternalStorageEnforcement = enforcement;
mSettings.writeLPr();
+
+ // kill any non-foreground processes so we restart them and
+ // grant/revoke the GID.
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ am.killProcessesBelowForeground("setPermissionEnforcement");
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
}
} else {
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 0e110be..c29ef3f 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -21,10 +21,12 @@
import com.android.server.wm.WindowManagerService.H;
import android.content.pm.ActivityInfo;
+import android.graphics.Matrix;
import android.os.Message;
import android.os.RemoteException;
import android.util.Slog;
import android.view.IApplicationToken;
+import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
@@ -90,6 +92,7 @@
boolean animating;
Animation animation;
+ boolean animInitialized;
boolean hasTransformation;
final Transformation transformation = new Transformation();
@@ -105,6 +108,15 @@
boolean startingMoved;
boolean firstWindowDrawn;
+ // Special surface for thumbnail animation.
+ Surface thumbnail;
+ int thumbnailTransactionSeq;
+ int thumbnailX;
+ int thumbnailY;
+ int thumbnailLayer;
+ Animation thumbnailAnimation;
+ final Transformation thumbnailTransformation = new Transformation();
+
// Input application handle used by the input dispatcher.
final InputApplicationHandle mInputApplicationHandle;
@@ -116,11 +128,12 @@
mInputApplicationHandle = new InputApplicationHandle(this);
}
- public void setAnimation(Animation anim) {
+ public void setAnimation(Animation anim, boolean initialized) {
if (WindowManagerService.localLOGV) Slog.v(
WindowManagerService.TAG, "Setting animation in " + this + ": " + anim);
animation = anim;
animating = false;
+ animInitialized = initialized;
anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
anim.scaleCurrentDuration(service.mTransitionAnimationScale);
int zorder = anim.getZAdjustment();
@@ -146,6 +159,7 @@
if (WindowManagerService.localLOGV) Slog.v(
WindowManagerService.TAG, "Setting dummy animation in " + this);
animation = WindowManagerService.sDummyAnimation;
+ animInitialized = false;
}
}
@@ -153,15 +167,28 @@
if (animation != null) {
animation = null;
animating = true;
+ animInitialized = false;
+ }
+ clearThumbnail();
+ }
+
+ public void clearThumbnail() {
+ if (thumbnail != null) {
+ thumbnail.destroy();
+ thumbnail = null;
}
}
void updateLayers() {
final int N = allAppWindows.size();
final int adj = animLayerAdjustment;
+ thumbnailLayer = -1;
for (int i=0; i<N; i++) {
WindowState w = allAppWindows.get(i);
w.mAnimLayer = w.mLayer + adj;
+ if (w.mAnimLayer > thumbnailLayer) {
+ thumbnailLayer = w.mAnimLayer;
+ }
if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Updating layer " + w + ": "
+ w.mAnimLayer);
if (w == service.mInputMethodTarget && !service.mInputMethodTargetWaitingAnim) {
@@ -203,6 +230,38 @@
return isAnimating;
}
+ private void stepThumbnailAnimation(long currentTime) {
+ thumbnailTransformation.clear();
+ thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
+ thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
+ final boolean screenAnimation = service.mAnimator.mScreenRotationAnimation != null
+ && service.mAnimator.mScreenRotationAnimation.isAnimating();
+ if (screenAnimation) {
+ thumbnailTransformation.postCompose(
+ service.mAnimator.mScreenRotationAnimation.getEnterTransformation());
+ }
+ // cache often used attributes locally
+ final float tmpFloats[] = service.mTmpFloats;
+ thumbnailTransformation.getMatrix().getValues(tmpFloats);
+ if (WindowManagerService.SHOW_TRANSACTIONS) service.logSurface(thumbnail,
+ "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
+ + ", " + tmpFloats[Matrix.MTRANS_Y], null);
+ thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
+ if (WindowManagerService.SHOW_TRANSACTIONS) service.logSurface(thumbnail,
+ "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
+ + " layer=" + thumbnailLayer
+ + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
+ + "," + tmpFloats[Matrix.MSKEW_Y]
+ + "][" + tmpFloats[Matrix.MSKEW_X]
+ + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
+ thumbnail.setAlpha(thumbnailTransformation.getAlpha());
+ // The thumbnail is layered below the window immediately above this
+ // token's anim layer.
+ thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
+ - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
+ thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
+ tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
+ }
private boolean stepAnimation(long currentTime) {
if (animation == null) {
@@ -215,6 +274,7 @@
": more=" + more + ", xform=" + transformation);
if (!more) {
animation = null;
+ clearThumbnail();
if (WindowManagerService.DEBUG_ANIM) Slog.v(
WindowManagerService.TAG, "Finished animation in " + this +
" @ " + currentTime);
@@ -243,12 +303,22 @@
" @ " + currentTime + ": dw=" + dw + " dh=" + dh
+ " scale=" + service.mTransitionAnimationScale
+ " allDrawn=" + allDrawn + " animating=" + animating);
- animation.initialize(dw, dh, dw, dh);
+ if (!animInitialized) {
+ animation.initialize(dw, dh, dw, dh);
+ }
animation.setStartTime(currentTime);
animating = true;
+ if (thumbnail != null) {
+ thumbnail.show();
+ thumbnailAnimation.setStartTime(currentTime);
+ }
}
if (stepAnimation(currentTime)) {
- // we're done!
+ // animation isn't over, step any thumbnail and that's
+ // it for now.
+ if (thumbnail != null) {
+ stepThumbnailAnimation(currentTime);
+ }
return true;
}
}
@@ -440,6 +510,15 @@
pw.print(" startingDisplayed="); pw.print(startingDisplayed);
pw.print(" startingMoved"); pw.println(startingMoved);
}
+ if (thumbnail != null) {
+ pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
+ pw.print(" x="); pw.print(thumbnailX);
+ pw.print(" y="); pw.print(thumbnailY);
+ pw.print(" layer="); pw.println(thumbnailLayer);
+ pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
+ pw.print(prefix); pw.print("thumbnailTransformation=");
+ pw.println(thumbnailTransformation.toShortString());
+ }
}
@Override
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index b3dbee1..7aa6716 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -23,7 +23,7 @@
* on behalf of WindowManagerService.
*/
public class WindowAnimator {
- private static final String TAG = "WindowAnimations";
+ private static final String TAG = "WindowAnimator";
final WindowManagerService mService;
final Context mContext;
@@ -67,8 +67,24 @@
final int NAT = mService.mAppTokens.size();
for (i=0; i<NAT; i++) {
final AppWindowToken appToken = mService.mAppTokens.get(i);
+ final boolean wasAnimating = appToken.animation != null;
if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
mAnimating = true;
+ } else if (wasAnimating) {
+ // stopped animating, do one more pass through the layout
+ mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ }
+
+ final int NEAT = mService.mExitingAppTokens.size();
+ for (i=0; i<NEAT; i++) {
+ final AppWindowToken appToken = mService.mExitingAppTokens.get(i);
+ final boolean wasAnimating = appToken.animation != null;
+ if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
+ mAnimating = true;
+ } else if (wasAnimating) {
+ // stopped animating, do one more pass through the layout
+ mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
}
@@ -273,6 +289,15 @@
w.performShowLocked();
mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
}
+ if (atoken != null && atoken.thumbnail != null) {
+ if (atoken.thumbnailTransactionSeq != mTransactionSequence) {
+ atoken.thumbnailTransactionSeq = mTransactionSequence;
+ atoken.thumbnailLayer = 0;
+ }
+ if (atoken.thumbnailLayer < w.mAnimLayer) {
+ atoken.thumbnailLayer = w.mAnimLayer;
+ }
+ }
} // end forall windows
}
@@ -517,6 +542,7 @@
}
void animate() {
+ mPendingLayoutChanges = 0;
mCurrentTime = SystemClock.uptimeMillis();
// Update animations of all applications, including those
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 26367d2..a978b35 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -117,8 +117,12 @@
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerPolicy.FakeWindow;
+import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.ScaleAnimation;
import android.view.animation.Transformation;
import java.io.BufferedWriter;
@@ -194,6 +198,18 @@
static final int LAYER_OFFSET_DIM = 1;
/**
+ * Blur surface layer is immediately below dim layer.
+ */
+ static final int LAYER_OFFSET_BLUR = 2;
+
+ /**
+ * Animation thumbnail is as far as possible below the window above
+ * the thumbnail (or in other words as far as possible above the window
+ * below it).
+ */
+ static final int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER-1;
+
+ /**
* Layer at which to put the rotation freeze snapshot.
*/
static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1;
@@ -479,8 +495,12 @@
// made visible or hidden at the next transition.
int mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
String mNextAppTransitionPackage;
+ Bitmap mNextAppTransitionThumbnail;
+ IRemoteCallback mNextAppTransitionCallback;
int mNextAppTransitionEnter;
int mNextAppTransitionExit;
+ int mNextAppTransitionStartX;
+ int mNextAppTransitionStartY;
boolean mAppTransitionReady = false;
boolean mAppTransitionRunning = false;
boolean mAppTransitionTimeout = false;
@@ -588,6 +608,9 @@
}
LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields();
+ /** Only do a maximum of 6 repeated layouts. After that quit */
+ private int mLayoutRepeatCount;
+
private final class AnimationRunnable implements Runnable {
@Override
public void run() {
@@ -1897,7 +1920,7 @@
rawChanged = true;
}
- if (rawChanged && (wallpaperWin.getAttrs().privateFlags &
+ if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
try {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
@@ -2296,7 +2319,7 @@
if (wasVisible) {
int transit = WindowManagerPolicy.TRANSIT_EXIT;
- if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
+ if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
// Try starting an animation.
@@ -2441,6 +2464,15 @@
Slog.i(TAG, str);
}
}
+
+ static void logSurface(Surface s, String title, String msg, RuntimeException where) {
+ String str = " SURFACE " + s + ": " + msg + " / " + title;
+ if (where != null) {
+ Slog.i(TAG, str, where);
+ } else {
+ Slog.i(TAG, str);
+ }
+ }
void setTransparentRegionWindow(Session session, IWindow client, Region region) {
long origId = Binder.clearCallingIdentity();
@@ -2761,7 +2793,7 @@
// Try starting an animation; if there isn't one, we
// can destroy the surface right away.
int transit = WindowManagerPolicy.TRANSIT_EXIT;
- if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
+ if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
if (!win.mSurfacePendingDestroy && win.isWinVisibleLw() &&
@@ -3081,6 +3113,63 @@
return null;
}
+ private Animation createThumbnailAnimationLocked(int transit,
+ boolean enter, boolean thumb) {
+ Animation a;
+ final float thumbWidth = mNextAppTransitionThumbnail.getWidth();
+ final float thumbHeight = mNextAppTransitionThumbnail.getHeight();
+ // Pick the desired duration. If this is an inter-activity transition,
+ // it is the standard duration for that. Otherwise we use the longer
+ // task transition duration.
+ int duration;
+ switch (transit) {
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+ duration = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_shortAnimTime);
+ break;
+ default:
+ duration = 500;
+ break;
+
+ }
+ if (thumb) {
+ // Animation for zooming thumbnail from its initial size to
+ // filling the screen.
+ Animation scale = new ScaleAnimation(
+ 1, mAppDisplayWidth/thumbWidth,
+ 1, mAppDisplayHeight/thumbHeight,
+ mNextAppTransitionStartX + thumbWidth/2,
+ mNextAppTransitionStartY + thumbHeight/2);
+ AnimationSet set = new AnimationSet(true);
+ Animation alpha = new AlphaAnimation(1, 0);
+ scale.setDuration(duration);
+ set.addAnimation(scale);
+ alpha.setDuration(duration);
+ set.addAnimation(alpha);
+ a = set;
+ } else if (enter) {
+ // Entering app zooms out from the center of the thumbnail.
+ a = new ScaleAnimation(
+ thumbWidth/mAppDisplayWidth, 1,
+ thumbHeight/mAppDisplayHeight, 1,
+ mNextAppTransitionStartX + thumbWidth/2,
+ mNextAppTransitionStartY + thumbHeight/2);
+ a.setDuration(duration);
+ } else {
+ // Exiting app just holds in place.
+ a = new AlphaAnimation(1, 1);
+ a.setDuration(duration);
+ }
+ a.setFillAfter(true);
+ final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
+ com.android.internal.R.interpolator.decelerate_quint);
+ a.setInterpolator(interpolator);
+ a.initialize(mAppDisplayWidth, mAppDisplayHeight,
+ mAppDisplayWidth, mAppDisplayHeight);
+ return a;
+ }
+
private boolean applyAnimationLocked(AppWindowToken wtoken,
WindowManager.LayoutParams lp, int transit, boolean enter) {
// Only apply an animation if the display isn't frozen. If it is
@@ -3089,7 +3178,11 @@
// is running.
if (okToDisplay()) {
Animation a;
- if (mNextAppTransitionPackage != null) {
+ boolean initialized = false;
+ if (mNextAppTransitionThumbnail != null) {
+ a = createThumbnailAnimationLocked(transit, enter, false);
+ initialized = true;
+ } else if (mNextAppTransitionPackage != null) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
mNextAppTransitionEnter : mNextAppTransitionExit);
} else {
@@ -3161,7 +3254,7 @@
}
Slog.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
}
- wtoken.setAnimation(a);
+ wtoken.setAnimation(a, initialized);
}
} else {
wtoken.clearAnimation();
@@ -3689,11 +3782,23 @@
int enterAnim, int exitAnim) {
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
mNextAppTransitionPackage = packageName;
+ mNextAppTransitionThumbnail = null;
mNextAppTransitionEnter = enterAnim;
mNextAppTransitionExit = exitAnim;
}
}
+ public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
+ int startY, IRemoteCallback startedCallback) {
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+ mNextAppTransitionPackage = null;
+ mNextAppTransitionThumbnail = srcThumb;
+ mNextAppTransitionStartX = startX;
+ mNextAppTransitionStartY = startY;
+ mNextAppTransitionCallback = startedCallback;
+ }
+ }
+
public void executeAppTransition() {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"executeAppTransition()")) {
@@ -3837,6 +3942,19 @@
mH.sendMessageAtFrontOfQueue(m);
return;
}
+ if (ttoken.thumbnail != null) {
+ // The old token is animating with a thumbnail, transfer
+ // that to the new token.
+ if (wtoken.thumbnail != null) {
+ wtoken.thumbnail.destroy();
+ }
+ wtoken.thumbnail = ttoken.thumbnail;
+ wtoken.thumbnailX = ttoken.thumbnailX;
+ wtoken.thumbnailY = ttoken.thumbnailY;
+ wtoken.thumbnailLayer = ttoken.thumbnailLayer;
+ wtoken.thumbnailAnimation = ttoken.thumbnailAnimation;
+ ttoken.thumbnail = null;
+ }
}
}
@@ -4232,6 +4350,7 @@
// Make sure there is no animation running on this token,
// so any windows associated with it will be removed as
// soon as their animations are complete
+ wtoken.clearAnimation();
wtoken.animation = null;
wtoken.animating = false;
}
@@ -7459,10 +7578,25 @@
} else {
mInLayout = false;
- if (mLayoutNeeded) {
- requestTraversalLocked();
- }
}
+
+ if (mLayoutNeeded) {
+ if (++mLayoutRepeatCount < 6) {
+ requestTraversalLocked();
+ } else {
+ Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
+ mLayoutRepeatCount = 0;
+ }
+ } else {
+ mLayoutRepeatCount = 0;
+ }
+
+ if (mAnimator.mAnimating) {
+ // Do this even if requestTraversalLocked was called above so we get a frame drawn
+ // at the proper time as well as the one drawn early.
+ scheduleAnimationLocked();
+ }
+
if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
@@ -7784,11 +7918,15 @@
animLp = null;
}
+ AppWindowToken topOpeningApp = null;
+ int topOpeningLayer = 0;
+
NN = mOpeningApps.size();
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mOpeningApps.get(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Now opening app" + wtoken);
+ wtoken.clearThumbnail();
wtoken.reportedVisible = false;
wtoken.inPendingTransaction = false;
wtoken.animation = null;
@@ -7797,12 +7935,26 @@
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToShow = false;
mAnimator.mAnimating |= wtoken.showAllWindowsLocked();
+ if (animLp != null) {
+ int layer = -1;
+ for (int j=0; j<wtoken.windows.size(); j++) {
+ WindowState win = wtoken.windows.get(j);
+ if (win.mAnimLayer > layer) {
+ layer = win.mAnimLayer;
+ }
+ }
+ if (topOpeningApp == null || layer > topOpeningLayer) {
+ topOpeningApp = wtoken;
+ topOpeningLayer = layer;
+ }
+ }
}
NN = mClosingApps.size();
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mClosingApps.get(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Now closing app" + wtoken);
+ wtoken.clearThumbnail();
wtoken.inPendingTransaction = false;
wtoken.animation = null;
setTokenVisibilityLocked(wtoken, animLp, false,
@@ -7815,7 +7967,47 @@
wtoken.allDrawn = true;
}
+ if (mNextAppTransitionThumbnail != null && topOpeningApp != null
+ && topOpeningApp.animation != null) {
+ // This thumbnail animation is very special, we need to have
+ // an extra surface with the thumbnail included with the animation.
+ Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
+ mNextAppTransitionThumbnail.getHeight());
+ try {
+ Surface surface = new Surface(mFxSession, Process.myPid(),
+ "thumbnail anim", 0, dirty.width(), dirty.height(),
+ PixelFormat.TRANSLUCENT, Surface.HIDDEN);
+ topOpeningApp.thumbnail = surface;
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " THUMBNAIL "
+ + surface + ": CREATE");
+ Surface drawSurface = new Surface();
+ drawSurface.copyFrom(surface);
+ Canvas c = drawSurface.lockCanvas(dirty);
+ c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
+ drawSurface.unlockCanvasAndPost(c);
+ drawSurface.release();
+ topOpeningApp.thumbnailLayer = topOpeningLayer;
+ Animation anim = createThumbnailAnimationLocked(transit, true, true);
+ topOpeningApp.thumbnailAnimation = anim;
+ anim.restrictDuration(MAX_ANIMATION_DURATION);
+ anim.scaleCurrentDuration(mTransitionAnimationScale);
+ topOpeningApp.thumbnailX = mNextAppTransitionStartX;
+ topOpeningApp.thumbnailY = mNextAppTransitionStartY;
+ } catch (Surface.OutOfResourcesException e) {
+ Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
+ + " h=" + dirty.height(), e);
+ topOpeningApp.clearThumbnail();
+ }
+ }
+
mNextAppTransitionPackage = null;
+ mNextAppTransitionThumbnail = null;
+ if (mNextAppTransitionCallback != null) {
+ try {
+ mNextAppTransitionCallback.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
mOpeningApps.clear();
mClosingApps.clear();
@@ -8192,6 +8384,7 @@
mLayoutNeeded = true;
}
}
+
if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
if (updateOrientationFromAppTokensLocked(true)) {
@@ -8199,6 +8392,7 @@
mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
+
if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
mLayoutNeeded = true;
}
@@ -8400,6 +8594,7 @@
// Make sure there is no animation running on this token,
// so any windows associated with it will be removed as
// soon as their animations are complete
+ token.clearAnimation();
token.animation = null;
token.animating = false;
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
@@ -8409,8 +8604,6 @@
}
}
- boolean needRelayout = false;
-
if (!mAnimator.mAnimating && mAppTransitionRunning) {
// We have finished the animation of an app transition. To do
// this, we have delayed a lot of operations like showing and
@@ -8419,7 +8612,7 @@
// be out of sync with it. So here we will just rebuild the
// entire app window list. Fun!
mAppTransitionRunning = false;
- needRelayout = true;
+ mLayoutNeeded = true;
rebuildAppWindowListLocked();
assignLayersLocked();
// Clear information about apps that were moving.
@@ -8430,19 +8623,10 @@
mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
}
if (wallpaperDestroyed) {
- needRelayout = adjustWallpaperWindowsLocked() != 0;
+ mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
}
- if ((mPendingLayoutChanges & (
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER |
- ADJUST_WALLPAPER_LAYERS_CHANGED |
- WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG |
- WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
- needRelayout = true;
- }
- if (needRelayout) {
- requestTraversalLocked();
- } else if (mAnimator.mAnimating) {
- scheduleAnimationLocked();
+ if (mPendingLayoutChanges != 0) {
+ mLayoutNeeded = true;
}
// Finally update all input windows now that the window changes have stabilized.
@@ -8485,7 +8669,7 @@
}
}
- if (mInnerFields.mOrientationChangeComplete && !needRelayout &&
+ if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded &&
!mInnerFields.mUpdateRotation) {
checkDrawnWindowsLocked();
}
@@ -8839,6 +9023,7 @@
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
mNextAppTransitionPackage = null;
+ mNextAppTransitionThumbnail = null;
mAppTransitionReady = true;
}
@@ -9399,6 +9584,12 @@
pw.print(" mNextAppTransitionExit=0x");
pw.print(Integer.toHexString(mNextAppTransitionExit));
}
+ if (mNextAppTransitionThumbnail != null) {
+ pw.print(" mNextAppTransitionThumbnail=");
+ pw.print(mNextAppTransitionThumbnail);
+ pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
+ pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
+ }
pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
index 4cacbc4..cceed16 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
@@ -39,7 +39,7 @@
@SmallTest
public void testREORDER_TASKS() {
try {
- mAm.moveTaskToFront(0, 0);
+ mAm.moveTaskToFront(0, 0, null);
fail("IActivityManager.moveTaskToFront did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 945b3cd7..5256b58 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -85,15 +85,18 @@
// ------ Native Delegates ------
@LayoutlibDelegate
- /*package*/ static void nativeSetDefaultConfig(int nativeConfig) {
- // pass
+ /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
+ Rect padding, Options opts) {
+ return nativeDecodeStream(is, storage, padding, opts, false, 1.f);
}
@LayoutlibDelegate
- /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
- Rect padding, Options opts) {
+ /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
+ Rect padding, Options opts, boolean applyScale, float scale) {
Bitmap bm = null;
+ //TODO support rescaling
+
Density density = Density.MEDIUM;
if (opts != null) {
density = Density.getEnum(opts.inDensity);
@@ -147,6 +150,13 @@
}
@LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts,
+ boolean applyScale, float scale) {
+ opts.inBitmap = null;
+ return null;
+ }
+
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
int length, Options opts) {
opts.inBitmap = null;
diff --git a/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Delegate.java
new file mode 100644
index 0000000..14b84ef
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Delegate.java
@@ -0,0 +1,34 @@
+/*
+ * 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.view;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link ViewRootImpl}
+ *
+ * Through the layoutlib_create tool, the original methods of ViewRootImpl have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class ViewRootImpl_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isInTouchMode() {
+ return false; // this allows displaying selection.
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index bef2c95..8b1d41a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -340,6 +340,12 @@
}
@Override
+ public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
+ IRemoteCallback startedCallback) throws RemoteException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 170cd6a..79e02c8 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -114,6 +114,7 @@
"android.view.LayoutInflater#rInflate",
"android.view.LayoutInflater#parseInclude",
"android.view.View#isInEditMode",
+ "android.view.ViewRootImpl#isInTouchMode",
"android.view.inputmethod.InputMethodManager#getInstance",
"android.util.Log#println_native",
"com.android.internal.util.XmlUtils#convertValueToInt",