1 /*
2  * Copyright (C) 2014 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 package android.uirendering.cts.testinfrastructure;
17 
18 import android.annotation.Nullable;
19 import android.app.Activity;
20 import android.content.res.Configuration;
21 import android.graphics.Point;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.view.View;
26 import android.view.ViewStub;
27 import android.view.ViewTreeObserver;
28 import android.webkit.WebView;
29 
30 import android.uirendering.cts.R;
31 
32 /**
33  * A generic activity that uses a view specified by the user.
34  */
35 public class DrawActivity extends Activity {
36     private final static long TIME_OUT_MS = 10000;
37     private final Point mLock = new Point();
38     public static final int MIN_NUMBER_OF_DRAWS = 20;
39 
40     private Handler mHandler;
41     private View mView;
42     private View mViewWrapper;
43     private boolean mOnTv;
44 
onCreate(Bundle bundle)45     public void onCreate(Bundle bundle){
46         super.onCreate(bundle);
47         getWindow().getDecorView().setSystemUiVisibility(
48                 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
49         mHandler = new RenderSpecHandler();
50         int uiMode = getResources().getConfiguration().uiMode;
51         mOnTv = (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
52     }
53 
getOnTv()54     public boolean getOnTv() {
55         return mOnTv;
56     }
57 
enqueueRenderSpecAndWait(int layoutId, CanvasClient canvasClient, String webViewUrl, @Nullable ViewInitializer viewInitializer, boolean useHardware)58     public Point enqueueRenderSpecAndWait(int layoutId, CanvasClient canvasClient, String webViewUrl,
59             @Nullable ViewInitializer viewInitializer, boolean useHardware) {
60         ((RenderSpecHandler) mHandler).setViewInitializer(viewInitializer);
61         int arg2 = (useHardware ? View.LAYER_TYPE_NONE : View.LAYER_TYPE_SOFTWARE);
62         if (canvasClient != null) {
63             mHandler.obtainMessage(RenderSpecHandler.CANVAS_MSG, 0, arg2, canvasClient).sendToTarget();
64         } else if (webViewUrl != null) {
65             mHandler.obtainMessage(RenderSpecHandler.WEB_VIEW_MSG, 0, arg2, webViewUrl).sendToTarget();
66         } else {
67             mHandler.obtainMessage(RenderSpecHandler.LAYOUT_MSG, layoutId, arg2).sendToTarget();
68         }
69 
70         Point point = new Point();
71         synchronized (mLock) {
72             try {
73                 mLock.wait(TIME_OUT_MS);
74                 point.set(mLock.x, mLock.y);
75             } catch (InterruptedException e) {
76                 e.printStackTrace();
77             }
78         }
79         return point;
80     }
81 
82     private ViewInitializer mViewInitializer;
83 
84     private class RenderSpecHandler extends Handler {
85         public static final int LAYOUT_MSG = 1;
86         public static final int CANVAS_MSG = 2;
87         public static final int WEB_VIEW_MSG = 3;
88 
89 
setViewInitializer(ViewInitializer viewInitializer)90         public void setViewInitializer(ViewInitializer viewInitializer) {
91             mViewInitializer = viewInitializer;
92         }
93 
handleMessage(Message message)94         public void handleMessage(Message message) {
95             int drawCountDelay = 0;
96             setContentView(R.layout.test_container);
97             ViewStub stub = (ViewStub) findViewById(R.id.test_content_stub);
98             mViewWrapper = findViewById(R.id.test_content_wrapper);
99             switch (message.what) {
100                 case LAYOUT_MSG: {
101                     stub.setLayoutResource(message.arg1);
102                     mView = stub.inflate();
103                 } break;
104 
105                 case CANVAS_MSG: {
106                     stub.setLayoutResource(R.layout.test_content_canvasclientview);
107                     mView = stub.inflate();
108                     ((CanvasClientView) mView).setCanvasClient((CanvasClient) (message.obj));
109                 } break;
110 
111                 case WEB_VIEW_MSG: {
112                     stub.setLayoutResource(R.layout.test_content_webview);
113                     mView = stub.inflate();
114                     ((WebView) mView).loadUrl((String) message.obj);
115                     ((WebView) mView).setInitialScale(100);
116                     drawCountDelay = 10;
117                 } break;
118             }
119 
120             if (mView == null) {
121                 throw new IllegalStateException("failed to inflate test content");
122             }
123 
124             if (mViewInitializer != null) {
125                 mViewInitializer.initializeView(mView);
126             }
127 
128             // set layer on wrapper parent of view, so view initializer
129             // can control layer type of View under test.
130             mViewWrapper.setLayerType(message.arg2, null);
131 
132             DrawCounterListener onDrawListener = new DrawCounterListener(drawCountDelay);
133 
134             mView.getViewTreeObserver().addOnPreDrawListener(onDrawListener);
135 
136             mView.postInvalidate();
137         }
138     }
139 
140     @Override
onPause()141     protected void onPause() {
142         super.onPause();
143         if (mViewInitializer != null) {
144             mViewInitializer.teardownView();
145         }
146     }
147 
148     private class DrawCounterListener implements ViewTreeObserver.OnPreDrawListener {
149         private int mCurrentDraws = 0;
150         private int mExtraDraws;
151 
DrawCounterListener(int extraDraws)152         public DrawCounterListener(int extraDraws) {
153             mExtraDraws = extraDraws;
154         }
155 
156         @Override
onPreDraw()157         public boolean onPreDraw() {
158             mCurrentDraws++;
159             if (mCurrentDraws < MIN_NUMBER_OF_DRAWS + mExtraDraws) {
160                 mView.postInvalidate();
161             } else {
162                 synchronized (mLock) {
163                     mLock.set(mViewWrapper.getLeft(), mViewWrapper.getTop());
164                     mLock.notify();
165                 }
166                 mView.getViewTreeObserver().removeOnPreDrawListener(this);
167             }
168             return true;
169         }
170     }
171 }
172