Skip to content

Commit 8437587

Browse files
author
Dianne Hackborn
committed
Work on issue #6579997: Mariner entrance animation
Add a new variation of ActivityOptions that allows you to supply custom animation resources and get a callback when the animation starts. Use this in SearchPanelView to determine when to start hiding the search panel instead of having a fixed delay. Fix some issues in the activity manager where we would cancel the options in cases where we should actually keep them to give to the window manager for a transition. (Basically when the activity being started is not actually ending up launched, but just results in a shift in the activity stack.) Note that this is not quite what the design calls for -- the entire search UI is waiting and then disappearing when the animation starts, instead of the ring first disappearing while waiting for the time to fade out the circle. Change-Id: Iee9a404ba530908d73cdbd4a9d0d2907ac03428f
1 parent ea01e4a commit 8437587

File tree

8 files changed

+170
-73
lines changed

8 files changed

+170
-73
lines changed

core/java/android/app/ActivityOptions.java

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,55 @@ public class ActivityOptions {
127127
*/
128128
public static ActivityOptions makeCustomAnimation(Context context,
129129
int enterResId, int exitResId) {
130+
return makeCustomAnimation(context, enterResId, exitResId, null, null);
131+
}
132+
133+
/**
134+
* Create an ActivityOptions specifying a custom animation to run when
135+
* the activity is displayed.
136+
*
137+
* @param context Who is defining this. This is the application that the
138+
* animation resources will be loaded from.
139+
* @param enterResId A resource ID of the animation resource to use for
140+
* the incoming activity. Use 0 for no animation.
141+
* @param exitResId A resource ID of the animation resource to use for
142+
* the outgoing activity. Use 0 for no animation.
143+
* @param handler If <var>listener</var> is non-null this must be a valid
144+
* Handler on which to dispatch the callback; otherwise it should be null.
145+
* @param listener Optional OnAnimationStartedListener to find out when the
146+
* requested animation has started running. If for some reason the animation
147+
* is not executed, the callback will happen immediately.
148+
* @return Returns a new ActivityOptions object that you can use to
149+
* supply these options as the options Bundle when starting an activity.
150+
* @hide
151+
*/
152+
public static ActivityOptions makeCustomAnimation(Context context,
153+
int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) {
130154
ActivityOptions opts = new ActivityOptions();
131155
opts.mPackageName = context.getPackageName();
132156
opts.mAnimationType = ANIM_CUSTOM;
133157
opts.mCustomEnterResId = enterResId;
134158
opts.mCustomExitResId = exitResId;
159+
opts.setListener(handler, listener);
135160
return opts;
136161
}
137162

163+
private void setListener(Handler handler, OnAnimationStartedListener listener) {
164+
if (listener != null) {
165+
final Handler h = handler;
166+
final OnAnimationStartedListener finalListener = listener;
167+
mAnimationStartedListener = new IRemoteCallback.Stub() {
168+
@Override public void sendResult(Bundle data) throws RemoteException {
169+
h.post(new Runnable() {
170+
@Override public void run() {
171+
finalListener.onAnimationStarted();
172+
}
173+
});
174+
}
175+
};
176+
}
177+
}
178+
138179
/**
139180
* Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
140181
* to find out when the given animation has started running.
@@ -258,19 +299,7 @@ private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
258299
source.getLocationOnScreen(pts);
259300
opts.mStartX = pts[0] + startX;
260301
opts.mStartY = pts[1] + startY;
261-
if (listener != null) {
262-
final Handler h = source.getHandler();
263-
final OnAnimationStartedListener finalListener = listener;
264-
opts.mAnimationStartedListener = new IRemoteCallback.Stub() {
265-
@Override public void sendResult(Bundle data) throws RemoteException {
266-
h.post(new Runnable() {
267-
@Override public void run() {
268-
finalListener.onAnimationStarted();
269-
}
270-
});
271-
}
272-
};
273-
}
302+
opts.setListener(source.getHandler(), listener);
274303
return opts;
275304
}
276305

@@ -284,6 +313,8 @@ public ActivityOptions(Bundle opts) {
284313
if (mAnimationType == ANIM_CUSTOM) {
285314
mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
286315
mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
316+
mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
317+
opts.getIBinder(KEY_ANIM_START_LISTENER));
287318
} else if (mAnimationType == ANIM_SCALE_UP) {
288319
mStartX = opts.getInt(KEY_ANIM_START_X, 0);
289320
mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
@@ -381,14 +412,27 @@ public void update(ActivityOptions otherOptions) {
381412
mCustomEnterResId = otherOptions.mCustomEnterResId;
382413
mCustomExitResId = otherOptions.mCustomExitResId;
383414
mThumbnail = null;
384-
mAnimationStartedListener = null;
415+
if (otherOptions.mAnimationStartedListener != null) {
416+
try {
417+
otherOptions.mAnimationStartedListener.sendResult(null);
418+
} catch (RemoteException e) {
419+
}
420+
}
421+
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
385422
break;
386423
case ANIM_SCALE_UP:
387424
mAnimationType = otherOptions.mAnimationType;
388425
mStartX = otherOptions.mStartX;
389426
mStartY = otherOptions.mStartY;
390427
mStartWidth = otherOptions.mStartWidth;
391428
mStartHeight = otherOptions.mStartHeight;
429+
if (otherOptions.mAnimationStartedListener != null) {
430+
try {
431+
otherOptions.mAnimationStartedListener.sendResult(null);
432+
} catch (RemoteException e) {
433+
}
434+
}
435+
mAnimationStartedListener = null;
392436
break;
393437
case ANIM_THUMBNAIL:
394438
case ANIM_THUMBNAIL_DELAYED:
@@ -425,6 +469,8 @@ public Bundle toBundle() {
425469
b.putInt(KEY_ANIM_TYPE, mAnimationType);
426470
b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
427471
b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
472+
b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
473+
!= null ? mAnimationStartedListener.asBinder() : null);
428474
break;
429475
case ANIM_SCALE_UP:
430476
b.putInt(KEY_ANIM_TYPE, mAnimationType);

core/java/android/view/IWindowManager.aidl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ interface IWindowManager
8080
void setFocusedApp(IBinder token, boolean moveFocusNow);
8181
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
8282
int getPendingAppTransition();
83-
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim);
83+
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
84+
IRemoteCallback startedCallback);
8485
void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
8586
int startHeight);
8687
void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,

packages/SystemUI/res/anim/search_launch_enter.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222

2323
<alpha android:fromAlpha="0" android:toAlpha="1.0"
2424
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
25-
android:interpolator="@android:interpolator/decelerate_quad"
25+
android:interpolator="@android:interpolator/decelerate_cubic"
2626
android:duration="300"/>
2727

28-
<translate android:fromYDelta="200" android:toYDelta="0"
28+
<translate android:fromYDelta="100%" android:toYDelta="0"
2929
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
3030
android:interpolator="@android:interpolator/decelerate_cubic"
3131
android:duration="300" />

packages/SystemUI/src/com/android/systemui/SearchPanelView.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
import com.android.systemui.statusbar.tablet.TabletStatusBar;
4747

4848
public class SearchPanelView extends FrameLayout implements
49-
StatusBarPanel {
50-
private static final int SEARCH_PANEL_HOLD_DURATION = 500;
49+
StatusBarPanel, ActivityOptions.OnAnimationStartedListener {
50+
private static final int SEARCH_PANEL_HOLD_DURATION = 0;
5151
static final String TAG = "SearchPanelView";
5252
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
5353
private final Context mContext;
@@ -113,18 +113,18 @@ private void startAssistActivity() {
113113
if (intent == null) return;
114114
try {
115115
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
116-
R.anim.search_launch_enter, R.anim.search_launch_exit);
116+
R.anim.search_launch_enter, R.anim.search_launch_exit,
117+
getHandler(), this);
117118
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
118119
mContext.startActivity(intent, opts.toBundle());
119120
} catch (ActivityNotFoundException e) {
120121
Slog.w(TAG, "Activity not found for " + intent.getAction());
122+
onAnimationStarted();
121123
}
122124
}
123125

124-
final MultiWaveView.OnTriggerListener mMultiWaveViewListener
125-
= new MultiWaveView.OnTriggerListener() {
126-
127-
private boolean mWaitingForLaunch;
126+
class MultiWaveTriggerListener implements MultiWaveView.OnTriggerListener {
127+
boolean mWaitingForLaunch;
128128

129129
public void onGrabbed(View v, int handle) {
130130
}
@@ -145,19 +145,24 @@ public void onTrigger(View v, final int target) {
145145
mWaitingForLaunch = true;
146146
startAssistActivity();
147147
vibrate();
148-
postDelayed(new Runnable() {
149-
public void run() {
150-
mWaitingForLaunch = false;
151-
mBar.hideSearchPanel();
152-
}
153-
}, SEARCH_PANEL_HOLD_DURATION);
154148
break;
155149
}
156150
}
157151

158152
public void onFinishFinalAnimation() {
159153
}
160-
};
154+
}
155+
final MultiWaveTriggerListener mMultiWaveViewListener = new MultiWaveTriggerListener();
156+
157+
@Override
158+
public void onAnimationStarted() {
159+
postDelayed(new Runnable() {
160+
public void run() {
161+
mMultiWaveViewListener.mWaitingForLaunch = false;
162+
mBar.hideSearchPanel();
163+
}
164+
}, SEARCH_PANEL_HOLD_DURATION);
165+
}
161166

162167
@Override
163168
protected void onFinishInflate() {

services/java/com/android/server/am/ActivityManagerService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2804,7 +2804,7 @@ public void overridePendingTransition(IBinder token, String packageName,
28042804
if (self.state == ActivityState.RESUMED
28052805
|| self.state == ActivityState.PAUSING) {
28062806
mWindowManager.overridePendingAppTransition(packageName,
2807-
enterAnim, exitAnim);
2807+
enterAnim, exitAnim, null);
28082808
}
28092809

28102810
Binder.restoreCallingIdentity(origId);

services/java/com/android/server/am/ActivityRecord.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,8 @@ void applyOptionsLocked() {
558558
service.mWindowManager.overridePendingAppTransition(
559559
pendingOptions.getPackageName(),
560560
pendingOptions.getCustomEnterResId(),
561-
pendingOptions.getCustomExitResId());
561+
pendingOptions.getCustomExitResId(),
562+
pendingOptions.getOnAnimationStartListener());
562563
break;
563564
case ActivityOptions.ANIM_SCALE_UP:
564565
service.mWindowManager.overridePendingAppTransitionScaleUp(

services/java/com/android/server/am/ActivityStack.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,10 @@ final void ensureActivitiesVisibleLocked(ActivityRecord starting,
13711371
* nothing happened.
13721372
*/
13731373
final boolean resumeTopActivityLocked(ActivityRecord prev) {
1374+
return resumeTopActivityLocked(prev, null);
1375+
}
1376+
1377+
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
13741378
// Find the first activity that is not finishing.
13751379
ActivityRecord next = topRunningActivityLocked(null);
13761380

@@ -1383,6 +1387,7 @@ final boolean resumeTopActivityLocked(ActivityRecord prev) {
13831387
// There are no more activities! Let's just start up the
13841388
// Launcher...
13851389
if (mMainStack) {
1390+
ActivityOptions.abort(options);
13861391
return mService.startHomeActivityLocked(0);
13871392
}
13881393
}
@@ -1395,6 +1400,7 @@ final boolean resumeTopActivityLocked(ActivityRecord prev) {
13951400
// should be nothing left to do at this point.
13961401
mService.mWindowManager.executeAppTransition();
13971402
mNoAnimActivities.clear();
1403+
ActivityOptions.abort(options);
13981404
return false;
13991405
}
14001406

@@ -1409,6 +1415,7 @@ final boolean resumeTopActivityLocked(ActivityRecord prev) {
14091415
// should be nothing left to do at this point.
14101416
mService.mWindowManager.executeAppTransition();
14111417
mNoAnimActivities.clear();
1418+
ActivityOptions.abort(options);
14121419
return false;
14131420
}
14141421

@@ -1419,6 +1426,8 @@ final boolean resumeTopActivityLocked(ActivityRecord prev) {
14191426
next.sleeping = false;
14201427
mWaitingVisibleActivities.remove(next);
14211428

1429+
next.updateOptionsLocked(options);
1430+
14221431
if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
14231432

14241433
// If we are currently pausing an activity, then don't do anything
@@ -2666,6 +2675,7 @@ final int startActivityUncheckedLocked(ActivityRecord r,
26662675
movedHome = true;
26672676
moveHomeToFrontFromLaunchLocked(launchFlags);
26682677
moveTaskToFrontLocked(taskTop.task, r, options);
2678+
options = null;
26692679
}
26702680
}
26712681
// If the caller has requested that the target task be
@@ -2679,9 +2689,10 @@ final int startActivityUncheckedLocked(ActivityRecord r,
26792689
// is the case, so this is it! And for paranoia, make
26802690
// sure we have correctly resumed the top activity.
26812691
if (doResume) {
2682-
resumeTopActivityLocked(null);
2692+
resumeTopActivityLocked(null, options);
2693+
} else {
2694+
ActivityOptions.abort(options);
26832695
}
2684-
ActivityOptions.abort(options);
26852696
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
26862697
}
26872698
if ((launchFlags &
@@ -2767,9 +2778,10 @@ final int startActivityUncheckedLocked(ActivityRecord r,
27672778
// don't use that intent!) And for paranoia, make
27682779
// sure we have correctly resumed the top activity.
27692780
if (doResume) {
2770-
resumeTopActivityLocked(null);
2781+
resumeTopActivityLocked(null, options);
2782+
} else {
2783+
ActivityOptions.abort(options);
27712784
}
2772-
ActivityOptions.abort(options);
27732785
return ActivityManager.START_TASK_TO_FRONT;
27742786
}
27752787
}

0 commit comments

Comments
 (0)