RenderSessionImpl.java revision 16584225125acba18b74920b902c798dfead0328
1c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/*
2c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
3c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
4c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
5c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * you may not use this file except in compliance with the License.
6c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * You may obtain a copy of the License at
7c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
8c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
9c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
10c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * Unless required by applicable law or agreed to in writing, software
11c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
12c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * See the License for the specific language governing permissions and
14c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * limitations under the License.
15c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
16c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
17c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetpackage com.android.layoutlib.bridge.impl;
18c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
2019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
2119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
2219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
2319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
2419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
2519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
2619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
2719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet
2819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener;
2919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ILayoutPullParser;
3019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.IProjectCallback;
31d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohetimport com.android.ide.common.rendering.api.LayoutLog;
3219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Params;
3370552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
3419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
3519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue;
3619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
3719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.StyleResourceValue;
3819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo;
3919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Params.RenderingMode;
4070552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
4119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
42c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.internal.util.XmlUtils;
432eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
44c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
45c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeInflater;
4601811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
47c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindow;
48c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindowSession;
49c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
5016584225125acba18b74920b902c798dfead0328Xavier Ducrohetimport com.android.resources.Density;
5116584225125acba18b74920b902c798dfead0328Xavier Ducrohetimport com.android.resources.ScreenSize;
52c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
53e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.Animator;
542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.animation.AnimatorInflater;
55e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.LayoutTransition;
562b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
57c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.app.Fragment_Delegate;
58c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap;
59c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
60c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Canvas;
61c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.drawable.Drawable;
62c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.os.Handler;
63c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.util.DisplayMetrics;
64c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.util.TypedValue;
65c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View;
66c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.ViewGroup;
67c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.AttachInfo;
68c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.MeasureSpec;
6901811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport android.view.ViewGroup.LayoutParams;
70c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.FrameLayout;
71796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.LinearLayout;
7231fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohetimport android.widget.QuickContactBadge;
73c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabHost;
74c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabWidget;
75796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.TabHost.TabSpec;
76c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
775a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohetimport java.awt.AlphaComposite;
78c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Color;
79c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Graphics2D;
80c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.image.BufferedImage;
81c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.ArrayList;
82c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.List;
83c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.Map;
842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport java.util.concurrent.TimeUnit;
852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport java.util.concurrent.locks.ReentrantLock;
86c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
87c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/**
8819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * Class implementing the render session.
89c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
9019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
9119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
92c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * be done on the layout.
93c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
94c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
9570552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohetpublic class RenderSessionImpl extends FrameworkResourceIdProvider {
96c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
97c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
98c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
99c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
1012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * The current context being rendered. This is set through {@link #acquire(long)} and
1022eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #init(long)}, and unset in {@link #release()}.
1032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
1042eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    private static BridgeContext sCurrentContext = null;
1052eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
10619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private final Params mParams;
107c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
108c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // scene state
10919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private RenderSession mScene;
110c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeContext mContext;
111c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
112c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeInflater mInflater;
113ffb42f6c5043de226f02318a1311669d35a90711Xavier Ducrohet    private ResourceValue mWindowBackground;
114c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private FrameLayout mViewRoot;
1159eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private Canvas mCanvas;
1169eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1179eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenHeight = -1;
11816584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private boolean mIsAlphaChannelImage = true;
11916584225125acba18b74920b902c798dfead0328Xavier Ducrohet
12016584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private int mStatusBarSize;
12116584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private int mTopBarSize;
12216584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private int mSystemBarSize;
12316584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private int mTopOffset;
12416584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private int mTotalBarSize;
12516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
126c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
127c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // information being returned through the API
128c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BufferedImage mImage;
1297d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    private List<ViewInfo> mViewInfoList;
130c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
131c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final class PostInflateException extends Exception {
132c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        private static final long serialVersionUID = 1L;
133c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
134c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        public PostInflateException(String message) {
135c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            super(message);
136c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
137c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
14219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a
14319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     *
145c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
14719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public RenderSessionImpl(Params params) {
148c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // copy the params.
14919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mParams = new Params(params);
1502eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
1512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
1532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
1542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * inflater, and parser.
1552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
1572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return whether the scene was prepared
1592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #acquire(long)
1612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #release()
1622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
16319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result init(long timeout) {
1642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
1652eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // the result.
16619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = acquireLock(timeout);
1672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (result != null) {
1682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            return result;
1692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
170c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
171c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // setup the display Metrics.
172c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        DisplayMetrics metrics = new DisplayMetrics();
173c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        metrics.densityDpi = mParams.getDensity();
174c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT;
175c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        metrics.scaledDensity = metrics.density;
176c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        metrics.widthPixels = mParams.getScreenWidth();
177c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        metrics.heightPixels = mParams.getScreenHeight();
178c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        metrics.xdpi = mParams.getXdpi();
179c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        metrics.ydpi = mParams.getYdpi();
180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
18170552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        RenderResources resources = mParams.getResources();
182c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
183c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // build the context
18470552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
1859d0577ec0c285c055da4c910dcb597fdae5bc5e5Xavier Ducrohet                mParams.getProjectCallback(), mParams.getTargetSdkVersion());
186c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
18716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // use default of true in case it's not found to use alpha by default
18816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        mIsAlphaChannelImage  = getBooleanThemeValue(resources,
18916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                "windowIsFloating", true /*defaultValue*/);
19016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
1912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
19270552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        setUp();
193c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
19416584225125acba18b74920b902c798dfead0328Xavier Ducrohet        findBackground(resources);
19516584225125acba18b74920b902c798dfead0328Xavier Ducrohet        findStatusBar(resources, metrics);
19616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        findTopBar(resources, metrics);
19716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        findSystemBar(resources, metrics);
198c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
19916584225125acba18b74920b902c798dfead0328Xavier Ducrohet        mTopOffset = mStatusBarSize + mTopBarSize;
20016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        mTotalBarSize = mTopOffset + mSystemBarSize;
201c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
202c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // build the inflater and parser.
203c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        mInflater = new BridgeInflater(mContext, mParams.getProjectCallback());
204c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        mContext.setBridgeInflater(mInflater);
205c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        mInflater.setFactory2(mContext);
206c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
207c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
208c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                mContext, false /* platformResourceFlag */);
2092eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
21019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        return SUCCESS.createResult();
211c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
212c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
213c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
2142eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Prepares the scene for action.
2152eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * <p>
2162eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * This call is blocking if another rendering/inflating is currently happening, and will return
2172eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * whether the preparation worked.
2182eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2192eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * The preparation can fail if another rendering took too long and the timeout was elapsed.
2202eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2212eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * More than one call to this from the same thread will have no effect and will return
22219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * {@link Result#SUCCESS}.
2232eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2242eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * After scene actions have taken place, only one call to {@link #release()} must be
2252eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * done.
2262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2272eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
2282eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2292eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return whether the scene was prepared
2302eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2312eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #release()
2322eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2332eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if {@link #init(long)} was never called.
2342eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
23519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result acquire(long timeout) {
2362eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (mContext == null) {
2372eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            throw new IllegalStateException("After scene creation, #init() must be called");
2382eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
2392eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
2402eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
2412eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // the result.
24219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = acquireLock(timeout);
2432eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (result != null) {
2442eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            return result;
2452eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
246c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
24770552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        setUp();
2482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
249168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet        return SUCCESS.createResult();
250c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
251c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
252c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
2532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Acquire the lock so that the scene can be acted upon.
254c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
2552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * This returns null if the lock was just acquired, otherwise it returns
25619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
25719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * instance (see {@link Result#getStatus()}) if an error occurred.
2582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
2602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return null if the lock was just acquire or another result depending on the state.
2612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
2632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene.
264c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
26519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result acquireLock(long timeout) {
2662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
2672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
2682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            try {
2692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
2702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
2712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (acquired == false) {
272168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet                    return ERROR_TIMEOUT.createResult();
2732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
2742eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            } catch (InterruptedException e) {
275168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet                return ERROR_LOCK_INTERRUPTED.createResult();
2762eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
2772eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } else {
2782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            // This thread holds the lock already. Checks that this wasn't for a different context.
2792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            // If this is called by init, mContext will be null and so should sCurrentContext
2802eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            // anyway
2812eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (mContext != sCurrentContext) {
2822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                throw new IllegalStateException("Acquiring different scenes from same thread without releases");
2832eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
284168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet            return SUCCESS.createResult();
2852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
286c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
2872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        return null;
2882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
2892eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
2902eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
2912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Cleans up the scene after an action.
2922eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
2932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    public void release() {
2942eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
2952eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
2962eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // with the use of finally blocks, it is possible to find ourself calling this
2972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // without a successful call to prepareScene. This test makes sure that unlock() will
2982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // not throw IllegalMonitorStateException.
2992eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (lock.isHeldByCurrentThread()) {
30070552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet            tearDown();
3012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            lock.unlock();
3022eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
303c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
304c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
305c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
30670552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     * Sets up the session for rendering.
30770552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     * <p/>
30870552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     * The counterpart is {@link #tearDown()}.
30970552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     */
31070552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    private void setUp() {
31170552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        // make sure the Resources object references the context (and other objects) for this
31270552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        // scene
31370552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        mContext.initResources();
31470552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        sCurrentContext = mContext;
31570552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet
31670552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        LayoutLog currentLog = mParams.getLog();
31770552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        Bridge.setLog(currentLog);
31870552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
31970552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        mContext.getRenderResources().setLogger(currentLog);
32070552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    }
32170552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet
32270552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    /**
32370552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     * Tear down the session after rendering.
32470552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     * <p/>
32570552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     * The counterpart is {@link #setUp()}.
32670552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet     */
32770552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    private void tearDown() {
32870552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        // Make sure to remove static references, otherwise we could not unload the lib
32970552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        mContext.disposeResources();
33070552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        sCurrentContext = null;
33170552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet
33270552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        Bridge.setLog(null);
33370552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(null);
33470552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        mContext.getRenderResources().setLogger(null);
33570552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet
33670552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    }
33770552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet
33870552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    /**
339c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Inflates the layout.
340c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
3412eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
3422eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
3432eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
3442eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
345c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
34619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result inflate() {
3472eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
3482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
349c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
350c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
351c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            mViewRoot = new FrameLayout(mContext);
352c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
353c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
354c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // it can instantiate the custom Fragment.
355c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Fragment_Delegate.setProjectCallback(mParams.getProjectCallback());
356c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
357c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            View view = mInflater.inflate(mBlockParser, mViewRoot);
358c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
359c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
360c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            postInflateProcess(view, mParams.getProjectCallback());
361c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
362c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Fragment_Delegate.setProjectCallback(null);
363c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
364c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // set the AttachInfo on the root view.
365c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
366c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    new Handler(), null);
367c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            info.mHasWindowFocus = true;
368c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            info.mWindowVisibility = View.VISIBLE;
369c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            info.mInTouchMode = false; // this is so that we can display selections.
37046a329244db12b6f7afc3c9a6409d420241a1058Xavier Ducrohet            info.mHardwareAccelerated = false;
371c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            mViewRoot.dispatchAttachedToWindow(info, 0);
372c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
373c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the background drawable
374c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mWindowBackground != null) {
375c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                Drawable d = ResourceHelper.getDrawable(mWindowBackground,
376c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                        mContext, true /* isFramework */);
377c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                mViewRoot.setBackgroundDrawable(d);
378c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
379c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
38019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
381c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (PostInflateException e) {
38219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
383c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
384c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
385c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
386c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
387c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
388c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
389c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
39019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
391c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
392c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
393c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
394c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
395c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Renders the scene.
396c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
3972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
3982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
3995a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
4005a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
4015a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      animations.)
4025a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *
4032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
4042eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
4059eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet     *
4069eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet     * @see SceneParams#getRenderingMode()
407e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @see LayoutScene#render(long)
408c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
4095a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet    public Result render(boolean freshRender) {
4102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
4112eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
412c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
413c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mViewRoot == null) {
41419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
415c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
416c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // measure the views
417c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            int w_spec, h_spec;
418c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
419fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet            RenderingMode renderingMode = mParams.getRenderingMode();
420fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet
4219eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // only do the screen measure when needed.
4229eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            boolean newRenderSize = false;
4239eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
4249eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                newRenderSize = true;
4259eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                mMeasuredScreenWidth = mParams.getScreenWidth();
42616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                mMeasuredScreenHeight = mParams.getScreenHeight() - mTotalBarSize;
4279eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
4289eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
4299eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    // measure the full size needed by the layout.
4309eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth,
4319eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                            renderingMode.isHorizExpand() ?
4329eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4339eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    : MeasureSpec.EXACTLY);
43416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight,
4359eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                            renderingMode.isVertExpand() ?
4369eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4379eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    : MeasureSpec.EXACTLY);
4389eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    mViewRoot.measure(w_spec, h_spec);
4399eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
4409eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
4419eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
4429eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        if (neededWidth > mMeasuredScreenWidth) {
4439eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                            mMeasuredScreenWidth = neededWidth;
4449eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
445fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
446c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4479eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isVertExpand()) {
4489eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
44916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        if (neededHeight > mMeasuredScreenHeight) {
45016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenHeight = neededHeight;
4519eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
452fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
453c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
454c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
455c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
456c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // remeasure with the size we need
457c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // This must always be done before the call to layout
4589eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, MeasureSpec.EXACTLY);
45916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight,
460c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    MeasureSpec.EXACTLY);
461c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            mViewRoot.measure(w_spec, h_spec);
462c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
463c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // now do the layout.
46416584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
465c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
466c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // draw the views
467c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // create the BufferedImage into which the layout will be rendered.
4685a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            boolean newImage = false;
4699eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            if (newRenderSize || mCanvas == null) {
4709eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                if (mParams.getImageFactory() != null) {
47116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    mImage = mParams.getImageFactory().getImage(
47216584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenWidth,
47316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize);
4749eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                } else {
47516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    mImage = new BufferedImage(
47616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenWidth,
47716584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize,
47816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            BufferedImage.TYPE_INT_ARGB);
4795a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    newImage = true;
4809eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
481c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
48219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                if (mParams.isBgColorOverridden()) {
4835a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    // since we override the content, it's the same as if it was a new image.
4845a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    newImage = true;
4859eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
48619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    gc.setColor(new Color(mParams.getOverrideBgColor(), true));
4875a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
48816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth,
48916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize);
4909eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    gc.dispose();
4919eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
492c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4939eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                // create an Android bitmap around the BufferedImage
4949eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
4959eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        true /*isMutable*/,
49616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        Density.getEnum(mParams.getDensity()));
497c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4989eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                // create a Canvas around the Android bitmap
4999eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                mCanvas = new Canvas(bitmap);
5009eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                mCanvas.setDensity(mParams.getDensity());
50116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                mCanvas.translate(0, mTopOffset);
5029eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            }
503c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
5045a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            if (freshRender && newImage == false) {
5055a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                Graphics2D gc = mImage.createGraphics();
5065a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                gc.setComposite(AlphaComposite.Src);
50716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
50816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                if (mStatusBarSize > 0) {
50916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    gc.setColor(new Color(0xFF3C3C3C, true));
51016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth, mStatusBarSize);
51116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                }
51216584225125acba18b74920b902c798dfead0328Xavier Ducrohet
51316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                if (mTopBarSize > 0) {
51416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    gc.setColor(new Color(0xFF7F7F7F, true));
51516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    gc.fillRect(0, mStatusBarSize, mMeasuredScreenWidth, mTopOffset);
51616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                }
51716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
51816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // erase the rest
51916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                gc.setColor(new Color(0x00000000, true));
52016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                gc.fillRect(0, mTopOffset,
52116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        mMeasuredScreenWidth, mMeasuredScreenHeight + mTopOffset);
52216584225125acba18b74920b902c798dfead0328Xavier Ducrohet
52316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                if (mSystemBarSize > 0) {
52416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    gc.setColor(new Color(0xFF3C3C3C, true));
52516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    gc.fillRect(0, mMeasuredScreenHeight + mTopOffset,
52616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenWidth, mMeasuredScreenHeight + mTotalBarSize);
52716584225125acba18b74920b902c798dfead0328Xavier Ducrohet                }
52816584225125acba18b74920b902c798dfead0328Xavier Ducrohet
52916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // done
5305a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                gc.dispose();
5315a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            }
5325a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet
5339eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            mViewRoot.draw(mCanvas);
5349eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
53516584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mViewInfoList = visitAllChildren((ViewGroup)mViewRoot, mContext, mTopOffset);
536c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
537c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // success!
53819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
539c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
540c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
541c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
542c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
543c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
544c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
545c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
54619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
547c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
548c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
549c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
550c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
5512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Animate an object
5522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * <p>
5532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
5542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
5552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
5562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
557e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
558e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @see LayoutScene#animate(Object, String, boolean, IAnimationListener)
5592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
56019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
5612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
5622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
5632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
5642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // find the animation file.
565ffb42f6c5043de226f02318a1311669d35a90711Xavier Ducrohet        ResourceValue animationResource = null;
5662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        int animationId = 0;
5672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (isFrameworkAnimation) {
56870552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet            animationResource = mContext.getRenderResources().getFrameworkResource(
56970552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet                    RenderResources.RES_ANIMATOR, animationName);
5702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
57170552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet                animationId = Bridge.getResourceValue(RenderResources.RES_ANIMATOR,
572eb87b3bb53a8a9e9a246b4b70ea40172e2229c85Xavier Ducrohet                        animationName);
5732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5742eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } else {
57570552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet            animationResource = mContext.getRenderResources().getProjectResource(
57670552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet                    RenderResources.RES_ANIMATOR, animationName);
5772eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
578eb87b3bb53a8a9e9a246b4b70ea40172e2229c85Xavier Ducrohet                animationId = mContext.getProjectCallback().getResourceValue(
57970552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet                        RenderResources.RES_ANIMATOR, animationName);
5802eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5812eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
5832eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (animationResource != null) {
5842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            try {
585e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(mContext, animationId);
5862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (anim != null) {
5872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    anim.setTarget(targetObject);
5882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
589e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
5902eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
59119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    return SUCCESS.createResult();
5922eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
5932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            } catch (Exception e) {
594c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                // get the real cause of the exception.
595c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                Throwable t = e;
596c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                while (t.getCause() != null) {
597c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                    t = t.getCause();
598c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                }
599c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
60019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
6012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
6022eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
6032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
60419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
605c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
606c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
607e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
608e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Insert a new child into an existing parent.
609e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
610e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
611e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
612e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
613e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
614e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
61519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @see LayoutScene#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
616e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
61719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
618e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final int index, IAnimationListener listener) {
619c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
620c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
621c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // create a block parser for the XML
622c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
623c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                false /* platformResourceFlag */);
624c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
625c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
626c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
627c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // be created correctly.
628e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
629c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
630e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
631e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
632e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
633e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
634e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
635e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
63619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
637e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
638e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return addView(parentView, child, index);
639e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
640e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
641e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
642e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
643e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(null);
644e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
645e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
646e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
647e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
64819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(child);
6499eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        }
6509eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
651e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        // add it to the parentView in the correct location
65219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = addView(parentView, child, index);
653e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (result.isSuccess() == false) {
654e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
655e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
656c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
6575a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
658c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        if (result.isSuccess()) {
659e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(child);
660c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        }
661c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet
662c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        return result;
663c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
664c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
665e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
666e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Adds a given view to a given parent at a given index.
667e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
668e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param parent the parent to receive the view
669e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to add to the parent
670e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the index where to do the add.
671e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
67219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
67319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
674e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
675e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
67619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
677e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
678e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.addView(view, index);
67919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
680e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
681e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
68219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
683e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
684e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
685e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
686e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
687e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a view to a new parent at a given location
688e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
689e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
690e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
691e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
692e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
693e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
694e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener)
695e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
6962b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
697479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
698c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
699c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
700e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
701e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
70201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        LayoutParams layoutParams = null;
703e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (layoutParamsMap != null) {
704e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
7052b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
706e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
707e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
7089eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
7092b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        // get the current parent of the view that needs to be moved.
7102b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
7112b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
712e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
713e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final LayoutParams params = layoutParams;
71401811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
715479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
716479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
717479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousParent != newParentView) {
718479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new Thread("not animated moveChild") {
719479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
720479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void run() {
721479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
722479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                params);
723479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (result.isSuccess() == false) {
724479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
725479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
726479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
727479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // ready to do the work, acquire the scene.
728479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        result = acquire(250);
729479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (result.isSuccess() == false) {
730479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
731479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            return;
732479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
733479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
734479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        try {
7355a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                            result = render(false /*freshRender*/);
736479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            if (result.isSuccess()) {
737479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
738479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            }
739479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        } finally {
740479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            release();
741479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
742479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
743479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        listener.done(result);
7442b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
745479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
746479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            } else {
747479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
7482b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
749479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
750479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public Result preAnimation() {
751479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // set up the transition for the parent.
752479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
753479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(transition);
7547550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet
755479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
756479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // animation playing just before).
757479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
758479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // on the LayoutTransition.
759479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
760479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
761479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
76201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
763479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
764479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
765479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
766479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
767479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
768479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
769479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
770479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
771479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
772479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
773479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
774479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
775479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void postAnimation() {
776479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(null);
777479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        newParentView.setLayoutTransition(null);
778479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
779479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
780479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            }
781e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
782e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
78319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
784c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
785c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7862b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
787e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (result.isSuccess() == false) {
788e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
789e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
790c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7915a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
79201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
793e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
79401811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        }
79501811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
79601811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        return result;
797c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
798c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
799e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
800e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
801e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * an optional new {@link LayoutParams} instance
802e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
8032b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
8042b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param newParent the new parent
805479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet     * @param movedView the view to move
806e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the new location in the new parent
807e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
808e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
80919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
81019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
811e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
812e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
813479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
814479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
8159eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        try {
8162b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            // check if there is a transition on the previousParent.
817479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
818479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousTransition != null) {
8197550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
8207550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
8217550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
8227550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
8237550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // to handle).
8247550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
8257550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
8267550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // adding the child or the child will appear in its new location before the
8277550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // other children have made room for it.
8282b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8292b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
830479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
831479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    private int mChangeDisappearingCount = 0;
8322b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8332b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
8342b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
835479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
836479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount++;
837479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
8382b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
839e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8402b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
8412b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
842479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
843479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount--;
844479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
845479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
846479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
847479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                mChangeDisappearingCount == 0) {
8482b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            // add it to the parentView in the correct location
8492b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            if (params != null) {
850479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index, params);
8512b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            } else {
852479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index);
8532b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            }
8542b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                        }
8552b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
8562b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                });
8572b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8582b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // remove the view from the current parent.
859479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
8602b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8612b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
8622b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
863e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            } else {
8642b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // standard code with no animation. pretty simple.
865479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
866e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8672b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add it to the parentView in the correct location
8682b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                if (params != null) {
869479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index, params);
8702b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                } else {
871479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index);
8722b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                }
8732b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8742b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
8752b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            }
8769eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        } catch (UnsupportedOperationException e) {
8779eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
87819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
879c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
880e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
881e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
882e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
883e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a child from its current parent.
884e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
885e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
886e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
887e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
888e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
889e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
890e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @see LayoutScene#removeChild(Object, IAnimationListener)
891e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
89219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
893e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        checkLock();
894c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
8959eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        invalidateRenderingSize();
8969eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
897e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
898e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
899e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
900e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
901e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
902e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
90319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
904e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
905e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return removeView(parent, childView);
906e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
907e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
908e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
909e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
910e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(null);
911e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
912e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
913e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
914e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
91519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
916e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
917e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
91819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = removeView(parent, childView);
919e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (result.isSuccess() == false) {
920e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
921e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
922e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
9235a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        return render(false /*freshRender*/);
9242eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
9252eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
9262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
927e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a given view from its current parent.
928e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
929e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to remove from its parent
930e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
93119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
93219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
933e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
934e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
93519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
936e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
937e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.removeView(view);
93819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
939e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
940e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
94119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
942e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
943e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
944e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
945e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
946d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet     * Returns the log associated with the session.
947d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet     * @return the log or null if there are none.
948d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet     */
949d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet    public LayoutLog getLog() {
950d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet        if (mParams != null) {
951d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet            return mParams.getLog();
952d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet        }
953d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet
954d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet        return null;
955d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet    }
956d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet
957d7cc1244d7f0901688545c8535fa531fbb68669aXavier Ducrohet    /**
9582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Checks that the lock is owned by the current thread and that the current context is the one
9592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * from this scene.
9602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
9612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
9622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
9632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
9642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    private void checkLock() {
9652eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
9662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
9672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
9682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
9692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (sCurrentContext != mContext) {
9702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
9712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
9722eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
9732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
97416584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findBackground(RenderResources resources) {
97516584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (mParams.isBgColorOverridden() == false) {
97616584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mWindowBackground = resources.findItemInTheme("windowBackground");
97716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            if (mWindowBackground != null) {
97816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                mWindowBackground = resources.resolveResValue(mWindowBackground);
97916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            }
98016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
98116584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
982c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
98316584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private boolean isTabletUi() {
98416584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return mParams.getConfigScreenSize() == ScreenSize.XLARGE;
98516584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
986c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
98716584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private boolean isHCApp() {
98816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        RenderResources resources = mContext.getRenderResources();
98916584225125acba18b74920b902c798dfead0328Xavier Ducrohet
99016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // the app must say it targets 11+ and the theme name must extend Theme.Holo or
99116584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // Theme.Holo.Light (which does not extend Theme.Holo, but Theme.Light)
99216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (mParams.getTargetSdkVersion() < 11) {
99316584225125acba18b74920b902c798dfead0328Xavier Ducrohet            return false;
99416584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
99516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
99616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        StyleResourceValue currentTheme = resources.getCurrentTheme();
99716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        StyleResourceValue holoTheme = resources.getTheme("Theme.Holo", true /*frameworkTheme*/);
99816584225125acba18b74920b902c798dfead0328Xavier Ducrohet
99916584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (currentTheme == holoTheme ||
100016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                resources.themeIsParentOf(holoTheme, currentTheme)) {
100116584225125acba18b74920b902c798dfead0328Xavier Ducrohet            return true;
100216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
100316584225125acba18b74920b902c798dfead0328Xavier Ducrohet
100416584225125acba18b74920b902c798dfead0328Xavier Ducrohet        StyleResourceValue holoLightTheme = resources.getTheme("Theme.Holo.Light",
100516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                true /*frameworkTheme*/);
100616584225125acba18b74920b902c798dfead0328Xavier Ducrohet
100716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (currentTheme == holoLightTheme ||
100816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                resources.themeIsParentOf(holoLightTheme, currentTheme)) {
100916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            return true;
101016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
101116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
101216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return false;
101316584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
101416584225125acba18b74920b902c798dfead0328Xavier Ducrohet
101516584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
101616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (isTabletUi() == false) {
101716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            boolean windowFullscreen = getBooleanThemeValue(resources,
101816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    "windowFullscreen", false /*defaultValue*/);
101916584225125acba18b74920b902c798dfead0328Xavier Ducrohet
102016584225125acba18b74920b902c798dfead0328Xavier Ducrohet            if (windowFullscreen == false) {
102116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // default value
102216584225125acba18b74920b902c798dfead0328Xavier Ducrohet                mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
102316584225125acba18b74920b902c798dfead0328Xavier Ducrohet
102416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // get the real value
102516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                ResourceValue value = resources.getFrameworkResource(RenderResources.RES_DIMEN,
102616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        "status_bar_height");
102716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
102816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                if (value != null) {
102916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
103016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    if (typedValue != null) {
103116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        // compute the pixel value based on the display metrics
103216584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        mStatusBarSize = (int)typedValue.getDimension(metrics);
103316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    }
103416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                }
103516584225125acba18b74920b902c798dfead0328Xavier Ducrohet            }
103616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
103716584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
103816584225125acba18b74920b902c798dfead0328Xavier Ducrohet
103916584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findTopBar(RenderResources resources, DisplayMetrics metrics) {
104016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        boolean windowIsFloating = getBooleanThemeValue(resources,
104116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                "windowIsFloating", true /*defaultValue*/);
104216584225125acba18b74920b902c798dfead0328Xavier Ducrohet
104316584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (windowIsFloating == false) {
104416584225125acba18b74920b902c798dfead0328Xavier Ducrohet            if (isHCApp()) {
104516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                findActionBar(resources, metrics);
104616584225125acba18b74920b902c798dfead0328Xavier Ducrohet            } else {
104716584225125acba18b74920b902c798dfead0328Xavier Ducrohet                findTitleBar(resources, metrics);
104816584225125acba18b74920b902c798dfead0328Xavier Ducrohet            }
104916584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
105016584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
105116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
105216584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
105316584225125acba18b74920b902c798dfead0328Xavier Ducrohet        boolean windowActionBar = getBooleanThemeValue(resources,
105416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                "windowActionBar", true /*defaultValue*/);
105516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
105616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // if there's a value and it's false (default is true)
105716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (windowActionBar) {
1058c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1059c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // default size of the window title bar
106016584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
1061c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1062c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get value from the theme.
106316584225125acba18b74920b902c798dfead0328Xavier Ducrohet            ResourceValue value = resources.findItemInTheme("actionBarSize");
1064c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1065c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // resolve it
106616584225125acba18b74920b902c798dfead0328Xavier Ducrohet            value = resources.resolveResValue(value);
1067c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1068c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (value != null) {
1069c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                // get the numerical value, if available
1070c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
1071c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                if (typedValue != null) {
1072c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    // compute the pixel value based on the display metrics
107316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    mTopBarSize = (int)typedValue.getDimension(metrics);
1074c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
1075c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1076c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
107716584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
1078c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
107916584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findTitleBar(RenderResources resources, DisplayMetrics metrics) {
108016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        boolean windowNoTitle = getBooleanThemeValue(resources,
108116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                "windowNoTitle", false /*defaultValue*/);
1082c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
108316584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (windowNoTitle == false) {
108416584225125acba18b74920b902c798dfead0328Xavier Ducrohet
108516584225125acba18b74920b902c798dfead0328Xavier Ducrohet            // default size of the window title bar
108616584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
108716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
108816584225125acba18b74920b902c798dfead0328Xavier Ducrohet            // get value from the theme.
108916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            ResourceValue value = resources.findItemInTheme("windowTitleSize");
109016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
109116584225125acba18b74920b902c798dfead0328Xavier Ducrohet            // resolve it
109216584225125acba18b74920b902c798dfead0328Xavier Ducrohet            value = resources.resolveResValue(value);
1093c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
109416584225125acba18b74920b902c798dfead0328Xavier Ducrohet            if (value != null) {
109516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // get the numerical value, if available
109616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
109716584225125acba18b74920b902c798dfead0328Xavier Ducrohet                if (typedValue != null) {
109816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    // compute the pixel value based on the display metrics
109916584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    mTopBarSize = (int)typedValue.getDimension(metrics);
110016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                }
110116584225125acba18b74920b902c798dfead0328Xavier Ducrohet            }
110216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
110316584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
110416584225125acba18b74920b902c798dfead0328Xavier Ducrohet
110516584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findSystemBar(RenderResources resources, DisplayMetrics metrics) {
110616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (isTabletUi() && getBooleanThemeValue(
110716584225125acba18b74920b902c798dfead0328Xavier Ducrohet                resources, "windowIsFloating", true /*defaultValue*/) == false) {
1108c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1109c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // default value
111016584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mSystemBarSize = 56; // ??
1111c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1112d1d6fafc7fc63543b10552dadf202dd6fa40fe6bXavier Ducrohet            // get the real value
111316584225125acba18b74920b902c798dfead0328Xavier Ducrohet            ResourceValue value = resources.getFrameworkResource(RenderResources.RES_DIMEN,
111416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    "status_bar_height");
111516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
1116c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (value != null) {
1117c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
1118c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                if (typedValue != null) {
1119c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    // compute the pixel value based on the display metrics
112016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    mSystemBarSize = (int)typedValue.getDimension(metrics);
1121c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
1122c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
112316584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
112416584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
112516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
112616584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private boolean getBooleanThemeValue(RenderResources resources,
112716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            String name, boolean defaultValue) {
112816584225125acba18b74920b902c798dfead0328Xavier Ducrohet
112916584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // get the title bar flag from the current theme.
113016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        ResourceValue value = resources.findItemInTheme(name);
113116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
113216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // because it may reference something else, we resolve it.
113316584225125acba18b74920b902c798dfead0328Xavier Ducrohet        value = resources.resolveResValue(value);
1134c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
113516584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // if there's no value, return the default.
113616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (value == null || value.getValue() == null) {
113716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            return defaultValue;
1138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
114016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
1141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1142c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1143c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
1144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Post process on a view hierachy that was just inflated.
1145c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
1146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
1147c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
1148c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root view to process.
1149c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param projectCallback callback to the project.
1150c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1151c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private void postInflateProcess(View view, IProjectCallback projectCallback)
1152c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1153c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof TabHost) {
1154c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            setupTabHost((TabHost)view, projectCallback);
115531fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
115631fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
115731fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            badge.setImageToDefault();
1158c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } else if (view instanceof ViewGroup) {
1159c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            ViewGroup group = (ViewGroup)view;
1160c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            final int count = group.getChildCount();
1161c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            for (int c = 0 ; c < count ; c++) {
1162c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                View child = group.getChildAt(c);
1163c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                postInflateProcess(child, projectCallback);
1164c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1165c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1166c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1167c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1168c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
1169c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Sets up a {@link TabHost} object.
1170c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param tabHost the TabHost to setup.
1171c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param projectCallback The project callback object to access the project R class.
1172c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @throws PostInflateException
1173c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1174c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
1175c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1176c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
1177c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
1178c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1179c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1181c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
1182c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1183c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1184c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if ((v instanceof TabWidget) == false) {
1185c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1186c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
1187c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
1188c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1189c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1190c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
1191c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1192c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1193c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
1194c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1195c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
1196c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1197c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1198c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if ((v instanceof FrameLayout) == false) {
1199c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1200c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
1201c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
1202c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1203c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1204c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
1205c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1206c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // now process the content of the framelayout and dynamically create tabs for it.
1207c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        final int count = content.getChildCount();
1208c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1209c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
1210c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // and FrameLayout.
1211c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        tabHost.setup();
1212c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1213796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        if (count == 0) {
1214796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // Create a dummy child to get a single tab
1215796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
1216796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
1217796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
1218796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        public View createTabContent(String tag) {
1219796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                            return new LinearLayout(mContext);
1220796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        }
1221796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    });
1222796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            tabHost.addTab(spec);
1223796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            return;
1224796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        } else {
1225796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // for each child of the framelayout, add a new TabSpec
1226796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            for (int i = 0 ; i < count ; i++) {
1227796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                View child = content.getChildAt(i);
1228796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
1229796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                int id = child.getId();
1230796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String[] resource = projectCallback.resolveResourceValue(id);
1231796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String name;
1232796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                if (resource != null) {
1233796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    name = resource[0]; // 0 is resource name, 1 is resource type.
1234796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                } else {
1235796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1236796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                }
1237796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
1238c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1239c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1240c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1241c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1242c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1243c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
1244c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Visits a View and its children and generate a {@link ViewInfo} containing the
1245c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * bounds of all the views.
1246c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root View
1247c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param context the context.
1248c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
124916584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private ViewInfo visit(View view, BridgeContext context, int offset) {
1250c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view == null) {
1251c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            return null;
1252c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1253c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1254c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        ViewInfo result = new ViewInfo(view.getClass().getName(),
1255c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                context.getViewKey(view),
125616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
1257cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet                view, view.getLayoutParams());
1258c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1259c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof ViewGroup) {
1260c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            ViewGroup group = ((ViewGroup) view);
126116584225125acba18b74920b902c798dfead0328Xavier Ducrohet            result.setChildren(visitAllChildren(group, context, 0 /*offset*/));
1262c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1263c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1264c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return result;
1265c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1266c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
126716584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, BridgeContext context,
126816584225125acba18b74920b902c798dfead0328Xavier Ducrohet            int offset) {
12697d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        if (viewGroup == null) {
12707d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet            return null;
12717d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        }
12727d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet
12737d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        List<ViewInfo> children = new ArrayList<ViewInfo>();
12747d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        for (int i = 0; i < viewGroup.getChildCount(); i++) {
127516584225125acba18b74920b902c798dfead0328Xavier Ducrohet            children.add(visit(viewGroup.getChildAt(i), context, offset));
12767d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        }
12777d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return children;
12787d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    }
12797d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet
12807d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet
12819eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private void invalidateRenderingSize() {
12829eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
12839eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    }
12849eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
1285c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    public BufferedImage getImage() {
1286c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return mImage;
1287c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1288c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
128916584225125acba18b74920b902c798dfead0328Xavier Ducrohet    public boolean isAlphaChannelImage() {
129016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return mIsAlphaChannelImage;
129116584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
129216584225125acba18b74920b902c798dfead0328Xavier Ducrohet
12937d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    public List<ViewInfo> getViewInfos() {
12947d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return mViewInfoList;
1295c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1296cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet
129719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
1298cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet        return mContext.getDefaultPropMap(viewObject);
1299cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet    }
1300c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
130119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public void setScene(RenderSession session) {
130219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mScene = session;
1303c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1304c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
130519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public RenderSession getSession() {
1306c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        return mScene;
1307c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
130870552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet
130970552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    // --- FrameworkResourceIdProvider methods
131070552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet
131170552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    @Override
131270552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    public Integer getId(String resType, String resName) {
131370552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet        return Bridge.getResourceValue(resType, resName);
131470552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohet    }
1315c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet}
1316