1ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne/*
2ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * Copyright (C) 2014 The Android Open Source Project
3ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne *
4ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * Licensed under the Apache License, Version 2.0 (the "License");
5ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * you may not use this file except in compliance with the License.
6ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * You may obtain a copy of the License at
7ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne *
8ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne *      http://www.apache.org/licenses/LICENSE-2.0
9ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne *
10ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * Unless required by applicable law or agreed to in writing, software
11ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * distributed under the License is distributed on an "AS IS" BASIS,
12ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * See the License for the specific language governing permissions and
14ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne * limitations under the License.
15ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne */
16ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
17ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhnepackage com.android.test.hwui;
18ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
19ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.app.Activity;
20ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.graphics.Canvas;
21ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.graphics.ColorFilter;
22ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.graphics.Paint;
23ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.graphics.PixelFormat;
24ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.graphics.Rect;
25ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.graphics.drawable.Drawable;
26ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.os.Bundle;
27ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.view.DisplayListCanvas;
2851aaf906f9f5fb2f117f5ccfae8be6974f7cb903John Reckimport android.view.ThreadedRenderer;
29ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.view.RenderNode;
30ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.view.ThreadedRenderer;
31ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.view.View;
32ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.view.View.OnClickListener;
33ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.widget.AbsoluteLayout;
34ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhneimport android.widget.AbsoluteLayout.LayoutParams;
35ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
36ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhnepublic class MultiProducerActivity extends Activity implements OnClickListener {
37ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private static final int DURATION = 800;
38ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private View mBackgroundTarget = null;
39ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private View mFrameTarget = null;
40ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private View mContent = null;
41ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    // The width & height of our "output drawing".
42ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private final int WIDTH = 900;
43ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private final int HEIGHT = 600;
44ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    // A border width around the drawing.
45ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private static final int BORDER_WIDTH = 20;
46ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    // The Gap between the content and the frame which should get filled on the right and bottom
47ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    // side by the backdrop.
48ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    final int CONTENT_GAP = 100;
49ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
50ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    // For debug purposes - disable drawing of frame / background.
51ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private final boolean USE_FRAME = true;
52ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private final boolean USE_BACK = true;
53ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
54ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    @Override
55ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    protected void onCreate(Bundle savedInstanceState) {
56ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        super.onCreate(savedInstanceState);
57ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        // To make things simple - we do a quick and dirty absolute layout.
58ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        final AbsoluteLayout layout = new AbsoluteLayout(this);
59ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
60ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        // Create the outer frame
61ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        if (USE_FRAME) {
62ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mFrameTarget = new View(this);
63ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            LayoutParams frameLP = new LayoutParams(WIDTH, HEIGHT, 0, 0);
64ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            layout.addView(mFrameTarget, frameLP);
65ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
66ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
67ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        // Create the background which fills the gap between content and frame.
68ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        if (USE_BACK) {
69ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mBackgroundTarget = new View(this);
70ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            LayoutParams backgroundLP = new LayoutParams(
71ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    WIDTH - 2 * BORDER_WIDTH, HEIGHT - 2 * BORDER_WIDTH,
72ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    BORDER_WIDTH, BORDER_WIDTH);
73ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            layout.addView(mBackgroundTarget, backgroundLP);
74ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
75ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
76ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        // Create the content
77ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        // Note: We reduce the size by CONTENT_GAP pixels on right and bottom, so that they get
78ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        // drawn by the backdrop.
79ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        mContent = new View(this);
80ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        mContent.setBackground(new ColorPulse(0xFFF44336, 0xFF9C27B0, null));
81ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        mContent.setOnClickListener(this);
82ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        LayoutParams contentLP = new LayoutParams(WIDTH - 2 * BORDER_WIDTH - CONTENT_GAP,
83ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                HEIGHT - 2 * BORDER_WIDTH - CONTENT_GAP, BORDER_WIDTH, BORDER_WIDTH);
84ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        layout.addView(mContent, contentLP);
85ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
86ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        setContentView(layout);
87ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    }
88ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
89ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    @Override
90ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    protected void onStart() {
91ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        super.onStart();
92ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget;
93ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        if (view != null) {
94ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            view.post(mSetup);
95ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
96ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    }
97ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
98ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    @Override
99ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    protected void onStop() {
100ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        super.onStop();
101ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget;
102ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        if (view != null) {
103ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            view.removeCallbacks(mSetup);
104ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
105ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        if (mBgRenderer != null) {
106ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mBgRenderer.destroy();
107ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mBgRenderer = null;
108ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
109ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    }
110ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
111ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    @Override
112ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    public void onClick(View view) {
113ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        sBlockThread.run();
114ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    }
115ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
116ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private Runnable mSetup = new Runnable() {
117ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        @Override
118ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public void run() {
119ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget;
120ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (view == null) {
121ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                view.postDelayed(mSetup, 50);
122ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
12351aaf906f9f5fb2f117f5ccfae8be6974f7cb903John Reck            ThreadedRenderer renderer = view.getHardwareRenderer();
124ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (renderer == null || view.getWidth() == 0) {
125ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                view.postDelayed(mSetup, 50);
126ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
127ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            ThreadedRenderer threaded = (ThreadedRenderer) renderer;
128ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
129ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mBgRenderer = new FakeFrame(threaded,mFrameTarget, mBackgroundTarget);
130ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mBgRenderer.start();
131ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
132ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    };
133ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
134ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private FakeFrame mBgRenderer;
135ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private class FakeFrame extends Thread {
136ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        ThreadedRenderer mRenderer;
137ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        volatile boolean mRunning = true;
138ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        View mTargetFrame;
139ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        View mTargetBack;
140ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        Drawable mFrameContent;
141ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        Drawable mBackContent;
142ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        // The Z value where to place this.
143ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        int mZFrame;
144ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        int mZBack;
145ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        String mRenderNodeName;
146ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
147ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        FakeFrame(ThreadedRenderer renderer, View targetFrame, View targetBack) {
148ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mRenderer = renderer;
149ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mTargetFrame = targetFrame;
150ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
151ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mTargetBack = targetBack;
152ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mFrameContent = new ColorPulse(0xFF101010, 0xFF707070, new Rect(0, 0, WIDTH, HEIGHT));
153ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mBackContent = new ColorPulse(0xFF909090, 0xFFe0e0e0, null);
154ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
155ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
156ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        @Override
157ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public void run() {
158ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            Rect currentFrameBounds = new Rect();
159ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            Rect currentBackBounds = new Rect();
160ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            Rect newBounds = new Rect();
161ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int[] surfaceOrigin = new int[2];
162ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            RenderNode nodeFrame = null;
163ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            RenderNode nodeBack = null;
164ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
165ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            // Since we are overriding the window painting logic we need to at least fill the
166ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            // surface with some window content (otherwise the world will go black).
167ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            try {
168ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                Thread.sleep(200);
169ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            } catch (InterruptedException e) {
170ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
171ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
172ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (mTargetBack != null) {
173ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                nodeBack = RenderNode.create("FakeBackdrop", null);
174ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                nodeBack.setClipToBounds(true);
175ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mRenderer.addRenderNode(nodeBack, true);
176ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
177ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
178ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (mTargetFrame != null) {
179ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                nodeFrame = RenderNode.create("FakeFrame", null);
180ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                nodeFrame.setClipToBounds(true);
181ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mRenderer.addRenderNode(nodeFrame, false);
182ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
183ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
184ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            while (mRunning) {
185ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                // Get the surface position to draw to within our surface.
186ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                surfaceOrigin[0] = 0;
187ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                surfaceOrigin[1] = 0;
188ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                // This call should be done while the rendernode's displaylist is produced.
189ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                // For simplicity of this test we do this before we kick off the draw.
190ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mContent.getLocationInSurface(surfaceOrigin);
191b816087962aba0019b022303330f03b897b580edSkuhne                mRenderer.setContentDrawBounds(surfaceOrigin[0], surfaceOrigin[1],
192ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                        surfaceOrigin[0] + mContent.getWidth(),
193ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                        surfaceOrigin[1] + mContent.getHeight());
194ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                // Determine new position for frame.
195ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                if (nodeFrame != null) {
196ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    surfaceOrigin[0] = 0;
197ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    surfaceOrigin[1] = 0;
198ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    mTargetFrame.getLocationInSurface(surfaceOrigin);
199ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    newBounds.set(surfaceOrigin[0], surfaceOrigin[1],
200ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                            surfaceOrigin[0] + mTargetFrame.getWidth(),
201ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                            surfaceOrigin[1] + mTargetFrame.getHeight());
202ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    if (!currentFrameBounds.equals(newBounds)) {
203ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                        currentFrameBounds.set(newBounds);
204ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                        nodeFrame.setLeftTopRightBottom(currentFrameBounds.left,
205ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                                currentFrameBounds.top,
206ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                                currentFrameBounds.right, currentFrameBounds.bottom);
207ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    }
208ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
209ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    // Draw frame
210ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    DisplayListCanvas canvas = nodeFrame.start(currentFrameBounds.width(),
211ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                            currentFrameBounds.height());
212ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    mFrameContent.draw(canvas);
213ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    nodeFrame.end(canvas);
214ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                }
215ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
216ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                // Determine new position for backdrop
217ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                if (nodeBack != null) {
218ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    surfaceOrigin[0] = 0;
219ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    surfaceOrigin[1] = 0;
220ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    mTargetBack.getLocationInSurface(surfaceOrigin);
221ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    newBounds.set(surfaceOrigin[0], surfaceOrigin[1],
222ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                            surfaceOrigin[0] + mTargetBack.getWidth(),
223ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                            surfaceOrigin[1] + mTargetBack.getHeight());
224ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    if (!currentBackBounds.equals(newBounds)) {
225ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                        currentBackBounds.set(newBounds);
226ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                        nodeBack.setLeftTopRightBottom(currentBackBounds.left,
227ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                                currentBackBounds.top,
228ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                                currentBackBounds.right, currentBackBounds.bottom);
229ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    }
230ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
231ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    // Draw Backdrop
232ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    DisplayListCanvas canvas = nodeBack.start(currentBackBounds.width(),
233ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                            currentBackBounds.height());
234ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    mBackContent.draw(canvas);
235ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    nodeBack.end(canvas);
236ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                }
237ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
238ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                // we need to only render one guy - the rest will happen automatically (I think).
239ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                if (nodeFrame != null) {
240ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    mRenderer.drawRenderNode(nodeFrame);
241ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                }
242ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                if (nodeBack != null) {
243ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    mRenderer.drawRenderNode(nodeBack);
244ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                }
245ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                try {
246ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    Thread.sleep(5);
247ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                } catch (InterruptedException e) {}
248ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
249ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (nodeFrame != null) {
250ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mRenderer.removeRenderNode(nodeFrame);
251ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
252ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (nodeBack != null) {
253ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mRenderer.removeRenderNode(nodeBack);
254ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
255ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
256ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
257ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public void destroy() {
258ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mRunning = false;
259ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            try {
260ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                join();
261ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            } catch (InterruptedException e) {}
262ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
263ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    }
264ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
265ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    private final static Runnable sBlockThread = new Runnable() {
266ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        @Override
267ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public void run() {
268ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            try {
269ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                Thread.sleep(DURATION);
270ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            } catch (InterruptedException e) {
271ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
272ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
273ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    };
274ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
275ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    static class ColorPulse extends Drawable {
276ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
277ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        private int mColorStart;
278ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        private int mColorEnd;
279ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        private int mStep;
280ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        private Rect mRect;
281ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        private Paint mPaint = new Paint();
282ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
283ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public ColorPulse(int color1, int color2, Rect rect) {
284ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mColorStart = color1;
285ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mColorEnd = color2;
286ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (rect != null) {
287ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mRect = new Rect(rect.left + BORDER_WIDTH / 2, rect.top + BORDER_WIDTH / 2,
288ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                                 rect.right - BORDER_WIDTH / 2, rect.bottom - BORDER_WIDTH / 2);
289ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
290ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
291ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
292ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        static int evaluate(float fraction, int startInt, int endInt) {
293ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int startA = (startInt >> 24) & 0xff;
294ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int startR = (startInt >> 16) & 0xff;
295ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int startG = (startInt >> 8) & 0xff;
296ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int startB = startInt & 0xff;
297ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
298ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int endA = (endInt >> 24) & 0xff;
299ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int endR = (endInt >> 16) & 0xff;
300ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int endG = (endInt >> 8) & 0xff;
301ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int endB = endInt & 0xff;
302ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
303ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
304ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    (int)((startR + (int)(fraction * (endR - startR))) << 16) |
305ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    (int)((startG + (int)(fraction * (endG - startG))) << 8) |
306ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                    (int)((startB + (int)(fraction * (endB - startB))));
307ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
308ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
309ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        @Override
310ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public void draw(Canvas canvas) {
311ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            float frac = mStep / 50.0f;
312ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            int color = evaluate(frac, mColorStart, mColorEnd);
313ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (mRect != null && !mRect.isEmpty()) {
314ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mPaint.setStyle(Paint.Style.STROKE);
315ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mPaint.setStrokeWidth(BORDER_WIDTH);
316ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mPaint.setColor(color);
317ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                canvas.drawRect(mRect, mPaint);
318ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            } else {
319ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                canvas.drawColor(color);
320ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
321ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
322ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            mStep++;
323ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            if (mStep >= 50) {
324ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mStep = 0;
325ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                int tmp = mColorStart;
326ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mColorStart = mColorEnd;
327ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne                mColorEnd = tmp;
328ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            }
329ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            invalidateSelf();
330ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
331ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
332ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        @Override
333ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public void setAlpha(int alpha) {
334ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
335ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
336ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        @Override
337ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public void setColorFilter(ColorFilter colorFilter) {
338ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
339ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
340ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        @Override
341ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        public int getOpacity() {
342ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne            return mRect == null || mRect.isEmpty() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
343ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne        }
344ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
345ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne    }
346ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne}
347ea7a7fb75acb7305eb774ca7bc7e96103bd49323Skuhne
348