AnimationThread.java revision d7cc1244d7f0901688545c8535fa531fbb68669a
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 172eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetpackage com.android.layoutlib.bridge.impl; 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; 242eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 252eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.animation.ValueAnimator; 262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.os.Handler; 272eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.os.Handler_Delegate; 282eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.os.Message; 292eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.os.Handler_Delegate.IHandlerCallback; 302eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 312eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport java.util.LinkedList; 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 482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet private static class 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 } 582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 6019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet private final RenderSessionImpl mSession; 612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 622b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet private Queue<MessageBundle> mQueue = new LinkedList<MessageBundle>(); 632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet private final IAnimationListener mListener; 642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 6519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet public AnimationThread(RenderSessionImpl scene, String threadName, 6619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet IAnimationListener listener) { 67e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet super(threadName); 6819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mSession = scene; 692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet mListener = listener; 702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 7219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet public abstract Result preAnimation(); 73e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet public abstract void postAnimation(); 74e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 752eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet @Override 762eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet public void run() { 779eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet Bridge.prepareThread(); 782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet try { 792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet Handler_Delegate.setCallback(new IHandlerCallback() { 802eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) { 812eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet if (msg.what == ValueAnimator.ANIMATION_START || 822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet msg.what == ValueAnimator.ANIMATION_FRAME) { 832eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet mQueue.add(new MessageBundle(handler, msg, uptimeMillis)); 842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } else { 852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // just ignore. 862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet }); 892eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 90e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // call out to the pre-animation work, which should start an animation or more. 9119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet Result result = preAnimation(); 92e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (result.isSuccess() == false) { 93e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet mListener.done(result); 94e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 952eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 962eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // loop the animation 9719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet RenderSession session = mSession.getSession(); 982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet do { 99e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // check early. 100e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (mListener.isCanceled()) { 101e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet break; 102e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 103e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 1042eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // get the next message. 1052eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet MessageBundle bundle = mQueue.poll(); 1062eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet if (bundle == null) { 1072eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet break; 1082eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1092eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 1102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // sleep enough for this bundle to be on time 1112eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet long currentTime = System.currentTimeMillis(); 1122eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet if (currentTime < bundle.mUptimeMillis) { 1132eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet try { 1142eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet sleep(bundle.mUptimeMillis - currentTime); 1152eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } catch (InterruptedException e) { 116c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet // FIXME log/do something/sleep again? 1172eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet e.printStackTrace(); 1182eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1192eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1202eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 121e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // check after sleeping. 122e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (mListener.isCanceled()) { 123e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet break; 124e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 125e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 1262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // ready to do the work, acquire the scene. 12719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet result = mSession.acquire(250); 128c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet if (result.isSuccess() == false) { 1292eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet mListener.done(result); 1302eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet return; 1312eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1322eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 1332eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // process the bundle. If the animation is not finished, this will enqueue 1342eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // the next message, so mQueue will have another one. 1352eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet try { 136e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // check after acquiring in case it took a while. 137e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (mListener.isCanceled()) { 138e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet break; 139e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 140e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 1412eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet bundle.mTarget.handleMessage(bundle.mMessage); 14219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet if (mSession.render().isSuccess()) { 14319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mListener.onNewFrame(session); 1442eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1452eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } finally { 14619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mSession.release(); 1472eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 148e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } while (mListener.isCanceled() == false && mQueue.size() > 0); 1492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 15019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mListener.done(Status.SUCCESS.createResult()); 1512b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet 1522b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet } catch (Throwable throwable) { 153d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet // can't use Bridge.getLog() as the exception might be thrown outside 154d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet // of an acquire/release block. 155d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet mSession.getLog().error(null, "Error playing animation", throwable); 156d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet mListener.done(Status.ERROR_UNKNOWN.createResult("Error playing animation", throwable)); 1572b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet 1582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } finally { 159e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet postAnimation(); 1602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet Handler_Delegate.setCallback(null); 1619eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet Bridge.cleanupThread(); 1622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet} 165