RenderSessionImpl.java revision 0d829bd739dfcb3374971c776676bf2e53bab43c
13bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/*
23bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
33bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
43bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
53bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * you may not use this file except in compliance with the License.
63bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * You may obtain a copy of the License at
73bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
83bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
93bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Unless required by applicable law or agreed to in writing, software
113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * See the License for the specific language governing permissions and
143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * limitations under the License.
153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */
163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetpackage com.android.layoutlib.bridge.impl;
183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
19ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
20ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
21ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
22ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
23ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
24ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
25ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
26ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
27ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet
28ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener;
29ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ILayoutPullParser;
30ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.IProjectCallback;
31907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohetimport com.android.ide.common.rendering.api.LayoutLog;
32ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Params;
330d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
34ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
35ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceDensity;
36ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue;
37ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
38ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.StyleResourceValue;
39ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo;
40ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Params.RenderingMode;
410d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
42ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.internal.util.XmlUtils;
44ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeInflater;
47ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindow;
493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindowSession;
503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.Animator;
53ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.AnimatorInflater;
5433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.LayoutTransition;
5562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate;
573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap;
583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas;
603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.drawable.Drawable;
613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Handler;
623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.DisplayMetrics;
633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.TypedValue;
643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View;
653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.ViewGroup;
663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.AttachInfo;
673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec;
68ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport android.view.ViewGroup.LayoutParams;
693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout;
703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost;
713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabWidget;
723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color;
743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D;
753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage;
763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList;
773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List;
783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map;
79ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.TimeUnit;
80ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.locks.ReentrantLock;
813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/**
83ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * Class implementing the render session.
843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
85ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
86ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout.
883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */
900d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetpublic class RenderSessionImpl extends FrameworkResourceIdProvider {
913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
95ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
96ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * The current context being rendered. This is set through {@link #acquire(long)} and
97ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #init(long)}, and unset in {@link #release()}.
98ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
99ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    private static BridgeContext sCurrentContext = null;
100ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
101ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private final Params mParams;
1023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // scene state
104ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private RenderSession mScene;
1053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeContext mContext;
1063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
1073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeInflater mInflater;
1083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private int mScreenOffset;
1096a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet    private ResourceValue mWindowBackground;
1103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private FrameLayout mViewRoot;
1111392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private Canvas mCanvas;
1121392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1131392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenHeight = -1;
1143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // information being returned through the API
1163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BufferedImage mImage;
1173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private ViewInfo mViewInfo;
1183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final class PostInflateException extends Exception {
1203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        private static final long serialVersionUID = 1L;
1213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        public PostInflateException(String message) {
1233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            super(message);
1243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
1263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
1293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
130ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a
131ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
1323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     *
1333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
1343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
135ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSessionImpl(Params params) {
1363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // copy the params.
137ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mParams = new Params(params);
138ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
139ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
140ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
141ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
142ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * inflater, and parser.
143ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
144ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
145ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
146ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
147ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
148ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #acquire(long)
149ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
150ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
151ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result init(long timeout) {
152ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
153ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // the result.
154ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = acquireLock(timeout);
155ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (result != null) {
156ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
157ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
1583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // setup the display Metrics.
1603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        DisplayMetrics metrics = new DisplayMetrics();
1613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.densityDpi = mParams.getDensity();
1623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT;
1633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.scaledDensity = metrics.density;
1643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.widthPixels = mParams.getScreenWidth();
1653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.heightPixels = mParams.getScreenHeight();
1663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.xdpi = mParams.getXdpi();
1673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.ydpi = mParams.getYdpi();
1683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1690d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        RenderResources resources = mParams.getResources();
1703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the context
1720d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
173089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet                mParams.getProjectCallback());
1743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
175ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
1760d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        setUp();
1773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // get the screen offset and window-background resource
1793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mWindowBackground = null;
1803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mScreenOffset = 0;
1810d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        StyleResourceValue theme = resources.getTheme();
182089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet        if (theme != null && mParams.isBgColorOverridden() == false) {
1830d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            mWindowBackground = resources.findItemInTheme("windowBackground");
1840d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            mWindowBackground = resources.resolveResValue(mWindowBackground);
1853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1860d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            mScreenOffset = getScreenOffset(resources, metrics);
1873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the inflater and parser.
1903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mInflater = new BridgeInflater(mContext, mParams.getProjectCallback());
1913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mContext.setBridgeInflater(mInflater);
1923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mInflater.setFactory2(mContext);
1933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
1953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                mContext, false /* platformResourceFlag */);
196ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
197ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return SUCCESS.createResult();
1983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
1993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
201ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Prepares the scene for action.
202ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
203ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * This call is blocking if another rendering/inflating is currently happening, and will return
204ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * whether the preparation worked.
205ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
206ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * The preparation can fail if another rendering took too long and the timeout was elapsed.
207ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
208ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * More than one call to this from the same thread will have no effect and will return
209ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * {@link Result#SUCCESS}.
210ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
211ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * After scene actions have taken place, only one call to {@link #release()} must be
212ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * done.
213ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
214ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
215ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
216ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
217ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
218ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
219ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
220ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if {@link #init(long)} was never called.
221ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
222ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result acquire(long timeout) {
223ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (mContext == null) {
224ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("After scene creation, #init() must be called");
225ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
226ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
227ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
228ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // the result.
229ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = acquireLock(timeout);
230ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (result != null) {
231ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
232ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
2333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2340d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        setUp();
235ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
2363054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet        return SUCCESS.createResult();
2373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
240ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Acquire the lock so that the scene can be acted upon.
2413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
242ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * This returns null if the lock was just acquired, otherwise it returns
243ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
244ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * instance (see {@link Result#getStatus()}) if an error occurred.
245ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
246ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
247ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return null if the lock was just acquire or another result depending on the state.
248ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
249ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
250ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene.
2513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
252ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result acquireLock(long timeout) {
253ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
254ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
255ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
256ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
257ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
258ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (acquired == false) {
2593054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet                    return ERROR_TIMEOUT.createResult();
260ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
261ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (InterruptedException e) {
2623054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet                return ERROR_LOCK_INTERRUPTED.createResult();
263ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
264ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
265ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // This thread holds the lock already. Checks that this wasn't for a different context.
266ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // If this is called by init, mContext will be null and so should sCurrentContext
267ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // anyway
268ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (mContext != sCurrentContext) {
269ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                throw new IllegalStateException("Acquiring different scenes from same thread without releases");
270ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
2713054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet            return SUCCESS.createResult();
272ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
2733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
274ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        return null;
275ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
276ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
277ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
278ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Cleans up the scene after an action.
279ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
280ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    public void release() {
281ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
282ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
283ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // with the use of finally blocks, it is possible to find ourself calling this
284ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // without a successful call to prepareScene. This test makes sure that unlock() will
285ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // not throw IllegalMonitorStateException.
286ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread()) {
2870d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            tearDown();
288ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            lock.unlock();
289ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
2903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
2930d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * Sets up the session for rendering.
2940d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * <p/>
2950d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * The counterpart is {@link #tearDown()}.
2960d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     */
2970d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    private void setUp() {
2980d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // make sure the Resources object references the context (and other objects) for this
2990d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // scene
3000d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.initResources();
3010d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        sCurrentContext = mContext;
3020d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3030d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        LayoutLog currentLog = mParams.getLog();
3040d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        Bridge.setLog(currentLog);
3050d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
3060d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setLogger(currentLog);
3070d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
3080d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3090d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    /**
3100d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * Tear down the session after rendering.
3110d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * <p/>
3120d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * The counterpart is {@link #setUp()}.
3130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     */
3140d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    private void tearDown() {
3150d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // Make sure to remove static references, otherwise we could not unload the lib
3160d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.disposeResources();
3170d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        sCurrentContext = null;
3180d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3190d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        Bridge.setLog(null);
3200d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(null);
3210d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setLogger(null);
3220d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3230d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
3240d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3250d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    /**
3263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Inflates the layout.
3273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
328ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
329ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
330ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
331ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
3323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
333ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result inflate() {
334ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
335ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
3363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
3373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot = new FrameLayout(mContext);
3393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
3413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // it can instantiate the custom Fragment.
3423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Fragment_Delegate.setProjectCallback(mParams.getProjectCallback());
3433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            View view = mInflater.inflate(mBlockParser, mViewRoot);
3453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
3473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            postInflateProcess(view, mParams.getProjectCallback());
3483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Fragment_Delegate.setProjectCallback(null);
3503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // set the AttachInfo on the root view.
3523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
3533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    new Handler(), null);
3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mHasWindowFocus = true;
3553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mWindowVisibility = View.VISIBLE;
3563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mInTouchMode = false; // this is so that we can display selections.
35790f9956c17660c35ee6fe934815c16e97bf0d3f8Xavier Ducrohet            info.mHardwareAccelerated = false;
3583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot.dispatchAttachedToWindow(info, 0);
3593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the background drawable
3613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mWindowBackground != null) {
3623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                Drawable d = ResourceHelper.getDrawable(mWindowBackground,
3633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                        mContext, true /* isFramework */);
3643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                mViewRoot.setBackgroundDrawable(d);
3653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
367ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
3683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (PostInflateException e) {
369ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
3703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
3713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
3723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
3733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
3743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
3753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
377ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
3793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
3803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
3823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Renders the scene.
3833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
384ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
385ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
386ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
387ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
3881392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     *
3891392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     * @see SceneParams#getRenderingMode()
39033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#render(long)
3913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
392ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result render() {
393ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
394ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
3953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
3963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mViewRoot == null) {
397ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
3983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // measure the views
4003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            int w_spec, h_spec;
4013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
402e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet            RenderingMode renderingMode = mParams.getRenderingMode();
403e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet
4041392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // only do the screen measure when needed.
4051392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            boolean newRenderSize = false;
4061392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
4071392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                newRenderSize = true;
4081392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mMeasuredScreenWidth = mParams.getScreenWidth();
4091392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mMeasuredScreenHeight = mParams.getScreenHeight();
4101392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
4111392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
4121392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    // measure the full size needed by the layout.
4131392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth,
4141392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            renderingMode.isHorizExpand() ?
4151392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4161392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    : MeasureSpec.EXACTLY);
4171392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight - mScreenOffset,
4181392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            renderingMode.isVertExpand() ?
4191392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4201392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    : MeasureSpec.EXACTLY);
4211392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    mViewRoot.measure(w_spec, h_spec);
4221392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
4231392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
4241392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
4251392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        if (neededWidth > mMeasuredScreenWidth) {
4261392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            mMeasuredScreenWidth = neededWidth;
4271392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
428e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
4293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4301392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isVertExpand()) {
4311392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
4321392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        if (neededHeight > mMeasuredScreenHeight - mScreenOffset) {
4331392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            mMeasuredScreenHeight = neededHeight + mScreenOffset;
4341392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
435e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
4363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
4373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // remeasure with the size we need
4403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // This must always be done before the call to layout
4411392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, MeasureSpec.EXACTLY);
4421392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight - mScreenOffset,
4433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    MeasureSpec.EXACTLY);
4443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot.measure(w_spec, h_spec);
4453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // now do the layout.
4471392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            mViewRoot.layout(0, mScreenOffset, mMeasuredScreenWidth, mMeasuredScreenHeight);
4483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // draw the views
4503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // create the BufferedImage into which the layout will be rendered.
4511392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            if (newRenderSize || mCanvas == null) {
4521392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                if (mParams.getImageFactory() != null) {
4531392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    mImage = mParams.getImageFactory().getImage(mMeasuredScreenWidth,
4541392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            mMeasuredScreenHeight - mScreenOffset);
4551392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                } else {
4561392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    mImage = new BufferedImage(mMeasuredScreenWidth,
4571392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            mMeasuredScreenHeight - mScreenOffset, BufferedImage.TYPE_INT_ARGB);
4581392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
4593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
460ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                if (mParams.isBgColorOverridden()) {
4611392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
462ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    gc.setColor(new Color(mParams.getOverrideBgColor(), true));
4631392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight - mScreenOffset);
4641392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    gc.dispose();
4651392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4671392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                // create an Android bitmap around the BufferedImage
4681392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
4691392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        true /*isMutable*/,
4706a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet                        ResourceDensity.getEnum(mParams.getDensity()));
4713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4721392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                // create a Canvas around the Android bitmap
4731392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mCanvas = new Canvas(bitmap);
4741392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mCanvas.setDensity(mParams.getDensity());
4751392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            }
4763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4771392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            mViewRoot.draw(mCanvas);
4781392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
4793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext);
4803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // success!
482ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
4833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
4843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
4853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
4863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
4873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
4883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
490ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
4913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
4923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
4933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
495ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Animate an object
496ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
497ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
498ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
499ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
500ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
50133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
50233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#animate(Object, String, boolean, IAnimationListener)
503ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
504ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
505ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
506ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
507ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
508ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // find the animation file.
5096a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet        ResourceValue animationResource = null;
510ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        int animationId = 0;
511ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (isFrameworkAnimation) {
5120d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            animationResource = mContext.getRenderResources().getFrameworkResource(
5130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet                    RenderResources.RES_ANIMATOR, animationName);
514ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
5150d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet                animationId = Bridge.getResourceValue(RenderResources.RES_ANIMATOR,
516551346323dace2bdb2509a7f5c9a0a200794b29cXavier Ducrohet                        animationName);
517ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
518ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
5190d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            animationResource = mContext.getRenderResources().getProjectResource(
5200d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet                    RenderResources.RES_ANIMATOR, animationName);
521ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
522551346323dace2bdb2509a7f5c9a0a200794b29cXavier Ducrohet                animationId = mContext.getProjectCallback().getResourceValue(
5230d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet                        RenderResources.RES_ANIMATOR, animationName);
524ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
525ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
526ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
527ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (animationResource != null) {
528ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
52933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(mContext, animationId);
530ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (anim != null) {
531ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                    anim.setTarget(targetObject);
532ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
53333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
534ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
535ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    return SUCCESS.createResult();
536ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
537ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (Exception e) {
538b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                // get the real cause of the exception.
539b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                Throwable t = e;
540b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                while (t.getCause() != null) {
541b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                    t = t.getCause();
542b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                }
543b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
544ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
545ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
546ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
547ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
548ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
549b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
550b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
55133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
55233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Insert a new child into an existing parent.
55333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
55433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
55533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
55633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
55733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
55833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
559ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @see LayoutScene#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
56033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
561ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
56233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final int index, IAnimationListener listener) {
563b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
564b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
565b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // create a block parser for the XML
566b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
567b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                false /* platformResourceFlag */);
568b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
569b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
570b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
571b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // be created correctly.
57233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
573b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
57433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
57533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
57633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
57733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
57833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
57933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
580ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
58133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
58233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return addView(parentView, child, index);
58333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
58433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
58533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
58633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
58733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(null);
58833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
58933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
59033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
59133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
592ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(child);
5931392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        }
5941392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
59533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        // add it to the parentView in the correct location
596ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = addView(parentView, child, index);
59733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
59833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
59933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
600b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
60133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        result = render();
6021766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        if (result.isSuccess()) {
60333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(child);
6041766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        }
6051766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet
6061766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        return result;
607b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
608b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
60933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
61033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Adds a given view to a given parent at a given index.
61133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
61233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param parent the parent to receive the view
61333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to add to the parent
61433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the index where to do the add.
61533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
616ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
617ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
61833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
61933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
620ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
62133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
62233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.addView(view, index);
623ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
62433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
62533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
626ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
62733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
62833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
62933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
63033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
63133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a view to a new parent at a given location
63233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
63333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
63433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
63533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
63633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
63733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
63833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener)
63933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
64062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
64124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
642b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
643b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
64433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
64533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
646ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        LayoutParams layoutParams = null;
64733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (layoutParamsMap != null) {
64833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
64962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
65033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
65133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
6521392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
65362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        // get the current parent of the view that needs to be moved.
65462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
65562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
65633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
65733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final LayoutParams params = layoutParams;
658ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
65924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
66024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
66124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousParent != newParentView) {
66224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new Thread("not animated moveChild") {
66324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
66424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void run() {
66524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
66624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                params);
66724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (result.isSuccess() == false) {
66824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
66924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
67024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
67124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // ready to do the work, acquire the scene.
67224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        result = acquire(250);
67324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (result.isSuccess() == false) {
67424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
67524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            return;
67624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
67724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
67824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        try {
67924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            result = render();
68024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            if (result.isSuccess()) {
68124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
68224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            }
68324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        } finally {
68424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            release();
68524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
68624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
68724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        listener.done(result);
68862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
68924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
69024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            } else {
69124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
69262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
69324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
69424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public Result preAnimation() {
69524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // set up the transition for the parent.
69624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
69724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(transition);
6985562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet
69924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
70024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // animation playing just before).
70124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
70224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // on the LayoutTransition.
70324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
70424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
70524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
706ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
70724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
70824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
70924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
71024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
71124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
71224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
71324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
71424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
71524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
71624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
71724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
71824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
71924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void postAnimation() {
72024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(null);
72124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        newParentView.setLayoutTransition(null);
72224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
72324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
72424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            }
72533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
72633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
727ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
728b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
729b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
73062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
73133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
73233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
73333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
734b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
73533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        result = render();
736ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
73733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
738ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        }
739ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
740ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        return result;
741b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
742b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
74333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
74433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
74533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * an optional new {@link LayoutParams} instance
74633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
74762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
74862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param newParent the new parent
74924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet     * @param movedView the view to move
75033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the new location in the new parent
75133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
75233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
753ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
754ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
75533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
75633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
75724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
75824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
7591392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        try {
76062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            // check if there is a transition on the previousParent.
76124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
76224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousTransition != null) {
7635562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
7645562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
7655562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
7665562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
7675562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // to handle).
7685562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
7695562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
7705562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // adding the child or the child will appear in its new location before the
7715562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // other children have made room for it.
77262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
77362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
77424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
77524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    private int mChangeDisappearingCount = 0;
77662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
77762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
77862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
77924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
78024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount++;
78124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
78262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
78333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
78462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
78562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
78624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
78724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount--;
78824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
78924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
79024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
79124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                mChangeDisappearingCount == 0) {
79262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            // add it to the parentView in the correct location
79362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            if (params != null) {
79424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index, params);
79562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            } else {
79624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index);
79762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            }
79862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                        }
79962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
80062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                });
80162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
80262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // remove the view from the current parent.
80324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
80462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
80562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
80662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
80733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            } else {
80862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // standard code with no animation. pretty simple.
80924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
81033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
81162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add it to the parentView in the correct location
81262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                if (params != null) {
81324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index, params);
81462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                } else {
81524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index);
81662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                }
81762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
81862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
81962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            }
8201392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        } catch (UnsupportedOperationException e) {
8211392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
822ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
823b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
82433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
82533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
82633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
82733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a child from its current parent.
82833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
82933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
83033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
83133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
83233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
83333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
83433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#removeChild(Object, IAnimationListener)
83533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
836ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
83733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        checkLock();
838b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
8391392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        invalidateRenderingSize();
8401392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
84133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
84233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
84333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
84433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
84533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
84633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
847ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
84833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
84933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return removeView(parent, childView);
85033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
85133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
85233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
85333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
85433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(null);
85533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
85633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
85733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
85833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
859ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
86033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
86133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
862ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = removeView(parent, childView);
86333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
86433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
86533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
86633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
867b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        return render();
868ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
869ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
870ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
87133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a given view from its current parent.
87233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
87333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to remove from its parent
87433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
875ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
876ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
87733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
87833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
879ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
88033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
88133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.removeView(view);
882ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
88333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
88433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
885ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
88633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
88733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
88833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
88933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
890907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     * Returns the log associated with the session.
891907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     * @return the log or null if there are none.
892907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     */
893907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    public LayoutLog getLog() {
894907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        if (mParams != null) {
895907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet            return mParams.getLog();
896907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        }
897907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet
898907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        return null;
899907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    }
900907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet
901907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    /**
902ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Checks that the lock is owned by the current thread and that the current context is the one
903ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * from this scene.
904ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
905ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
906ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
907ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
908ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    private void checkLock() {
909ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
910ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
911ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
912ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
913ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (sCurrentContext != mContext) {
914ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
915ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
916ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
917ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
9183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
9193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Returns the top screen offset. This depends on whether the current theme defines the user
9203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * of the title and status bars.
921089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet     * @param resolver The {@link ResourceResolver}
922089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet     * @param metrics The display metrics
9233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @return the pixel height offset
9243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
9250d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    private int getScreenOffset(RenderResources resolver, DisplayMetrics metrics) {
9263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        int offset = 0;
9273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // get the title bar flag from the current theme.
929089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet        ResourceValue value = resolver.findItemInTheme("windowNoTitle");
9303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // because it may reference something else, we resolve it.
932089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet        value = resolver.resolveResValue(value);
9333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // if there's a value and it's true (default is false)
9353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (value == null || value.getValue() == null ||
9363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
9373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // default size of the window title bar
9383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
9393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get value from the theme.
941089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet            value = resolver.findItemInTheme("windowTitleSize");
9423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // resolve it
944089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet            value = resolver.resolveResValue(value);
9453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (value != null) {
9473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                // get the numerical value, if available
9483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
9493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                if (typedValue != null) {
9503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    // compute the pixel value based on the display metrics
951089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet                    defaultOffset = (int)typedValue.getDimension(metrics);
9523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
9533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
9543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            offset += defaultOffset;
9563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
9573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // get the fullscreen flag from the current theme.
959089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet        value = resolver.findItemInTheme("windowFullscreen");
9603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // because it may reference something else, we resolve it.
962089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet        value = resolver.resolveResValue(value);
9633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (value == null || value.getValue() == null ||
9653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
9663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // default value
9683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
9693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
970089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet            // get the real value
9710d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            value = resolver.getFrameworkResource(RenderResources.RES_DIMEN, "status_bar_height");
9723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (value != null) {
9733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
9743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                if (typedValue != null) {
9753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    // compute the pixel value based on the display metrics
976089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet                    defaultOffset = (int)typedValue.getDimension(metrics);
9773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
9783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
9793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // add the computed offset.
9813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            offset += defaultOffset;
9823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
9833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return offset;
9853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
9863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
9873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
9883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Post process on a view hierachy that was just inflated.
9893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
9903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
9913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
9923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root view to process.
9933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param projectCallback callback to the project.
9943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
9953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private void postInflateProcess(View view, IProjectCallback projectCallback)
9963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
9973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof TabHost) {
9983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            setupTabHost((TabHost)view, projectCallback);
9993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } else if (view instanceof ViewGroup) {
10003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            ViewGroup group = (ViewGroup)view;
10013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            final int count = group.getChildCount();
10023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            for (int c = 0 ; c < count ; c++) {
10033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                View child = group.getChildAt(c);
10043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                postInflateProcess(child, projectCallback);
10053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
10063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
10083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
10103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Sets up a {@link TabHost} object.
10113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param tabHost the TabHost to setup.
10123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param projectCallback The project callback object to access the project R class.
10133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @throws PostInflateException
10143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
10153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
10163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
10173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
10183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
10193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
10213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
10223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
10233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if ((v instanceof TabWidget) == false) {
10263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
10273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
10283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
10293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
10323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
10343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
10353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
10363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
10373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if ((v instanceof FrameLayout) == false) {
10403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
10413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
10423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
10433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
10463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // now process the content of the framelayout and dynamically create tabs for it.
10483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        final int count = content.getChildCount();
10493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (count == 0) {
10513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
10523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "The FrameLayout for the TabHost has no content. Rendering failed.\n");
10533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
10563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // and FrameLayout.
10573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        tabHost.setup();
10583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // for each child of the framelayout, add a new TabSpec
10603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        for (int i = 0 ; i < count ; i++) {
10613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            View child = content.getChildAt(i);
10623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            String tabSpec = String.format("tab_spec%d", i+1);
10633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            int id = child.getId();
10643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            String[] resource = projectCallback.resolveResourceValue(id);
10653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            String name;
10663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (resource != null) {
10673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                name = resource[0]; // 0 is resource name, 1 is resource type.
10683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            } else {
10693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                name = String.format("Tab %d", i+1); // default name if id is unresolved.
10703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
10713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
10723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
10743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
10773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Visits a View and its children and generate a {@link ViewInfo} containing the
10783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * bounds of all the views.
10793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root View
10803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param context the context.
10813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
10823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private ViewInfo visit(View view, BridgeContext context) {
10833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view == null) {
10843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            return null;
10853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        ViewInfo result = new ViewInfo(view.getClass().getName(),
10883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                context.getViewKey(view),
10892d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet                view.getLeft(), view.getTop(), view.getRight(), view.getBottom(),
10902d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet                view, view.getLayoutParams());
10913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof ViewGroup) {
10933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            ViewGroup group = ((ViewGroup) view);
10943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            List<ViewInfo> children = new ArrayList<ViewInfo>();
10953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            for (int i = 0; i < group.getChildCount(); i++) {
10963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                children.add(visit(group.getChildAt(i), context));
10973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
10983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            result.setChildren(children);
10993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return result;
11023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11041392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private void invalidateRenderingSize() {
11051392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
11061392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    }
11071392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
11083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    public BufferedImage getImage() {
11093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return mImage;
11103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    public ViewInfo getViewInfo() {
11133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return mViewInfo;
11143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11152d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet
1116ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
11172d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet        return mContext.getDefaultPropMap(viewObject);
11182d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet    }
1119b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1120ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public void setScene(RenderSession session) {
1121ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mScene = session;
1122b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
1123b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1124ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSession getSession() {
1125b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        return mScene;
1126b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
11270d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
11280d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    // --- FrameworkResourceIdProvider methods
11290d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
11300d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    @Override
11310d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    public Integer getId(String resType, String resName) {
11320d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        return Bridge.getResourceValue(resType, resName);
11330d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
11343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet}
1135