diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 7aa0e3ccb2004..2a94774bafbc8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -335,7 +335,7 @@ public final class Bridge extends LayoutBridge { t2 = t.getCause(); } return new BridgeLayoutScene(null, - new SceneResult(SceneStatus.ERROR_UNKNOWN, t2.getMessage(), t2)); + SceneStatus.ERROR_UNKNOWN.getResult(t2.getMessage(), t2)); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java index 2b9d52fbcc64d..400a05fc0ac11 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java @@ -22,7 +22,6 @@ import com.android.layoutlib.api.LayoutScene.IAnimationListener; import com.android.layoutlib.api.SceneResult.SceneStatus; import com.android.layoutlib.bridge.Bridge; -import android.animation.Animator; import android.animation.ValueAnimator; import android.os.Handler; import android.os.Handler_Delegate; @@ -32,7 +31,19 @@ import android.os.Handler_Delegate.IHandlerCallback; import java.util.LinkedList; import java.util.Queue; -public class AnimationThread extends Thread { +/** + * Abstract animation thread. + *
+ * 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}. + * + * Classes should implement {@link #preAnimation()} and {@link #postAnimation()}. + * + * 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 { final Handler mTarget; @@ -47,17 +58,19 @@ public class AnimationThread extends Thread { } private final LayoutSceneImpl mScene; - private final Animator mAnimator; Queue+ * {@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(); // create a block parser for the XML @@ -549,83 +561,216 @@ public class LayoutSceneImpl { // 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 // be created correctly. - View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); - - // add it to the parentView in the correct location - try { - parentView.addView(child, index); - } catch (UnsupportedOperationException e) { - // looks like this is a view class that doesn't support children manipulation! - return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN); - } + final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); invalidateRenderingSize(); - SceneResult result = render(); + if (listener != null) { + new AnimationThread(this, "insertChild", listener) { + + @Override + public SceneResult preAnimation() { + parentView.setLayoutTransition(new LayoutTransition()); + return addView(parentView, child, index); + } + + @Override + public void postAnimation() { + parentView.setLayoutTransition(null); + } + }.start(); + + // always return success since the real status will come through the listener. + return SceneStatus.SUCCESS.getResult(child); + } + + // add it to the parentView in the correct location + SceneResult result = addView(parentView, child, index); + if (result.isSuccess() == false) { + return result; + } + + result = render(); if (result.isSuccess()) { - result.setData(child); + result = result.getCopyWithData(child); } return result; } - public SceneResult moveChild(ViewGroup parentView, View childView, int index, + /** + * 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 { + parent.addView(view, index); + 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(); + } + } + + /** + * Moves a view to a new parent at a given location + *
+ * {@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
+ * {@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();
+ 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();
}
+ /**
+ * 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
* from this scene.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java
new file mode 100644
index 0000000000000..bbc7f4bceaa15
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ }
+}