AnimationThread.java revision 5a82d8c58bf91c357c37a82b9f5e5c26f676d847
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 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 59479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet public int compareTo(MessageBundle bundle) { 60479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet if (mUptimeMillis < bundle.mUptimeMillis) { 61479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet return -1; 62479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet } 63479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet return 1; 64479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet } 652eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 6719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet private final RenderSessionImpl mSession; 682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 69479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet private Queue<MessageBundle> mQueue = new PriorityQueue<MessageBundle>(); 702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet private final IAnimationListener mListener; 712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 7219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet public AnimationThread(RenderSessionImpl scene, String threadName, 7319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet IAnimationListener listener) { 74e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet super(threadName); 7519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mSession = scene; 762eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet mListener = listener; 772eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 7919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet public abstract Result preAnimation(); 80e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet public abstract void postAnimation(); 81e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet @Override 832eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet public void run() { 849eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet Bridge.prepareThread(); 852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet try { 862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet Handler_Delegate.setCallback(new IHandlerCallback() { 872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) { 882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet if (msg.what == ValueAnimator.ANIMATION_START || 892eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet msg.what == ValueAnimator.ANIMATION_FRAME) { 902eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet mQueue.add(new MessageBundle(handler, msg, uptimeMillis)); 912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } else { 922eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // just ignore. 932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 942eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 952eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet }); 962eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 97e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // call out to the pre-animation work, which should start an animation or more. 9819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet Result result = preAnimation(); 99e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (result.isSuccess() == false) { 100e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet mListener.done(result); 101e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 1022eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 1032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // loop the animation 10419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet RenderSession session = mSession.getSession(); 1052eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet do { 106e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // check early. 107e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (mListener.isCanceled()) { 108e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet break; 109e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 110e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 1112eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // get the next message. 1122eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet MessageBundle bundle = mQueue.poll(); 1132eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet if (bundle == null) { 1142eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet break; 1152eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1162eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 1172eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // sleep enough for this bundle to be on time 1182eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet long currentTime = System.currentTimeMillis(); 1192eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet if (currentTime < bundle.mUptimeMillis) { 1202eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet try { 1212eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet sleep(bundle.mUptimeMillis - currentTime); 1222eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } catch (InterruptedException e) { 123c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet // FIXME log/do something/sleep again? 1242eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet e.printStackTrace(); 1252eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1272eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 128e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // check after sleeping. 129e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (mListener.isCanceled()) { 130e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet break; 131e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 132e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 1332eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // ready to do the work, acquire the scene. 13419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet result = mSession.acquire(250); 135c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet if (result.isSuccess() == false) { 1362eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet mListener.done(result); 1372eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet return; 1382eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1392eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 1402eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // process the bundle. If the animation is not finished, this will enqueue 1412eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet // the next message, so mQueue will have another one. 1422eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet try { 143e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet // check after acquiring in case it took a while. 144e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet if (mListener.isCanceled()) { 145e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet break; 146e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } 147e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet 1482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet bundle.mTarget.handleMessage(bundle.mMessage); 1495a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet if (mSession.render(false /*freshRender*/).isSuccess()) { 15019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mListener.onNewFrame(session); 1512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } finally { 15319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mSession.release(); 1542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 155e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet } while (mListener.isCanceled() == false && mQueue.size() > 0); 1562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet 15719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet mListener.done(Status.SUCCESS.createResult()); 1582b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet 1592b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet } catch (Throwable throwable) { 160d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet // can't use Bridge.getLog() as the exception might be thrown outside 161d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet // of an acquire/release block. 162d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet mListener.done(Status.ERROR_UNKNOWN.createResult("Error playing animation", throwable)); 1632b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet 1642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } finally { 165e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet postAnimation(); 1662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet Handler_Delegate.setCallback(null); 1679eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet Bridge.cleanupThread(); 1682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet } 1702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet} 171