12eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet/*
22eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
32eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet *
42eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
52eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * you may not use this file except in compliance with the License.
62eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * You may obtain a copy of the License at
72eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet *
82eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
92eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet *
102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
112eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
122eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * See the License for the specific language governing permissions and
142eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet * limitations under the License.
152eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet */
162eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
177f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetpackage android.animation;
182eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener;
2019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
2119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
2219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
239eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
247f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport com.android.layoutlib.bridge.impl.RenderSessionImpl;
252eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.os.Handler;
272eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.os.Handler_Delegate;
282eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.os.Handler_Delegate.IHandlerCallback;
2946d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.os.Message;
302eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
31479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohetimport java.util.PriorityQueue;
322eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport java.util.Queue;
332eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
34e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet/**
35e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * Abstract animation thread.
36e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * <p/>
37e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * This does not actually start an animation, instead it fakes a looper that will play whatever
38e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * animation is sending messages to its own {@link Handler}.
39e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * <p/>
40e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * Classes should implement {@link #preAnimation()} and {@link #postAnimation()}.
41e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * <p/>
422b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet * If {@link #preAnimation()} does not start an animation somehow then the thread doesn't do
43e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet * anything.
44e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet *
45e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet */
46e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetpublic abstract class AnimationThread extends Thread {
472eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
48479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private static class MessageBundle implements Comparable<MessageBundle> {
492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        final Handler mTarget;
502eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        final Message mMessage;
512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        final long mUptimeMillis;
522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        MessageBundle(Handler target, Message message, long uptimeMillis) {
542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            mTarget = target;
552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            mMessage = message;
562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            mUptimeMillis = uptimeMillis;
572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
58479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
5946d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet        @Override
60479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet        public int compareTo(MessageBundle bundle) {
61479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (mUptimeMillis < bundle.mUptimeMillis) {
62479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                return -1;
63479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            }
64479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            return 1;
65479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet        }
662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
6819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private final RenderSessionImpl mSession;
692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
70479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private Queue<MessageBundle> mQueue = new PriorityQueue<MessageBundle>();
712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    private final IAnimationListener mListener;
722eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
7319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public AnimationThread(RenderSessionImpl scene, String threadName,
7419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            IAnimationListener listener) {
75e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        super(threadName);
7619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mSession = scene;
772eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        mListener = listener;
782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
8019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public abstract Result preAnimation();
81e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    public abstract void postAnimation();
82e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
832eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    @Override
842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    public void run() {
859eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        Bridge.prepareThread();
862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        try {
8796ff709fe25632f6e27fa4c13c7d75dbbcfa38e0Jeff Brown            /* FIXME: The ANIMATION_FRAME message no longer exists.  Instead, the
8896ff709fe25632f6e27fa4c13c7d75dbbcfa38e0Jeff Brown             * animation timing loop is completely based on a Choreographer objects
8996ff709fe25632f6e27fa4c13c7d75dbbcfa38e0Jeff Brown             * that schedules animation and drawing frames.  The animation handler is
9096ff709fe25632f6e27fa4c13c7d75dbbcfa38e0Jeff Brown             * no longer even a handler; it is just a Runnable enqueued on the Choreographer.
912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            Handler_Delegate.setCallback(new IHandlerCallback() {
9246d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                @Override
932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
9496ff709fe25632f6e27fa4c13c7d75dbbcfa38e0Jeff Brown                    if (msg.what == ValueAnimator.ANIMATION_START ||
9596ff709fe25632f6e27fa4c13c7d75dbbcfa38e0Jeff Brown                            msg.what == ValueAnimator.ANIMATION_FRAME) {
962eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                        mQueue.add(new MessageBundle(handler, msg, uptimeMillis));
972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    } else {
982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                        // just ignore.
992eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    }
1002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
1012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            });
10296ff709fe25632f6e27fa4c13c7d75dbbcfa38e0Jeff Brown            */
1032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
104e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // call out to the pre-animation work, which should start an animation or more.
10519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            Result result = preAnimation();
106e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            if (result.isSuccess() == false) {
107e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                mListener.done(result);
108e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }
1092eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            // loop the animation
11119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            RenderSession session = mSession.getSession();
1122eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            do {
113e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                // check early.
114e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                if (mListener.isCanceled()) {
115e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    break;
116e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
117e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
1182eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                // get the next message.
1192eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                MessageBundle bundle = mQueue.poll();
1202eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (bundle == null) {
1212eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    break;
1222eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
1232eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1242eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                // sleep enough for this bundle to be on time
1252eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                long currentTime = System.currentTimeMillis();
1262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (currentTime < bundle.mUptimeMillis) {
1272eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    try {
1282eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                        sleep(bundle.mUptimeMillis - currentTime);
1292eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    } catch (InterruptedException e) {
130c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet                        // FIXME log/do something/sleep again?
1312eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                        e.printStackTrace();
1322eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    }
1332eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
1342eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
135e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                // check after sleeping.
136e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                if (mListener.isCanceled()) {
137e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    break;
138e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
139e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
1402eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                // ready to do the work, acquire the scene.
14119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                result = mSession.acquire(250);
142c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet                if (result.isSuccess() == false) {
1432eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    mListener.done(result);
1442eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    return;
1452eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
1462eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1472eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                // process the bundle. If the animation is not finished, this will enqueue
1482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                // the next message, so mQueue will have another one.
1492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                try {
150e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    // check after acquiring in case it took a while.
151e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    if (mListener.isCanceled()) {
152e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                        break;
153e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    }
154e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
1552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    bundle.mTarget.handleMessage(bundle.mMessage);
1565a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    if (mSession.render(false /*freshRender*/).isSuccess()) {
15719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                        mListener.onNewFrame(session);
1582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    }
1592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                } finally {
16019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    mSession.release();
1612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
162e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            } while (mListener.isCanceled() == false && mQueue.size() > 0);
1632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
16419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            mListener.done(Status.SUCCESS.createResult());
1652b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
1662b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        } catch (Throwable throwable) {
167d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet            // can't use Bridge.getLog() as the exception might be thrown outside
168d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet            // of an acquire/release block.
169d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet            mListener.done(Status.ERROR_UNKNOWN.createResult("Error playing animation", throwable));
1702b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
1712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } finally {
172e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            postAnimation();
1732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            Handler_Delegate.setCallback(null);
1749eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            Bridge.cleanupThread();
1752eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
1762eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
1772eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet}
178