Skip to content

Commit 12d3a94

Browse files
author
Dianne Hackborn
committed
When a window is first shown only draw once while animating.
On some hardware allocating a new graphics buffer is quite expensive, which blocks updates to the UI. This can cause glitches when performing window animations. To reduce these glitches, the view hierarchy will now only allow itself to be drawn once if its window is being shown while the window manager is animating, not resuming draws until it is told that the animation is done. Change-Id: Ie15192f6fddbd0931b022a72c76ddd55ca266d84
1 parent 11dea29 commit 12d3a94

File tree

6 files changed

+90
-10
lines changed

6 files changed

+90
-10
lines changed

core/java/android/view/IWindow.aidl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,18 @@ oneway interface IWindow {
7070
/**
7171
* Drag/drop events
7272
*/
73-
void dispatchDragEvent(in DragEvent event);
73+
void dispatchDragEvent(in DragEvent event);
7474

7575
/**
7676
* System chrome visibility changes
7777
*/
78-
void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
78+
void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7979
int localValue, int localChanges);
80+
81+
/**
82+
* If the window manager returned RELAYOUT_RES_ANIMATING
83+
* from relayout(), this method will be called when the animation
84+
* is done.
85+
*/
86+
void doneAnimating();
8087
}

core/java/android/view/ViewRootImpl.java

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ public final class ViewRootImpl implements ViewParent,
229229
boolean mNewSurfaceNeeded;
230230
boolean mHasHadWindowFocus;
231231
boolean mLastWasImTarget;
232+
boolean mWindowsAnimating;
232233
int mLastSystemUiVisibility;
233234

234235
// Pool of queued input events.
@@ -1768,6 +1769,8 @@ private void performTraversals() {
17681769
}
17691770
}
17701771

1772+
boolean skipDraw = false;
1773+
17711774
if (mFirst) {
17721775
// handle first focus request
17731776
if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
@@ -1784,6 +1787,14 @@ private void performTraversals() {
17841787
+ mRealFocusedView);
17851788
}
17861789
}
1790+
if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_ANIMATING) != 0) {
1791+
// The first time we relayout the window, if the system is
1792+
// doing window animations, we want to hold of on any future
1793+
// draws until the animation is done.
1794+
mWindowsAnimating = true;
1795+
}
1796+
} else if (mWindowsAnimating) {
1797+
skipDraw = true;
17871798
}
17881799

17891800
mFirst = false;
@@ -1815,14 +1826,16 @@ private void performTraversals() {
18151826
viewVisibility != View.VISIBLE;
18161827

18171828
if (!cancelDraw && !newSurface) {
1818-
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1819-
for (int i = 0; i < mPendingTransitions.size(); ++i) {
1820-
mPendingTransitions.get(i).startChangingAnimations();
1829+
if (!skipDraw || mReportNextDraw) {
1830+
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1831+
for (int i = 0; i < mPendingTransitions.size(); ++i) {
1832+
mPendingTransitions.get(i).startChangingAnimations();
1833+
}
1834+
mPendingTransitions.clear();
18211835
}
1822-
mPendingTransitions.clear();
1836+
1837+
performDraw();
18231838
}
1824-
1825-
performDraw();
18261839
} else {
18271840
// End any pending transitions on this non-visible window
18281841
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
@@ -2680,6 +2693,7 @@ private static void forceLayout(View view) {
26802693
private final static int MSG_DISPATCH_SCREEN_STATE = 20;
26812694
private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
26822695
private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22;
2696+
private final static int MSG_DISPATCH_DONE_ANIMATING = 23;
26832697

26842698
final class ViewRootHandler extends Handler {
26852699
@Override
@@ -2729,6 +2743,8 @@ public String getMessageName(Message message) {
27292743
return "MSG_INVALIDATE_DISPLAY_LIST";
27302744
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
27312745
return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
2746+
case MSG_DISPATCH_DONE_ANIMATING:
2747+
return "MSG_DISPATCH_DONE_ANIMATING";
27322748
}
27332749
return super.getMessageName(message);
27342750
}
@@ -2941,6 +2957,9 @@ public void handleMessage(Message msg) {
29412957
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
29422958
setAccessibilityFocusedHost(null);
29432959
} break;
2960+
case MSG_DISPATCH_DONE_ANIMATING: {
2961+
handleDispatchDoneAnimating();
2962+
} break;
29442963
}
29452964
}
29462965
}
@@ -3756,6 +3775,15 @@ public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args)
37563775
mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
37573776
}
37583777

