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