Skip to content

Commit 8078d8c

Browse files
author
Dianne Hackborn
committed
Add new thumbnail animation.
Use it for recent tasks switching. Not perfect yet by far, but something. Also fix issue #6186758: Twitter crashes after tapping on a tweet on JRM75D Change-Id: I49bf6c94aafde875ac652dedaf96d6c08cc9e7d2
1 parent 3c4da3c commit 8078d8c

File tree

19 files changed

+598
-49
lines changed

19 files changed

+598
-49
lines changed

api/current.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,6 +2744,7 @@ package android.app {
27442744
method public static boolean isUserAMonkey();
27452745
method public void killBackgroundProcesses(java.lang.String);
27462746
method public void moveTaskToFront(int, int);
2747+
method public void moveTaskToFront(int, int, android.os.Bundle);
27472748
method public deprecated void restartPackage(java.lang.String);
27482749
field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
27492750
field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -2867,9 +2868,14 @@ package android.app {
28672868
public class ActivityOptions {
28682869
method public void join(android.app.ActivityOptions);
28692870
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
2871+
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int, android.app.ActivityOptions.OnAnimationStartedListener);
28702872
method public android.os.Bundle toBundle();
28712873
}
28722874

2875+
public static abstract interface ActivityOptions.OnAnimationStartedListener {
2876+
method public abstract void onAnimationStarted();
2877+
}
2878+
28732879
public class AlarmManager {
28742880
method public void cancel(android.app.PendingIntent);
28752881
method public void set(int, long, android.app.PendingIntent);

core/java/android/app/Activity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3639,7 +3639,7 @@ public boolean startNextMatchingActivity(Intent intent, Bundle options) {
36393639
*/
36403640
public void startActivityFromChild(Activity child, Intent intent,
36413641
int requestCode) {
3642-
startActivityFromChild(child, intent, requestCode);
3642+
startActivityFromChild(child, intent, requestCode, null);
36433643
}
36443644

36453645
/**

core/java/android/app/ActivityManager.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import android.graphics.Bitmap;
3232
import android.graphics.Point;
3333
import android.os.Binder;
34+
import android.os.Bundle;
3435
import android.os.Debug;
3536
import android.os.Handler;
3637
import android.os.Parcel;
@@ -815,6 +816,19 @@ public TaskThumbnails getTaskThumbnails(int id) throws SecurityException {
815816
*/
816817
public static final int MOVE_TASK_NO_USER_ACTION = 0x00000002;
817818

819+
/**
820+
* Equivalent to calling {@link #moveTaskToFront(int, int, Bundle)}
821+
* with a null options argument.
822+
*
823+
* @param taskId The identifier of the task to be moved, as found in
824+
* {@link RunningTaskInfo} or {@link RecentTaskInfo}.
825+
* @param flags Additional operational flags, 0 or more of
826+
* {@link #MOVE_TASK_WITH_HOME}.
827+
*/
828+
public void moveTaskToFront(int taskId, int flags) {
829+
moveTaskToFront(taskId, flags, null);
830+
}
831+
818832
/**
819833
* Ask that the task associated with a given task ID be moved to the
820834
* front of the stack, so it is now visible to the user. Requires that
@@ -825,10 +839,13 @@ public TaskThumbnails getTaskThumbnails(int id) throws SecurityException {
825839
* {@link RunningTaskInfo} or {@link RecentTaskInfo}.
826840
* @param flags Additional operational flags, 0 or more of
827841
* {@link #MOVE_TASK_WITH_HOME}.
842+
* @param options Additional options for the operation, either null or
843+
* as per {@link Context#startActivity(Intent, android.os.Bundle)
844+
* Context.startActivity(Intent, Bundle)}.
828845
*/
829-
public void moveTaskToFront(int taskId, int flags) {
846+
public void moveTaskToFront(int taskId, int flags, Bundle options) {
830847
try {
831-
ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags);
848+
ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags, options);
832849
} catch (RemoteException e) {
833850
// System dead, we will be dead too soon!
834851
}

core/java/android/app/ActivityManagerNative.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,9 @@ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
510510
data.enforceInterface(IActivityManager.descriptor);
511511
int task = data.readInt();
512512
int fl = data.readInt();
513-
moveTaskToFront(task, fl);
513+
Bundle options = data.readInt() != 0
514+
? Bundle.CREATOR.createFromParcel(data) : null;
515+
moveTaskToFront(task, fl, options);
514516
reply.writeNoException();
515517
return true;
516518
}
@@ -2134,13 +2136,19 @@ public List<ApplicationInfo> getRunningExternalApplications()
21342136
reply.recycle();
21352137
return list;
21362138
}
2137-
public void moveTaskToFront(int task, int flags) throws RemoteException
2139+
public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException
21382140
{
21392141
Parcel data = Parcel.obtain();
21402142
Parcel reply = Parcel.obtain();
21412143
data.writeInterfaceToken(IActivityManager.descriptor);
21422144
data.writeInt(task);
21432145
data.writeInt(flags);
2146+
if (options != null) {
2147+
data.writeInt(1);
2148+
options.writeToParcel(data, 0);
2149+
} else {
2150+
data.writeInt(0);
2151+
}
21442152
mRemote.transact(MOVE_TASK_TO_FRONT_TRANSACTION, data, reply, 0);
21452153
reply.readException();
21462154
data.recycle();

core/java/android/app/ActivityOptions.java

Lines changed: 181 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717
package android.app;
1818

1919
import android.content.Context;
20+
import android.graphics.Bitmap;
2021
import android.os.Bundle;
22+
import android.os.Handler;
23+
import android.os.IRemoteCallback;
24+
import android.os.Message;
25+
import android.os.RemoteException;
26+
import android.view.View;
2127

2228
/**
2329
* Helper class for building an options Bundle that can be used with
@@ -31,6 +37,12 @@ public class ActivityOptions {
3137
*/
3238
public static final String KEY_PACKAGE_NAME = "android:packageName";
3339

40+
/**
41+
* Type of animation that arguments specify.
42+
* @hide
43+
*/
44+
public static final String KEY_ANIM_TYPE = "android:animType";
45+
3446
/**
3547
* Custom enter animation resource ID.
3648
* @hide
@@ -43,10 +55,45 @@ public class ActivityOptions {
4355
*/
4456
public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes";
4557

58+
/**
59+
* Bitmap for thumbnail animation.
60+
* @hide
61+
*/
62+
public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail";
63+
64+
/**
65+
* Start X position of thumbnail animation.
66+
* @hide
67+
*/
68+
public static final String KEY_ANIM_START_X = "android:animStartX";
69+
70+
/**
71+
* Start Y position of thumbnail animation.
72+
* @hide
73+
*/
74+
public static final String KEY_ANIM_START_Y = "android:animStartY";
75+
76+
/**
77+
* Callback for when animation is started.
78+
* @hide
79+
*/
80+
public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
81+
82+
/** @hide */
83+
public static final int ANIM_NONE = 0;
84+
/** @hide */
85+
public static final int ANIM_CUSTOM = 1;
86+
/** @hide */
87+
public static final int ANIM_THUMBNAIL = 2;
88+
4689
private String mPackageName;
47-
private boolean mIsCustomAnimation;
90+
private int mAnimationType = ANIM_NONE;
4891
private int mCustomEnterResId;
4992
private int mCustomExitResId;
93+
private Bitmap mThumbnail;
94+
private int mStartX;
95+
private int mStartY;
96+
private IRemoteCallback mAnimationStartedListener;
5097

5198
/**
5299
* Create an ActivityOptions specifying a custom animation to run when
@@ -65,22 +112,79 @@ public static ActivityOptions makeCustomAnimation(Context context,
65112
int enterResId, int exitResId) {
66113
ActivityOptions opts = new ActivityOptions();
67114
opts.mPackageName = context.getPackageName();
68-
opts.mIsCustomAnimation = true;
115+
opts.mAnimationType = ANIM_CUSTOM;
69116
opts.mCustomEnterResId = enterResId;
70117
opts.mCustomExitResId = exitResId;
71118
return opts;
72119
}
73120

121+
/**
122+
* Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
123+
* to find out when the given animation has started running.
124+
*/
125+
public interface OnAnimationStartedListener {
126+
void onAnimationStarted();
127+
}
128+
129+
/**
130+
* Create an ActivityOptions specifying an animation where a thumbnail
131+
* is scaled from a given position to the new activity window that is
132+
* being started.
133+
*
134+
* @param source The View that this thumbnail is animating from. This
135+
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
136+
* @param thumbnail The bitmap that will be shown as the initial thumbnail
137+
* of the animation.
138+
* @param startX The x starting location of the bitmap, in screen coordiantes.
139+
* @param startY The y starting location of the bitmap, in screen coordinates.
140+
* @param listener Optional OnAnimationStartedListener to find out when the
141+
* requested animation has started running. If for some reason the animation
142+
* is not executed, the callback will happen immediately.
143+
* @return Returns a new ActivityOptions object that you can use to
144+
* supply these options as the options Bundle when starting an activity.
145+
*/
146+
public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
147+
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
148+
ActivityOptions opts = new ActivityOptions();
149+
opts.mPackageName = source.getContext().getPackageName();
150+
opts.mAnimationType = ANIM_THUMBNAIL;
151+
opts.mThumbnail = thumbnail;
152+
int[] pts = new int[2];
153+
source.getLocationOnScreen(pts);
154+
opts.mStartX = pts[0] + startX;
155+
opts.mStartY = pts[1] + startY;
156+
if (listener != null) {
157+
final Handler h = source.getHandler();
158+
final OnAnimationStartedListener finalListener = listener;
159+
opts.mAnimationStartedListener = new IRemoteCallback.Stub() {
160+
@Override public void sendResult(Bundle data) throws RemoteException {
161+
h.post(new Runnable() {
162+
@Override public void run() {
163+
finalListener.onAnimationStarted();
164+
}
165+
});
166+
}
167+
};
168+
}
169+
return opts;
170+
}
171+
74172
private ActivityOptions() {
75173
}
76174

77175
/** @hide */
78176
public ActivityOptions(Bundle opts) {
79177
mPackageName = opts.getString(KEY_PACKAGE_NAME);
80-
if (opts.containsKey(KEY_ANIM_ENTER_RES_ID)) {
81-
mIsCustomAnimation = true;
178+
mAnimationType = opts.getInt(KEY_ANIM_TYPE);
179+
if (mAnimationType == ANIM_CUSTOM) {
82180
mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
83181
mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
182+
} else if (mAnimationType == ANIM_THUMBNAIL) {
183+
mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
184+
mStartX = opts.getInt(KEY_ANIM_START_X, 0);
185+
mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
186+
mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
187+
opts.getIBinder(KEY_ANIM_START_LISTENER));
84188
}
85189
}
86190

@@ -90,8 +194,8 @@ public String getPackageName() {
90194
}
91195

92196
/** @hide */
93-
public boolean isCustomAnimation() {
94-
return mIsCustomAnimation;
197+
public int getAnimationType() {
198+
return mAnimationType;
95199
}
96200

97201
/** @hide */
@@ -104,6 +208,43 @@ public int getCustomExitResId() {
104208
return mCustomExitResId;
105209
}
106210

211+
/** @hide */
212+
public Bitmap getThumbnail() {
213+
return mThumbnail;
214+
}
215+
216+
/** @hide */
217+
public int getStartX() {
218+
return mStartX;
219+
}
220+
221+
/** @hide */
222+
public int getStartY() {
223+
return mStartY;
224+
}
225+
226+
/** @hide */
227+
public IRemoteCallback getOnAnimationStartListener() {
228+
return mAnimationStartedListener;
229+
}
230+
231+
/** @hide */
232+
public void abort() {
233+
if (mAnimationStartedListener != null) {
234+
try {
235+
mAnimationStartedListener.sendResult(null);
236+
} catch (RemoteException e) {
237+
}
238+
}
239+
}
240+
241+
/** @hide */
242+
public static void abort(Bundle options) {
243+
if (options != null) {
244+
(new ActivityOptions(options)).abort();
245+
}
246+
}
247+
107248
/**
108249
* Join the values in <var>otherOptions</var> in to this one. Any values
109250
* defined in <var>otherOptions</var> replace those in the base options.
@@ -112,10 +253,27 @@ public void join(ActivityOptions otherOptions) {
112253
if (otherOptions.mPackageName != null) {
113254
mPackageName = otherOptions.mPackageName;
114255
}
115-
if (otherOptions.mIsCustomAnimation) {
116-
mIsCustomAnimation = true;
117-
mCustomEnterResId = otherOptions.mCustomEnterResId;
118-
mCustomExitResId = otherOptions.mCustomExitResId;
256+
switch (otherOptions.mAnimationType) {
257+
case ANIM_CUSTOM:
258+
mAnimationType = otherOptions.mAnimationType;
259+
mCustomEnterResId = otherOptions.mCustomEnterResId;
260+
mCustomExitResId = otherOptions.mCustomExitResId;
261+
mThumbnail = null;
262+
mAnimationStartedListener = null;
263+
break;
264+
case ANIM_THUMBNAIL:
265+
mAnimationType = otherOptions.mAnimationType;
266+
mThumbnail = otherOptions.mThumbnail;
267+
mStartX = otherOptions.mStartX;
268+
mStartY = otherOptions.mStartY;
269+
if (otherOptions.mAnimationStartedListener != null) {
270+
try {
271+
otherOptions.mAnimationStartedListener.sendResult(null);
272+
} catch (RemoteException e) {
273+
}
274+
}
275+
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
276+
break;
119277
}
120278
}
121279

@@ -132,9 +290,19 @@ public Bundle toBundle() {
132290
if (mPackageName != null) {
133291
b.putString(KEY_PACKAGE_NAME, mPackageName);
134292
}
135-
if (mIsCustomAnimation) {
136-
b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
137-
b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
293+
switch (mAnimationType) {
294+
case ANIM_CUSTOM:
295+
b.putInt(KEY_ANIM_TYPE, mAnimationType);
296+
b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
297+
b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
298+
break;
299+
case ANIM_THUMBNAIL:
300+
b.putInt(KEY_ANIM_TYPE, mAnimationType);
301+
b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
302+
b.putInt(KEY_ANIM_START_X, mStartX);
303+
b.putInt(KEY_ANIM_START_Y, mStartY);
304+
b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
305+
!= null ? mAnimationStartedListener.asBinder() : null);
138306
}
139307
return b;
140308
}

core/java/android/app/IActivityManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
105105
public List getServices(int maxNum, int flags) throws RemoteException;
106106
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
107107
throws RemoteException;
108-
public void moveTaskToFront(int task, int flags) throws RemoteException;
108+
public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException;
109109
public void moveTaskToBack(int task) throws RemoteException;
110110
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
111111
public void moveTaskBackwards(int task) throws RemoteException;

core/java/android/view/IWindowManager.aidl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ interface IWindowManager
8989
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
9090
int getPendingAppTransition();
9191
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim);
92+
void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
93+
IRemoteCallback startedCallback);
9294
void executeAppTransition();
9395
void setAppStartingWindow(IBinder token, String pkg, int theme,
9496
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,

0 commit comments

Comments
 (0)