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
onCreate(Bundle savedInstanceState)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      */
randomInvalidator(ViewGroup parent)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 
collectLinearLayouts(View view)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 
collectTextViews(View view)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 }
163