Skip to content

Commit fe5984f

Browse files
chethaaseAndroid (Google) Code Review
authored andcommitted
Merge "Corrects invalidation logic for layered views" into jb-dev
2 parents d07223f + 810a867 commit fe5984f

File tree

4 files changed

+271
-59
lines changed

4 files changed

+271
-59
lines changed

core/java/android/view/ViewGroup.java

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3938,59 +3938,6 @@ public final void invalidateChild(View child, final Rect dirty) {
39383938
// through
39393939
final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
39403940

3941-
//noinspection PointlessBooleanExpression
3942-
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
3943-
if (dirty == null) {
3944-
if (child.mLayerType != LAYER_TYPE_NONE) {
3945-
mPrivateFlags |= INVALIDATED;
3946-
mPrivateFlags &= ~DRAWING_CACHE_VALID;
3947-
child.mLocalDirtyRect.setEmpty();
3948-
}
3949-
do {
3950-
View view = null;
3951-
if (parent instanceof View) {
3952-
view = (View) parent;
3953-
if (view.mLayerType != LAYER_TYPE_NONE) {
3954-
view.mLocalDirtyRect.setEmpty();
3955-
if (view.getParent() instanceof View) {
3956-
final View grandParent = (View) view.getParent();
3957-
grandParent.mPrivateFlags |= INVALIDATED;
3958-
grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3959-
}
3960-
}
3961-
if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
3962-
// already marked dirty - we're done
3963-
break;
3964-
}
3965-
}
3966-
3967-
if (drawAnimation) {
3968-
if (view != null) {
3969-
view.mPrivateFlags |= DRAW_ANIMATION;
3970-
} else if (parent instanceof ViewRootImpl) {
3971-
((ViewRootImpl) parent).mIsAnimating = true;
3972-
}
3973-
}
3974-
3975-
if (parent instanceof ViewRootImpl) {
3976-
((ViewRootImpl) parent).invalidate();
3977-
parent = null;
3978-
} else if (view != null) {
3979-
if ((view.mPrivateFlags & DRAWN) == DRAWN ||
3980-
(view.mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
3981-
view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3982-
view.mPrivateFlags |= DIRTY;
3983-
parent = view.mParent;
3984-
} else {
3985-
parent = null;
3986-
}
3987-
}
3988-
} while (parent != null);
3989-
}
3990-
3991-
return;
3992-
}
3993-
39943941
// Check whether the child that requests the invalidate is fully opaque
39953942
// Views being animated or transformed are not considered opaque because we may
39963943
// be invalidating their old position and need the parent to paint behind them.
@@ -4025,12 +3972,6 @@ public final void invalidateChild(View child, final Rect dirty) {
40253972
View view = null;
40263973
if (parent instanceof View) {
40273974
view = (View) parent;
4028-
if (view.mLayerType != LAYER_TYPE_NONE &&
4029-
view.getParent() instanceof View) {
4030-
final View grandParent = (View) view.getParent();
4031-
grandParent.mPrivateFlags |= INVALIDATED;
4032-
grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
4033-
}
40343975
}
40353976

40363977
if (drawAnimation) {
@@ -4103,6 +4044,7 @@ public ViewParent invalidateChildInParent(final int[] location, final Rect dirty
41034044
location[CHILD_TOP_INDEX] = top;
41044045

41054046
if (mLayerType != LAYER_TYPE_NONE) {
4047+
mPrivateFlags |= INVALIDATED;
41064048
mLocalDirtyRect.union(dirty);
41074049
}
41084050

@@ -4121,6 +4063,7 @@ public ViewParent invalidateChildInParent(final int[] location, final Rect dirty
41214063
}
41224064

41234065
if (mLayerType != LAYER_TYPE_NONE) {
4066+
mPrivateFlags |= INVALIDATED;
41244067
mLocalDirtyRect.union(dirty);
41254068
}
41264069

tests/HwAccelerationTest/AndroidManifest.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,5 +675,14 @@
675675
</intent-filter>
676676
</activity>
677677

678+
<activity
679+
android:name="ViewLayerInvalidationActivity"
680+
android:label="_ViewLayerInvalidation">
681+
<intent-filter>
682+
<action android:name="android.intent.action.MAIN" />
683+
<category android:name="android.intent.category.LAUNCHER" />
684+
</intent-filter>
685+
</activity>
686+
678687
</application>
679688
</manifest>
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
**
4+
** Copyright 2012, The Android Open Source Project
5+
**
6+
** Licensed under the Apache License, Version 2.0 (the "License");
7+
** you may not use this file except in compliance with the License.
8+
** You may obtain a copy of the License at
9+
**
10+
** http://www.apache.org/licenses/LICENSE-2.0
11+
**
12+
** Unless required by applicable law or agreed to in writing, software
13+
** distributed under the License is distributed on an "AS IS" BASIS,
14+
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
** See the License for the specific language governing permissions and
16+
** limitations under the License.
17+
*/
18+
-->
19+
20+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
21+
android:orientation="vertical"
22+
android:layout_width="fill_parent"
23+
android:layout_height="fill_parent">
24+
<LinearLayout android:orientation="horizontal"
25+
android:layout_width="wrap_content"
26+
android:layout_height="wrap_content">
27+
<TextView
28+
android:layout_width="wrap_content"
29+
android:layout_height="wrap_content"
30+
android:text="This is some text"
31+
android:id="@+id/nestedStatus"/>
32+
<TextView
33+
android:layout_width="wrap_content"
34+
android:layout_height="wrap_content"
35+
android:text="This is some text"
36+
android:id="@+id/invalidateStatus"/>
37+
</LinearLayout>
38+
<LinearLayout android:orientation="vertical"
39+
android:layout_width="fill_parent"
40+
android:layout_height="fill_parent"
41+
android:id="@+id/container">
42+
<TextView
43+
android:layout_width="wrap_content"
44+
android:layout_height="wrap_content"
45+
android:text="This is some text"
46+
android:id="@+id/textview"/>
47+
<TextView
48+
android:layout_width="wrap_content"
49+
android:layout_height="wrap_content"
50+
android:text="This is some text"
51+
android:id="@+id/textviewa"/>
52+
<LinearLayout android:orientation="vertical"
53+
android:layout_width="wrap_content"
54+
android:layout_height="wrap_content"
55+
android:id="@+id/container1">
56+
<TextView
57+
android:layout_width="wrap_content"
58+
android:layout_height="wrap_content"
59+
android:text="This is some text"
60+
android:id="@+id/textview1"/>
61+
</LinearLayout>
62+
<LinearLayout android:orientation="vertical"
63+
android:layout_width="wrap_content"
64+
android:layout_height="wrap_content"
65+
android:id="@+id/container2">
66+
<LinearLayout android:orientation="vertical"
67+
android:layout_width="wrap_content"
68+
android:layout_height="wrap_content"
69+
android:id="@+id/container2a">
70+
<TextView
71+
android:layout_width="wrap_content"
72+
android:layout_height="wrap_content"
73+
android:text="This is some text"
74+
android:id="@+id/textview2"/>
75+
</LinearLayout>
76+
</LinearLayout>
77+
<LinearLayout android:orientation="vertical"
78+
android:layout_width="wrap_content"
79+
android:layout_height="wrap_content"
80+
android:id="@+id/container3">
81+
<LinearLayout android:orientation="vertical"
82+
android:layout_width="wrap_content"
83+
android:layout_height="wrap_content"
84+
android:id="@+id/container3a">
85+
<LinearLayout android:orientation="vertical"
86+
android:layout_width="wrap_content"
87+
android:layout_height="wrap_content"
88+
android:id="@+id/container3b">
89+
<TextView
90+
android:layout_width="wrap_content"
91+
android:layout_height="wrap_content"
92+
android:text="This is some text"
93+
android:id="@+id/textview3"/>
94+
</LinearLayout>
95+
</LinearLayout>
96+
</LinearLayout>
97+
</LinearLayout>
98+
</LinearLayout>
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright (C) 2012 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.android.test.hwui;
18+
19+
import android.app.Activity;
20+
import android.graphics.Color;
21+
import android.os.Bundle;
22+
import android.view.View;
23+
import android.view.ViewGroup;
24+
import android.widget.LinearLayout;
25+
import android.widget.TextView;
26+
27+
import java.util.ArrayList;
28+
29+
public class ViewLayerInvalidationActivity extends Activity {
30+
31+
int currentColor = Color.WHITE;
32+
boolean nestedLayersOn = false;
33+
ArrayList<LinearLayout> linearLayouts = new ArrayList<LinearLayout>();
34+
ArrayList<LinearLayout> topLayouts = new ArrayList<LinearLayout>();
35+
ArrayList<TextView> textViews = new ArrayList<TextView>();
36+
LinearLayout container = null;
37+
boolean randomInvalidates = false;
38+
TextView nestedStatusTV, invalidateStatusTV;
39+
static final String NO_NESTING = "Nested Layer: NO ";
40+
static final String NESTING = "Nested Layers: YES ";
41+
static final String NO_INVALIDATING = "Random Invalidating: NO ";
42+
static final String INVALIDATING = "Random Invalidating: YES ";
43+
static final int TEXT_COLOR_INTERVAL = 400;
44+
static final int INVALIDATING_INTERVAL = 1000;
45+
static final int NESTING_INTERVAL = 2000;
46+
47+
@Override
48+
public void onCreate(Bundle savedInstanceState) {
49+
super.onCreate(savedInstanceState);
50+
setContentView(R.layout.view_layer_invalidation);
51+
52+
container = (LinearLayout) findViewById(R.id.container);
53+
final LinearLayout container1 = (LinearLayout) findViewById(R.id.container1);
54+
final LinearLayout container2 = (LinearLayout) findViewById(R.id.container2);
55+
final LinearLayout container3 = (LinearLayout) findViewById(R.id.container3);
56+
nestedStatusTV = (TextView) findViewById(R.id.nestedStatus);
57+
invalidateStatusTV = (TextView) findViewById(R.id.invalidateStatus);
58+
final TextView tva = (TextView) findViewById(R.id.textviewa);
59+
60+
topLayouts.add(container1);
61+
topLayouts.add(container2);
62+
topLayouts.add(container3);
63+
64+
collectLinearLayouts(container);
65+
collectTextViews(container);
66+
67+
nestedStatusTV.setText(NO_NESTING);
68+
invalidateStatusTV.setText(NO_INVALIDATING);
69+
70+
tva.setLayerType(View.LAYER_TYPE_HARDWARE, null);
71+
container1.setLayerType(View.LAYER_TYPE_HARDWARE, null);
72+
container2.setLayerType(View.LAYER_TYPE_HARDWARE, null);
73+
container3.setLayerType(View.LAYER_TYPE_HARDWARE, null);
74+
75+
container.postDelayed(textColorSetter, TEXT_COLOR_INTERVAL);
76+
container.postDelayed(nestedLayerSetter, NESTING_INTERVAL);
77+
container.postDelayed(randomInvalidatesSetter, INVALIDATING_INTERVAL);
78+
}
79+
80+
private Runnable textColorSetter = new Runnable() {
81+
@Override
82+
public void run() {
83+
currentColor = (currentColor == Color.WHITE) ? Color.RED : Color.WHITE;
84+
for (TextView tv : textViews) {
85+
tv.setTextColor(currentColor);
86+
}
87+
if (randomInvalidates) {
88+
randomInvalidator(container);
89+
}
90+
container.postDelayed(textColorSetter, TEXT_COLOR_INTERVAL);
91+
}
92+
};
93+
94+
private Runnable randomInvalidatesSetter = new Runnable() {
95+
@Override
96+
public void run() {
97+
randomInvalidates = !randomInvalidates;
98+
invalidateStatusTV.setText(randomInvalidates ? INVALIDATING : NO_INVALIDATING);
99+
container.postDelayed(randomInvalidatesSetter, INVALIDATING_INTERVAL);
100+
}
101+
};
102+
103+
private Runnable nestedLayerSetter = new Runnable() {
104+
@Override
105+
public void run() {
106+
nestedLayersOn = !nestedLayersOn;
107+
nestedStatusTV.setText(nestedLayersOn ? NESTING : NO_NESTING);
108+
for (LinearLayout layout : linearLayouts) {
109+
layout.setLayerType(nestedLayersOn ?
110+
View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
111+
}
112+
if (!nestedLayersOn) {
113+
for (LinearLayout layout : topLayouts) {
114+
layout.setLayerType(View.LAYER_TYPE_HARDWARE, null);
115+
}
116+
}
117+
container.postDelayed(nestedLayerSetter, NESTING_INTERVAL);
118+
}
119+
};
120+
121+
/**
122+
* Invalidates views based on random chance (50%). This is meant to test
123+
* invalidating several items in the hierarchy at the same time, which can cause artifacts
124+
* if our invalidation-propagation logic is not sound.
125+
*/
126+
private void randomInvalidator(ViewGroup parent) {
127+
for (int i = 0; i < parent.getChildCount(); ++i) {
128+
View child = parent.getChildAt(i);
129+
if (Math.random() < .5) {
130+
child.invalidate();
131+
}
132+
if (child instanceof ViewGroup) {
133+
randomInvalidator((ViewGroup) child);
134+
}
135+
}
136+
}
137+
138+
private void collectLinearLayouts(View view) {
139+
if (!(view instanceof LinearLayout)) {
140+
return;
141+
}
142+
LinearLayout parent = (LinearLayout) view;
143+
linearLayouts.add(parent);
144+
for (int i = 0; i < parent.getChildCount(); ++i) {
145+
collectLinearLayouts(parent.getChildAt(i));
146+
}
147+
}
148+
149+
private void collectTextViews(View view) {
150+
if (view instanceof TextView) {
151+
textViews.add((TextView) view);
152+
return;
153+
}
154+
if (!(view instanceof ViewGroup)) {
155+
return;
156+
}
157+
ViewGroup parent = (ViewGroup) view;
158+
for (int i = 0; i < parent.getChildCount(); ++i) {
159+
collectTextViews(parent.getChildAt(i));
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)