Create end of animation callback for Activity
Activities cannot draw while their entering animations are active.
This change introduces a callback, onEnterAnimationComplete() so
that activities can know when their draws will be effective.
Fixes bug 13658460.
Change-Id: Ic48540cd4c7e37538f10cb2dc0852aa3f55d11e1
diff --git a/api/current.txt b/api/current.txt
index 569425f..4e0d311 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3392,6 +3392,7 @@
method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
method protected void onDestroy();
method public void onDetachedFromWindow();
+ method public void onEnterAnimationComplete();
method public boolean onGenericMotionEvent(android.view.MotionEvent);
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cac646d..2ebfa1d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5501,6 +5501,14 @@
}
/**
+ * Activities cannot draw during the period that their windows are animating in. In order
+ * to know when it is safe to begin drawing they can override this method which will be
+ * called when the entering animation has completed.
+ */
+ public void onEnterAnimationComplete() {
+ }
+
+ /**
* Adjust the current immersive mode setting.
*
* Note that changing this value will have no effect on the activity's
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 318a520..311a8f55 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2231,6 +2231,14 @@
reply.writeNoException();
return true;
}
+
+ case NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ notifyEnterAnimationComplete(token);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5146,5 +5154,18 @@
reply.recycle();
}
+ @Override
+ public void notifyEnterAnimationComplete(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION, data, reply,
+ IBinder.FLAG_ONEWAY);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 48954f4..0bab7b2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1163,6 +1163,10 @@
public void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean playing) {
sendMessage(H.BACKGROUND_MEDIA_PLAYING_CHANGED, token, playing ? 1 : 0);
}
+
+ public void scheduleEnterAnimationComplete(IBinder token) {
+ sendMessage(H.ENTER_ANIMATION_COMPLETE, token);
+ }
}
private class H extends Handler {
@@ -1215,6 +1219,7 @@
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
public static final int STOP_MEDIA_PLAYING = 147;
public static final int BACKGROUND_MEDIA_PLAYING_CHANGED = 148;
+ public static final int ENTER_ANIMATION_COMPLETE = 149;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1267,6 +1272,7 @@
case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS";
case STOP_MEDIA_PLAYING: return "STOP_MEDIA_PLAYING";
case BACKGROUND_MEDIA_PLAYING_CHANGED: return "BACKGROUND_MEDIA_PLAYING_CHANGED";
+ case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
}
}
return Integer.toString(code);
@@ -1491,6 +1497,9 @@
case BACKGROUND_MEDIA_PLAYING_CHANGED:
handleOnBackgroundMediaPlayingChanged((IBinder) msg.obj, msg.arg1 > 0);
break;
+ case ENTER_ANIMATION_COMPLETE:
+ handleEnterAnimationComplete((IBinder) msg.obj);
+ break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
@@ -2509,6 +2518,13 @@
installContentProviders(mInitialApplication, Lists.newArrayList(info));
}
+ private void handleEnterAnimationComplete(IBinder token) {
+ ActivityClientRecord r = mActivities.get(token);
+ if (r != null) {
+ r.activity.onEnterAnimationComplete();
+ }
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 0b4510fe..e9d4bd9 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -666,6 +666,15 @@
reply.writeNoException();
return true;
}
+
+ case ENTER_ANIMATION_COMPLETE_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ IBinder token = data.readStrongBinder();
+ scheduleEnterAnimationComplete(token);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1342,4 +1351,13 @@
mRemote.transact(BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
+
+ @Override
+ public void scheduleEnterAnimationComplete(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(ENTER_ANIMATION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 53c1408..5347f03 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -448,6 +448,7 @@
public void mediaResourcesReleased(IBinder token) throws RemoteException;
public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException;
+ public void notifyEnterAnimationComplete(IBinder token) throws RemoteException;
/*
* Private non-Binder interfaces
@@ -758,4 +759,5 @@
int MEDIA_RESOURCES_RELEASED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+227;
int NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+228;
int START_ACTIVITY_FROM_RECENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 229;
+ int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 18faf0e..4a1fda4 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -147,6 +147,7 @@
void updateTimePrefs(boolean is24Hour) throws RemoteException;
void scheduleStopMediaPlaying(IBinder token) throws RemoteException;
void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean enabled) throws RemoteException;
+ void scheduleEnterAnimationComplete(IBinder token) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -203,4 +204,5 @@
int UPDATE_TIME_PREFS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51;
int STOP_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52;
int BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53;
+ int ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fed68f9..314e906 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1158,6 +1158,7 @@
static final int UPDATE_TIME = 41;
static final int SYSTEM_USER_START_MSG = 42;
static final int SYSTEM_USER_CURRENT_MSG = 43;
+ static final int ENTER_ANIMATION_COMPLETE_MSG = 44;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1813,6 +1814,18 @@
mSystemServiceManager.switchUser(msg.arg1);
break;
}
+ case ENTER_ANIMATION_COMPLETE_MSG: {
+ synchronized (ActivityManagerService.this) {
+ ActivityRecord r = ActivityRecord.forToken((IBinder) msg.obj);
+ if (r != null && r.app != null && r.app.thread != null) {
+ try {
+ r.app.thread.scheduleEnterAnimationComplete(r.appToken);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ break;
+ }
}
}
};
@@ -5699,6 +5712,11 @@
}
@Override
+ public final void notifyEnterAnimationComplete(IBinder token) {
+ mHandler.sendMessage(mHandler.obtainMessage(ENTER_ANIMATION_COMPLETE_MSG, token));
+ }
+
+ @Override
public String getCallingPackage(IBinder token) {
synchronized (this) {
ActivityRecord r = getCallingRecordLocked(token);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 874e105..9b69ce2 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -297,6 +297,13 @@
mAppToken.mLaunchTaskBehind = false;
} else {
mAppToken.updateReportedVisibilityLocked();
+ if (mAppToken.mEnteringAnimation) {
+ mAppToken.mEnteringAnimation = false;
+ try {
+ mService.mActivityManager.notifyEnterAnimationComplete(mAppToken.token);
+ } catch (RemoteException e) {
+ }
+ }
}
return false;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 312689b..3fcd067 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -110,6 +110,7 @@
boolean mDeferRemoval;
boolean mLaunchTaskBehind;
+ boolean mEnteringAnimation;
AppWindowToken(WindowManagerService _service, IApplicationToken _token,
boolean _voiceInteraction) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 170ecbd..670ba55 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4450,6 +4450,7 @@
if (visible) {
mOpeningApps.add(wtoken);
wtoken.startingMoved = false;
+ wtoken.mEnteringAnimation = true;
// If the token is currently hidden (should be the
// common case), then we need to set up to wait for
@@ -4472,6 +4473,7 @@
}
} else {
mClosingApps.add(wtoken);
+ wtoken.mEnteringAnimation = false;
// If the token is currently visible (should be the
// common case), then set up to wait for it to be hidden.