3778+
public void handleDispatchDoneAnimating() {
3779+
if (mWindowsAnimating) {
3780+
mWindowsAnimating = false;
3781+
if (!mDirty.isEmpty() || mIsAnimating) {
3782+
scheduleTraversals();
3783+
}
3784+
}
3785+
}
3786+
37593787
public void getLastTouchPoint(Point outLocation) {
37603788
outLocation.x = (int) mLastTouchPoint.x;
37613789
outLocation.y = (int) mLastTouchPoint.y;
@@ -4476,6 +4504,10 @@ public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
44764504
mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
44774505
}
44784506

4507+
public void dispatchDoneAnimating() {
4508+
mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
4509+
}
4510+
44794511
public void dispatchCheckFocus() {
44804512
if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
44814513
// This will result in a call to checkFocus() below.
@@ -4783,6 +4815,13 @@ public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
47834815
localValue, localChanges);
47844816
}
47854817
}
4818+
4819+
public void doneAnimating() {
4820+
final ViewRootImpl viewAncestor = mViewAncestor.get();
4821+
if (viewAncestor != null) {
4822+
viewAncestor.dispatchDoneAnimating();
4823+
}
4824+
}
47864825
}
47874826

47884827
/**

core/java/android/view/WindowManagerImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ public class WindowManagerImpl implements WindowManager {
7373
* The window manager has changed the surface from the last call.
7474
*/
7575
public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
76+
/**
77+
* The window manager is currently animating. It will call
78+
* IWindow.doneAnimating() when done.
79+
*/
80+
public static final int RELAYOUT_RES_ANIMATING = 0x8;
7681

7782
/**
7883
* Flag for relayout: the client will be later giving

core/java/com/android/internal/view/BaseIWindow.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,7 @@ public void dispatchWallpaperCommand(String action, int x, int y,
8787
}
8888
}
8989
}
90+
91+
public void doneAnimating() {
92+
}
9093
}

services/java/com/android/server/wm/WindowManagerService.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,12 @@ public void onReceive(Context context, Intent intent) {
423423
ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn
424424
= new ArrayList<Pair<WindowState, IRemoteCallback>>();
425425

426+
/**
427+
* Windows that have called relayout() while we were running animations,
428+
* so we need to tell when the animation is done.
429+
*/
430+
final ArrayList<WindowState> mRelayoutWhileAnimating = new ArrayList<WindowState>();
431+
426432
/**
427433
* Used when rebuilding window list to keep track of windows that have
428434
* been removed.
@@ -2647,6 +2653,7 @@ public int relayoutWindow(Session session, IWindow client, int seq,
26472653
boolean inTouchMode;
26482654
boolean configChanged;
26492655
boolean surfaceChanged = false;
2656+
boolean animating;
26502657

26512658
// if they don't have this permission, mask out the status bar bits
26522659
int systemUiVisibility = 0;
@@ -2946,7 +2953,11 @@ public int relayoutWindow(Session session, IWindow client, int seq,
29462953
TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
29472954

29482955
inTouchMode = mInTouchMode;
2949-
2956+
animating = mAnimator.mAnimating;
2957+
if (animating && !mRelayoutWhileAnimating.contains(win)) {
2958+
mRelayoutWhileAnimating.add(win);
2959+
}
2960+
29502961
mInputMonitor.updateInputWindowsLw(true /*force*/);
29512962
}
29522963

@@ -2958,7 +2969,8 @@ public int relayoutWindow(Session session, IWindow client, int seq,
29582969

29592970
return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0)
29602971
| (displayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
2961-
| (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0);
2972+
| (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0)
2973+
| (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0);
29622974
}
29632975

29642976
public void performDeferredDestroyWindow(Session session, IWindow client) {
@@ -8579,6 +8591,16 @@ private final void performLayoutAndPlaceSurfacesLockedInner(
85798591
mToBottomApps.clear();
85808592
}
85818593

8594+
if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
8595+
for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
8596+
try {
8597+
mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
8598+
} catch (RemoteException e) {
8599+
}
8600+
}
8601+
mRelayoutWhileAnimating.clear();
8602+
}
8603+
85828604
if (wallpaperDestroyed) {
85838605
mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
85848606
}

tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
9090
// pass for now.
9191
}
9292

93+
@Override
94+
public void doneAnimating() {
95+
}
96+
9397
@Override
9498
public IBinder asBinder() {
9599
// pass for now.

0 commit comments

Comments
 (0)