1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2010 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage android.animation; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.IAnimationListener; 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderSession; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.Result; 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.Result.Status; 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.Bridge; 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.impl.RenderSessionImpl; 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.Handler; 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.Handler_Delegate; 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.Handler_Delegate.IHandlerCallback; 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.Message; 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.PriorityQueue; 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.Queue; 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Abstract animation thread. 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p/> 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This does not actually start an animation, instead it fakes a looper that will play whatever 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * animation is sending messages to its own {@link Handler}. 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p/> 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Classes should implement {@link #preAnimation()} and {@link #postAnimation()}. 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p/> 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If {@link #preAnimation()} does not start an animation somehow then the thread doesn't do 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * anything. 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic abstract class AnimationThread extends Thread { 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static class MessageBundle implements Comparable<MessageBundle> { 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final Handler mTarget; 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final Message mMessage; 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final long mUptimeMillis; 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski MessageBundle(Handler target, Message message, long uptimeMillis) { 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mTarget = target; 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mMessage = message; 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mUptimeMillis = uptimeMillis; 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public int compareTo(MessageBundle bundle) { 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (mUptimeMillis < bundle.mUptimeMillis) { 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return -1; 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return 1; 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final RenderSessionImpl mSession; 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private Queue<MessageBundle> mQueue = new PriorityQueue<MessageBundle>(); 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final IAnimationListener mListener; 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public AnimationThread(RenderSessionImpl scene, String threadName, 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski IAnimationListener listener) { 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski super(threadName); 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mSession = scene; 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mListener = listener; 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public abstract Result preAnimation(); 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public abstract void postAnimation(); 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public void run() { 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.prepareThread(); 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* FIXME: The ANIMATION_FRAME message no longer exists. Instead, the 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * animation timing loop is completely based on a Choreographer objects 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * that schedules animation and drawing frames. The animation handler is 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * no longer even a handler; it is just a Runnable enqueued on the Choreographer. 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Handler_Delegate.setCallback(new IHandlerCallback() { 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) { 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (msg.what == ValueAnimator.ANIMATION_START || 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski msg.what == ValueAnimator.ANIMATION_FRAME) { 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mQueue.add(new MessageBundle(handler, msg, uptimeMillis)); 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // just ignore. 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski }); 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // call out to the pre-animation work, which should start an animation or more. 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Result result = preAnimation(); 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (result.isSuccess() == false) { 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mListener.done(result); 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // loop the animation 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski RenderSession session = mSession.getSession(); 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski do { 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // check early. 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (mListener.isCanceled()) { 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski break; 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // get the next message. 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski MessageBundle bundle = mQueue.poll(); 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle == null) { 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski break; 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // sleep enough for this bundle to be on time 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski long currentTime = System.currentTimeMillis(); 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (currentTime < bundle.mUptimeMillis) { 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski sleep(bundle.mUptimeMillis - currentTime); 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (InterruptedException e) { 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // FIXME log/do something/sleep again? 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski e.printStackTrace(); 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // check after sleeping. 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (mListener.isCanceled()) { 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski break; 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // ready to do the work, acquire the scene. 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = mSession.acquire(250); 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (result.isSuccess() == false) { 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mListener.done(result); 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return; 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // process the bundle. If the animation is not finished, this will enqueue 148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // the next message, so mQueue will have another one. 149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // check after acquiring in case it took a while. 151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (mListener.isCanceled()) { 152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski break; 153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bundle.mTarget.handleMessage(bundle.mMessage); 156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (mSession.render(false /*freshRender*/).isSuccess()) { 157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mListener.onNewFrame(session); 158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } finally { 160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mSession.release(); 161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } while (mListener.isCanceled() == false && mQueue.size() > 0); 163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mListener.done(Status.SUCCESS.createResult()); 165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (Throwable throwable) { 167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // can't use Bridge.getLog() as the exception might be thrown outside 168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // of an acquire/release block. 169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mListener.done(Status.ERROR_UNKNOWN.createResult("Error playing animation", throwable)); 170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } finally { 172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski postAnimation(); 173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Handler_Delegate.setCallback(null); 174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Bridge.cleanupThread(); 175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 178