Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -335,7 +335,7 @@ public final class Bridge extends LayoutBridge { t2 = t.getCause(); t2 = t.getCause(); } } return new BridgeLayoutScene(null, return new BridgeLayoutScene(null, new SceneResult(SceneStatus.ERROR_UNKNOWN, t2.getMessage(), t2)); SceneStatus.ERROR_UNKNOWN.getResult(t2.getMessage(), t2)); } } } } Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java +41 −10 Original line number Original line Diff line number Diff line Loading @@ -22,7 +22,6 @@ import com.android.layoutlib.api.LayoutScene.IAnimationListener; import com.android.layoutlib.api.SceneResult.SceneStatus; import com.android.layoutlib.api.SceneResult.SceneStatus; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.Bridge; import android.animation.Animator; import android.animation.ValueAnimator; import android.animation.ValueAnimator; import android.os.Handler; import android.os.Handler; import android.os.Handler_Delegate; import android.os.Handler_Delegate; Loading @@ -32,7 +31,19 @@ import android.os.Handler_Delegate.IHandlerCallback; import java.util.LinkedList; import java.util.LinkedList; import java.util.Queue; import java.util.Queue; public class AnimationThread extends Thread { /** * Abstract animation thread. * <p/> * This does not actually start an animation, instead it fakes a looper that will play whatever * animation is sending messages to its own {@link Handler}. * <p/> * Classes should implement {@link #preAnimation()} and {@link #postAnimation()}. * <p/> * If {@link #preAnimation()} does not start an animation something then the thread doesn't do * anything. * */ public abstract class AnimationThread extends Thread { private static class MessageBundle { private static class MessageBundle { final Handler mTarget; final Handler mTarget; Loading @@ -47,17 +58,19 @@ public class AnimationThread extends Thread { } } private final LayoutSceneImpl mScene; private final LayoutSceneImpl mScene; private final Animator mAnimator; Queue<MessageBundle> mQueue = new LinkedList<MessageBundle>(); Queue<MessageBundle> mQueue = new LinkedList<MessageBundle>(); private final IAnimationListener mListener; private final IAnimationListener mListener; public AnimationThread(LayoutSceneImpl scene, Animator animator, IAnimationListener listener) { public AnimationThread(LayoutSceneImpl scene, String threadName, IAnimationListener listener) { super(threadName); mScene = scene; mScene = scene; mAnimator = animator; mListener = listener; mListener = listener; } } public abstract SceneResult preAnimation(); public abstract void postAnimation(); @Override @Override public void run() { public void run() { Bridge.prepareThread(); Bridge.prepareThread(); Loading @@ -73,13 +86,20 @@ public class AnimationThread extends Thread { } } }); }); // start the animation. This will send a message to the handler right away, so // call out to the pre-animation work, which should start an animation or more. // mQueue is filled when this method returns. SceneResult result = preAnimation(); mAnimator.start(); if (result.isSuccess() == false) { mListener.done(result); } // loop the animation // loop the animation LayoutScene scene = mScene.getScene(); LayoutScene scene = mScene.getScene(); do { do { // check early. if (mListener.isCanceled()) { break; } // get the next message. // get the next message. MessageBundle bundle = mQueue.poll(); MessageBundle bundle = mQueue.poll(); if (bundle == null) { if (bundle == null) { Loading @@ -97,8 +117,13 @@ public class AnimationThread extends Thread { } } } } // check after sleeping. if (mListener.isCanceled()) { break; } // ready to do the work, acquire the scene. // ready to do the work, acquire the scene. SceneResult result = mScene.acquire(250); result = mScene.acquire(250); if (result.isSuccess() == false) { if (result.isSuccess() == false) { mListener.done(result); mListener.done(result); return; return; Loading @@ -107,6 +132,11 @@ public class AnimationThread extends Thread { // process the bundle. If the animation is not finished, this will enqueue // process the bundle. If the animation is not finished, this will enqueue // the next message, so mQueue will have another one. // the next message, so mQueue will have another one. try { try { // check after acquiring in case it took a while. if (mListener.isCanceled()) { break; } bundle.mTarget.handleMessage(bundle.mMessage); bundle.mTarget.handleMessage(bundle.mMessage); if (mScene.render().isSuccess()) { if (mScene.render().isSuccess()) { mListener.onNewFrame(scene); mListener.onNewFrame(scene); Loading @@ -114,10 +144,11 @@ public class AnimationThread extends Thread { } finally { } finally { mScene.release(); mScene.release(); } } } while (mQueue.size() > 0); } while (mListener.isCanceled() == false && mQueue.size() > 0); mListener.done(SceneStatus.SUCCESS.getResult()); mListener.done(SceneStatus.SUCCESS.getResult()); } finally { } finally { postAnimation(); Handler_Delegate.setCallback(null); Handler_Delegate.setCallback(null); Bridge.cleanupThread(); Bridge.cleanupThread(); } } Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java +198 −53 Original line number Original line Diff line number Diff line Loading @@ -43,8 +43,9 @@ import com.android.layoutlib.bridge.android.BridgeWindow; import com.android.layoutlib.bridge.android.BridgeWindowSession; import com.android.layoutlib.bridge.android.BridgeWindowSession; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.AnimatorInflater; import android.animation.ObjectAnimator; import android.animation.LayoutTransition; import android.app.Fragment_Delegate; import android.app.Fragment_Delegate; import android.graphics.Bitmap; import android.graphics.Bitmap; import android.graphics.Bitmap_Delegate; import android.graphics.Bitmap_Delegate; Loading @@ -56,7 +57,6 @@ import android.util.DisplayMetrics; import android.util.TypedValue; import android.util.TypedValue; import android.view.View; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup; import android.view.ViewParent; import android.view.View.AttachInfo; import android.view.View.AttachInfo; import android.view.View.MeasureSpec; import android.view.View.MeasureSpec; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams; Loading Loading @@ -346,7 +346,7 @@ public class LayoutSceneImpl { return SceneStatus.SUCCESS.getResult(); return SceneStatus.SUCCESS.getResult(); } catch (PostInflateException e) { } catch (PostInflateException e) { return new SceneResult(SceneStatus.ERROR_INFLATION, e.getMessage(), e); return SceneStatus.ERROR_INFLATION.getResult(e.getMessage(), e); } catch (Throwable e) { } catch (Throwable e) { // get the real cause of the exception. // get the real cause of the exception. Throwable t = e; Throwable t = e; Loading @@ -357,7 +357,7 @@ public class LayoutSceneImpl { // log it // log it mParams.getLogger().error(t); mParams.getLogger().error(t); return new SceneResult(SceneStatus.ERROR_INFLATION, t.getMessage(), t); return SceneStatus.ERROR_INFLATION.getResult(t.getMessage(), t); } } } } Loading @@ -370,13 +370,14 @@ public class LayoutSceneImpl { * the scene, or if {@link #acquire(long)} was not called. * the scene, or if {@link #acquire(long)} was not called. * * * @see SceneParams#getRenderingMode() * @see SceneParams#getRenderingMode() * @see LayoutScene#render(long) */ */ public SceneResult render() { public SceneResult render() { checkLock(); checkLock(); try { try { if (mViewRoot == null) { if (mViewRoot == null) { return new SceneResult(SceneStatus.ERROR_NOT_INFLATED); return SceneStatus.ERROR_NOT_INFLATED.getResult(); } } // measure the views // measure the views int w_spec, h_spec; int w_spec, h_spec; Loading Loading @@ -482,7 +483,7 @@ public class LayoutSceneImpl { // log it // log it mParams.getLogger().error(t); mParams.getLogger().error(t); return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t); return SceneStatus.ERROR_UNKNOWN.getResult(t.getMessage(), t); } } } } Loading @@ -493,6 +494,8 @@ public class LayoutSceneImpl { * * * @throws IllegalStateException if the current context is different than the one owned by * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#animate(Object, String, boolean, IAnimationListener) */ */ public SceneResult animate(Object targetObject, String animationName, public SceneResult animate(Object targetObject, String animationName, boolean isFrameworkAnimation, IAnimationListener listener) { boolean isFrameworkAnimation, IAnimationListener listener) { Loading @@ -515,12 +518,11 @@ public class LayoutSceneImpl { if (animationResource != null) { if (animationResource != null) { try { try { ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator( Animator anim = AnimatorInflater.loadAnimator(mContext, animationId); mContext, animationId); if (anim != null) { if (anim != null) { anim.setTarget(targetObject); anim.setTarget(targetObject); new AnimationThread(this, anim, listener).start(); new PlayAnimationThread(anim, this, animationName, listener).start(); return SceneStatus.SUCCESS.getResult(); return SceneStatus.SUCCESS.getResult(); } } Loading @@ -531,15 +533,25 @@ public class LayoutSceneImpl { t = t.getCause(); t = t.getCause(); } } return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t); return SceneStatus.ERROR_UNKNOWN.getResult(t.getMessage(), t); } } } } return new SceneResult(SceneStatus.ERROR_ANIM_NOT_FOUND); return SceneStatus.ERROR_ANIM_NOT_FOUND.getResult(); } } public SceneResult insertChild(ViewGroup parentView, IXmlPullParser childXml, /** int index, IAnimationListener listener) { * Insert a new child into an existing parent. * <p> * {@link #acquire(long)} must have been called before this. * * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#insertChild(Object, IXmlPullParser, int, IAnimationListener) */ public SceneResult insertChild(final ViewGroup parentView, IXmlPullParser childXml, final int index, IAnimationListener listener) { checkLock(); checkLock(); // create a block parser for the XML // create a block parser for the XML Loading @@ -549,83 +561,216 @@ public class LayoutSceneImpl { // inflate the child without adding it to the root since we want to control where it'll // inflate the child without adding it to the root since we want to control where it'll // get added. We do pass the parentView however to ensure that the layoutParams will // get added. We do pass the parentView however to ensure that the layoutParams will // be created correctly. // be created correctly. View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); // add it to the parentView in the correct location invalidateRenderingSize(); try { parentView.addView(child, index); if (listener != null) { } catch (UnsupportedOperationException e) { new AnimationThread(this, "insertChild", listener) { // looks like this is a view class that doesn't support children manipulation! return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN); @Override public SceneResult preAnimation() { parentView.setLayoutTransition(new LayoutTransition()); return addView(parentView, child, index); } } invalidateRenderingSize(); @Override public void postAnimation() { parentView.setLayoutTransition(null); } }.start(); SceneResult result = render(); // always return success since the real status will come through the listener. if (result.isSuccess()) { return SceneStatus.SUCCESS.getResult(child); result.setData(child); } } // add it to the parentView in the correct location SceneResult result = addView(parentView, child, index); if (result.isSuccess() == false) { return result; return result; } } public SceneResult moveChild(ViewGroup parentView, View childView, int index, result = render(); Map<String, String> layoutParamsMap, IAnimationListener listener) { if (result.isSuccess()) { checkLock(); result = result.getCopyWithData(child); } LayoutParams layoutParams = null; return result; } /** * Adds a given view to a given parent at a given index. * * @param parent the parent to receive the view * @param view the view to add to the parent * @param index the index where to do the add. * * @return a SceneResult with {@link SceneStatus#SUCCESS} or * {@link SceneStatus#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support * adding views. */ private SceneResult addView(ViewGroup parent, View view, int index) { try { try { ViewParent parent = childView.getParent(); parent.addView(view, index); if (parent instanceof ViewGroup) { return SceneStatus.SUCCESS.getResult(); ViewGroup parentGroup = (ViewGroup) parent; } catch (UnsupportedOperationException e) { parentGroup.removeView(childView); // looks like this is a view class that doesn't support children manipulation! return SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN.getResult(); } } } // add it to the parentView in the correct location /** * Moves a view to a new parent at a given location * <p> * {@link #acquire(long)} must have been called before this. * * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener) */ public SceneResult moveChild(final ViewGroup parentView, final View childView, final int index, Map<String, String> layoutParamsMap, IAnimationListener listener) { checkLock(); invalidateRenderingSize(); LayoutParams layoutParams = null; if (layoutParamsMap != null) { if (layoutParamsMap != null) { // need to create a new LayoutParams object for the new parent. // need to create a new LayoutParams object for the new parent. layoutParams = parentView.generateLayoutParams( layoutParams = parentView.generateLayoutParams( new BridgeLayoutParamsMapAttributes(layoutParamsMap)); new BridgeLayoutParamsMapAttributes(layoutParamsMap)); } parentView.addView(childView, index, layoutParams); if (listener != null) { } else { final LayoutParams params = layoutParams; parentView.addView(childView, index); new AnimationThread(this, "moveChild", listener) { @Override public SceneResult preAnimation() { parentView.setLayoutTransition(new LayoutTransition()); return moveView(parentView, childView, index, params); } } } catch (UnsupportedOperationException e) { // looks like this is a view class that doesn't support children manipulation! @Override return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN); public void postAnimation() { parentView.setLayoutTransition(null); } } }.start(); invalidateRenderingSize(); // always return success since the real status will come through the listener. return SceneStatus.SUCCESS.getResult(layoutParams); } SceneResult result = moveView(parentView, childView, index, layoutParams); if (result.isSuccess() == false) { return result; } SceneResult result = render(); result = render(); if (layoutParams != null && result.isSuccess()) { if (layoutParams != null && result.isSuccess()) { result.setData(layoutParams); result = result.getCopyWithData(layoutParams); } } return result; return result; } } public SceneResult removeChild(View childView, IAnimationListener listener) { /** checkLock(); * Moves a View from its current parent to a new given parent at a new given location, with * an optional new {@link LayoutParams} instance * * @param parent the new parent * @param view the view to move * @param index the new location in the new parent * @param params an option (can be null) {@link LayoutParams} instance. * * @return a SceneResult with {@link SceneStatus#SUCCESS} or * {@link SceneStatus#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support * adding views. */ private SceneResult moveView(ViewGroup parent, View view, int index, LayoutParams params) { try { try { ViewParent parent = childView.getParent(); ViewGroup previousParent = (ViewGroup) view.getParent(); if (parent instanceof ViewGroup) { previousParent.removeView(view); ViewGroup parentGroup = (ViewGroup) parent; parentGroup.removeView(childView); // add it to the parentView in the correct location if (params != null) { parent.addView(view, index, params); } else { parent.addView(view, index); } } return SceneStatus.SUCCESS.getResult(); } catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) { // looks like this is a view class that doesn't support children manipulation! // looks like this is a view class that doesn't support children manipulation! return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN); return SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN.getResult(); } } } /** * Removes a child from its current parent. * <p> * {@link #acquire(long)} must have been called before this. * * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#removeChild(Object, IAnimationListener) */ public SceneResult removeChild(final View childView, IAnimationListener listener) { checkLock(); invalidateRenderingSize(); invalidateRenderingSize(); final ViewGroup parent = (ViewGroup) childView.getParent(); if (listener != null) { new AnimationThread(this, "moveChild", listener) { @Override public SceneResult preAnimation() { parent.setLayoutTransition(new LayoutTransition()); return removeView(parent, childView); } @Override public void postAnimation() { parent.setLayoutTransition(null); } }.start(); // always return success since the real status will come through the listener. return SceneStatus.SUCCESS.getResult(); } SceneResult result = removeView(parent, childView); if (result.isSuccess() == false) { return result; } return render(); return render(); } } /** * Removes a given view from its current parent. * * @param view the view to remove from its parent * * @return a SceneResult with {@link SceneStatus#SUCCESS} or * {@link SceneStatus#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support * adding views. */ private SceneResult removeView(ViewGroup parent, View view) { try { parent.removeView(view); return SceneStatus.SUCCESS.getResult(); } catch (UnsupportedOperationException e) { // looks like this is a view class that doesn't support children manipulation! return SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN.getResult(); } } /** /** * Checks that the lock is owned by the current thread and that the current context is the one * Checks that the lock is owned by the current thread and that the current context is the one * from this scene. * from this scene. Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java 0 → 100644 +48 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.layoutlib.bridge.impl; import com.android.layoutlib.api.SceneResult; import com.android.layoutlib.api.LayoutScene.IAnimationListener; import com.android.layoutlib.api.SceneResult.SceneStatus; import android.animation.Animator; public class PlayAnimationThread extends AnimationThread { private final Animator mAnimator; public PlayAnimationThread(Animator animator, LayoutSceneImpl scene, String animName, IAnimationListener listener) { super(scene, animName, listener); mAnimator = animator; } @Override public SceneResult preAnimation() { // start the animation. This will send a message to the handler right away, so // the queue is filled when this method returns. mAnimator.start(); return SceneStatus.SUCCESS.getResult(); } @Override public void postAnimation() { // nothing to be done. } } Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -335,7 +335,7 @@ public final class Bridge extends LayoutBridge { t2 = t.getCause(); t2 = t.getCause(); } } return new BridgeLayoutScene(null, return new BridgeLayoutScene(null, new SceneResult(SceneStatus.ERROR_UNKNOWN, t2.getMessage(), t2)); SceneStatus.ERROR_UNKNOWN.getResult(t2.getMessage(), t2)); } } } } Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java +41 −10 Original line number Original line Diff line number Diff line Loading @@ -22,7 +22,6 @@ import com.android.layoutlib.api.LayoutScene.IAnimationListener; import com.android.layoutlib.api.SceneResult.SceneStatus; import com.android.layoutlib.api.SceneResult.SceneStatus; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.Bridge; import android.animation.Animator; import android.animation.ValueAnimator; import android.animation.ValueAnimator; import android.os.Handler; import android.os.Handler; import android.os.Handler_Delegate; import android.os.Handler_Delegate; Loading @@ -32,7 +31,19 @@ import android.os.Handler_Delegate.IHandlerCallback; import java.util.LinkedList; import java.util.LinkedList; import java.util.Queue; import java.util.Queue; public class AnimationThread extends Thread { /** * Abstract animation thread. * <p/> * This does not actually start an animation, instead it fakes a looper that will play whatever * animation is sending messages to its own {@link Handler}. * <p/> * Classes should implement {@link #preAnimation()} and {@link #postAnimation()}. * <p/> * If {@link #preAnimation()} does not start an animation something then the thread doesn't do * anything. * */ public abstract class AnimationThread extends Thread { private static class MessageBundle { private static class MessageBundle { final Handler mTarget; final Handler mTarget; Loading @@ -47,17 +58,19 @@ public class AnimationThread extends Thread { } } private final LayoutSceneImpl mScene; private final LayoutSceneImpl mScene; private final Animator mAnimator; Queue<MessageBundle> mQueue = new LinkedList<MessageBundle>(); Queue<MessageBundle> mQueue = new LinkedList<MessageBundle>(); private final IAnimationListener mListener; private final IAnimationListener mListener; public AnimationThread(LayoutSceneImpl scene, Animator animator, IAnimationListener listener) { public AnimationThread(LayoutSceneImpl scene, String threadName, IAnimationListener listener) { super(threadName); mScene = scene; mScene = scene; mAnimator = animator; mListener = listener; mListener = listener; } } public abstract SceneResult preAnimation(); public abstract void postAnimation(); @Override @Override public void run() { public void run() { Bridge.prepareThread(); Bridge.prepareThread(); Loading @@ -73,13 +86,20 @@ public class AnimationThread extends Thread { } } }); }); // start the animation. This will send a message to the handler right away, so // call out to the pre-animation work, which should start an animation or more. // mQueue is filled when this method returns. SceneResult result = preAnimation(); mAnimator.start(); if (result.isSuccess() == false) { mListener.done(result); } // loop the animation // loop the animation LayoutScene scene = mScene.getScene(); LayoutScene scene = mScene.getScene(); do { do { // check early. if (mListener.isCanceled()) { break; } // get the next message. // get the next message. MessageBundle bundle = mQueue.poll(); MessageBundle bundle = mQueue.poll(); if (bundle == null) { if (bundle == null) { Loading @@ -97,8 +117,13 @@ public class AnimationThread extends Thread { } } } } // check after sleeping. if (mListener.isCanceled()) { break; } // ready to do the work, acquire the scene. // ready to do the work, acquire the scene. SceneResult result = mScene.acquire(250); result = mScene.acquire(250); if (result.isSuccess() == false) { if (result.isSuccess() == false) { mListener.done(result); mListener.done(result); return; return; Loading @@ -107,6 +132,11 @@ public class AnimationThread extends Thread { // process the bundle. If the animation is not finished, this will enqueue // process the bundle. If the animation is not finished, this will enqueue // the next message, so mQueue will have another one. // the next message, so mQueue will have another one. try { try { // check after acquiring in case it took a while. if (mListener.isCanceled()) { break; } bundle.mTarget.handleMessage(bundle.mMessage); bundle.mTarget.handleMessage(bundle.mMessage); if (mScene.render().isSuccess()) { if (mScene.render().isSuccess()) { mListener.onNewFrame(scene); mListener.onNewFrame(scene); Loading @@ -114,10 +144,11 @@ public class AnimationThread extends Thread { } finally { } finally { mScene.release(); mScene.release(); } } } while (mQueue.size() > 0); } while (mListener.isCanceled() == false && mQueue.size() > 0); mListener.done(SceneStatus.SUCCESS.getResult()); mListener.done(SceneStatus.SUCCESS.getResult()); } finally { } finally { postAnimation(); Handler_Delegate.setCallback(null); Handler_Delegate.setCallback(null); Bridge.cleanupThread(); Bridge.cleanupThread(); } } Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java +198 −53 Original line number Original line Diff line number Diff line Loading @@ -43,8 +43,9 @@ import com.android.layoutlib.bridge.android.BridgeWindow; import com.android.layoutlib.bridge.android.BridgeWindowSession; import com.android.layoutlib.bridge.android.BridgeWindowSession; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.AnimatorInflater; import android.animation.ObjectAnimator; import android.animation.LayoutTransition; import android.app.Fragment_Delegate; import android.app.Fragment_Delegate; import android.graphics.Bitmap; import android.graphics.Bitmap; import android.graphics.Bitmap_Delegate; import android.graphics.Bitmap_Delegate; Loading @@ -56,7 +57,6 @@ import android.util.DisplayMetrics; import android.util.TypedValue; import android.util.TypedValue; import android.view.View; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup; import android.view.ViewParent; import android.view.View.AttachInfo; import android.view.View.AttachInfo; import android.view.View.MeasureSpec; import android.view.View.MeasureSpec; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams; Loading Loading @@ -346,7 +346,7 @@ public class LayoutSceneImpl { return SceneStatus.SUCCESS.getResult(); return SceneStatus.SUCCESS.getResult(); } catch (PostInflateException e) { } catch (PostInflateException e) { return new SceneResult(SceneStatus.ERROR_INFLATION, e.getMessage(), e); return SceneStatus.ERROR_INFLATION.getResult(e.getMessage(), e); } catch (Throwable e) { } catch (Throwable e) { // get the real cause of the exception. // get the real cause of the exception. Throwable t = e; Throwable t = e; Loading @@ -357,7 +357,7 @@ public class LayoutSceneImpl { // log it // log it mParams.getLogger().error(t); mParams.getLogger().error(t); return new SceneResult(SceneStatus.ERROR_INFLATION, t.getMessage(), t); return SceneStatus.ERROR_INFLATION.getResult(t.getMessage(), t); } } } } Loading @@ -370,13 +370,14 @@ public class LayoutSceneImpl { * the scene, or if {@link #acquire(long)} was not called. * the scene, or if {@link #acquire(long)} was not called. * * * @see SceneParams#getRenderingMode() * @see SceneParams#getRenderingMode() * @see LayoutScene#render(long) */ */ public SceneResult render() { public SceneResult render() { checkLock(); checkLock(); try { try { if (mViewRoot == null) { if (mViewRoot == null) { return new SceneResult(SceneStatus.ERROR_NOT_INFLATED); return SceneStatus.ERROR_NOT_INFLATED.getResult(); } } // measure the views // measure the views int w_spec, h_spec; int w_spec, h_spec; Loading Loading @@ -482,7 +483,7 @@ public class LayoutSceneImpl { // log it // log it mParams.getLogger().error(t); mParams.getLogger().error(t); return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t); return SceneStatus.ERROR_UNKNOWN.getResult(t.getMessage(), t); } } } } Loading @@ -493,6 +494,8 @@ public class LayoutSceneImpl { * * * @throws IllegalStateException if the current context is different than the one owned by * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#animate(Object, String, boolean, IAnimationListener) */ */ public SceneResult animate(Object targetObject, String animationName, public SceneResult animate(Object targetObject, String animationName, boolean isFrameworkAnimation, IAnimationListener listener) { boolean isFrameworkAnimation, IAnimationListener listener) { Loading @@ -515,12 +518,11 @@ public class LayoutSceneImpl { if (animationResource != null) { if (animationResource != null) { try { try { ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator( Animator anim = AnimatorInflater.loadAnimator(mContext, animationId); mContext, animationId); if (anim != null) { if (anim != null) { anim.setTarget(targetObject); anim.setTarget(targetObject); new AnimationThread(this, anim, listener).start(); new PlayAnimationThread(anim, this, animationName, listener).start(); return SceneStatus.SUCCESS.getResult(); return SceneStatus.SUCCESS.getResult(); } } Loading @@ -531,15 +533,25 @@ public class LayoutSceneImpl { t = t.getCause(); t = t.getCause(); } } return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t); return SceneStatus.ERROR_UNKNOWN.getResult(t.getMessage(), t); } } } } return new SceneResult(SceneStatus.ERROR_ANIM_NOT_FOUND); return SceneStatus.ERROR_ANIM_NOT_FOUND.getResult(); } } public SceneResult insertChild(ViewGroup parentView, IXmlPullParser childXml, /** int index, IAnimationListener listener) { * Insert a new child into an existing parent. * <p> * {@link #acquire(long)} must have been called before this. * * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#insertChild(Object, IXmlPullParser, int, IAnimationListener) */ public SceneResult insertChild(final ViewGroup parentView, IXmlPullParser childXml, final int index, IAnimationListener listener) { checkLock(); checkLock(); // create a block parser for the XML // create a block parser for the XML Loading @@ -549,83 +561,216 @@ public class LayoutSceneImpl { // inflate the child without adding it to the root since we want to control where it'll // inflate the child without adding it to the root since we want to control where it'll // get added. We do pass the parentView however to ensure that the layoutParams will // get added. We do pass the parentView however to ensure that the layoutParams will // be created correctly. // be created correctly. View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); // add it to the parentView in the correct location invalidateRenderingSize(); try { parentView.addView(child, index); if (listener != null) { } catch (UnsupportedOperationException e) { new AnimationThread(this, "insertChild", listener) { // looks like this is a view class that doesn't support children manipulation! return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN); @Override public SceneResult preAnimation() { parentView.setLayoutTransition(new LayoutTransition()); return addView(parentView, child, index); } } invalidateRenderingSize(); @Override public void postAnimation() { parentView.setLayoutTransition(null); } }.start(); SceneResult result = render(); // always return success since the real status will come through the listener. if (result.isSuccess()) { return SceneStatus.SUCCESS.getResult(child); result.setData(child); } } // add it to the parentView in the correct location SceneResult result = addView(parentView, child, index); if (result.isSuccess() == false) { return result; return result; } } public SceneResult moveChild(ViewGroup parentView, View childView, int index, result = render(); Map<String, String> layoutParamsMap, IAnimationListener listener) { if (result.isSuccess()) { checkLock(); result = result.getCopyWithData(child); } LayoutParams layoutParams = null; return result; } /** * Adds a given view to a given parent at a given index. * * @param parent the parent to receive the view * @param view the view to add to the parent * @param index the index where to do the add. * * @return a SceneResult with {@link SceneStatus#SUCCESS} or * {@link SceneStatus#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support * adding views. */ private SceneResult addView(ViewGroup parent, View view, int index) { try { try { ViewParent parent = childView.getParent(); parent.addView(view, index); if (parent instanceof ViewGroup) { return SceneStatus.SUCCESS.getResult(); ViewGroup parentGroup = (ViewGroup) parent; } catch (UnsupportedOperationException e) { parentGroup.removeView(childView); // looks like this is a view class that doesn't support children manipulation! return SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN.getResult(); } } } // add it to the parentView in the correct location /** * Moves a view to a new parent at a given location * <p> * {@link #acquire(long)} must have been called before this. * * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener) */ public SceneResult moveChild(final ViewGroup parentView, final View childView, final int index, Map<String, String> layoutParamsMap, IAnimationListener listener) { checkLock(); invalidateRenderingSize(); LayoutParams layoutParams = null; if (layoutParamsMap != null) { if (layoutParamsMap != null) { // need to create a new LayoutParams object for the new parent. // need to create a new LayoutParams object for the new parent. layoutParams = parentView.generateLayoutParams( layoutParams = parentView.generateLayoutParams( new BridgeLayoutParamsMapAttributes(layoutParamsMap)); new BridgeLayoutParamsMapAttributes(layoutParamsMap)); } parentView.addView(childView, index, layoutParams); if (listener != null) { } else { final LayoutParams params = layoutParams; parentView.addView(childView, index); new AnimationThread(this, "moveChild", listener) { @Override public SceneResult preAnimation() { parentView.setLayoutTransition(new LayoutTransition()); return moveView(parentView, childView, index, params); } } } catch (UnsupportedOperationException e) { // looks like this is a view class that doesn't support children manipulation! @Override return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN); public void postAnimation() { parentView.setLayoutTransition(null); } } }.start(); invalidateRenderingSize(); // always return success since the real status will come through the listener. return SceneStatus.SUCCESS.getResult(layoutParams); } SceneResult result = moveView(parentView, childView, index, layoutParams); if (result.isSuccess() == false) { return result; } SceneResult result = render(); result = render(); if (layoutParams != null && result.isSuccess()) { if (layoutParams != null && result.isSuccess()) { result.setData(layoutParams); result = result.getCopyWithData(layoutParams); } } return result; return result; } } public SceneResult removeChild(View childView, IAnimationListener listener) { /** checkLock(); * Moves a View from its current parent to a new given parent at a new given location, with * an optional new {@link LayoutParams} instance * * @param parent the new parent * @param view the view to move * @param index the new location in the new parent * @param params an option (can be null) {@link LayoutParams} instance. * * @return a SceneResult with {@link SceneStatus#SUCCESS} or * {@link SceneStatus#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support * adding views. */ private SceneResult moveView(ViewGroup parent, View view, int index, LayoutParams params) { try { try { ViewParent parent = childView.getParent(); ViewGroup previousParent = (ViewGroup) view.getParent(); if (parent instanceof ViewGroup) { previousParent.removeView(view); ViewGroup parentGroup = (ViewGroup) parent; parentGroup.removeView(childView); // add it to the parentView in the correct location if (params != null) { parent.addView(view, index, params); } else { parent.addView(view, index); } } return SceneStatus.SUCCESS.getResult(); } catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) { // looks like this is a view class that doesn't support children manipulation! // looks like this is a view class that doesn't support children manipulation! return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN); return SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN.getResult(); } } } /** * Removes a child from its current parent. * <p> * {@link #acquire(long)} must have been called before this. * * @throws IllegalStateException if the current context is different than the one owned by * the scene, or if {@link #acquire(long)} was not called. * * @see LayoutScene#removeChild(Object, IAnimationListener) */ public SceneResult removeChild(final View childView, IAnimationListener listener) { checkLock(); invalidateRenderingSize(); invalidateRenderingSize(); final ViewGroup parent = (ViewGroup) childView.getParent(); if (listener != null) { new AnimationThread(this, "moveChild", listener) { @Override public SceneResult preAnimation() { parent.setLayoutTransition(new LayoutTransition()); return removeView(parent, childView); } @Override public void postAnimation() { parent.setLayoutTransition(null); } }.start(); // always return success since the real status will come through the listener. return SceneStatus.SUCCESS.getResult(); } SceneResult result = removeView(parent, childView); if (result.isSuccess() == false) { return result; } return render(); return render(); } } /** * Removes a given view from its current parent. * * @param view the view to remove from its parent * * @return a SceneResult with {@link SceneStatus#SUCCESS} or * {@link SceneStatus#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support * adding views. */ private SceneResult removeView(ViewGroup parent, View view) { try { parent.removeView(view); return SceneStatus.SUCCESS.getResult(); } catch (UnsupportedOperationException e) { // looks like this is a view class that doesn't support children manipulation! return SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN.getResult(); } } /** /** * Checks that the lock is owned by the current thread and that the current context is the one * Checks that the lock is owned by the current thread and that the current context is the one * from this scene. * from this scene. Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java 0 → 100644 +48 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.layoutlib.bridge.impl; import com.android.layoutlib.api.SceneResult; import com.android.layoutlib.api.LayoutScene.IAnimationListener; import com.android.layoutlib.api.SceneResult.SceneStatus; import android.animation.Animator; public class PlayAnimationThread extends AnimationThread { private final Animator mAnimator; public PlayAnimationThread(Animator animator, LayoutSceneImpl scene, String animName, IAnimationListener listener) { super(scene, animName, listener); mAnimator = animator; } @Override public SceneResult preAnimation() { // start the animation. This will send a message to the handler right away, so // the queue is filled when this method returns. mAnimator.start(); return SceneStatus.SUCCESS.getResult(); } @Override public void postAnimation() { // nothing to be done. } }