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