RenderSessionImpl.java revision b0d34f9c99cbd43e8238c5952b19d032f02dd168
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_NOT_INFLATED;
2219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
2319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
2419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
2519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet
2619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener;
2719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ILayoutPullParser;
2819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.IProjectCallback;
29bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderParams;
3070552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
3119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
3219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue;
3319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
341126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams;
3519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo;
3619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
371126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams.RenderingMode;
38c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.internal.util.XmlUtils;
392eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
40c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
41c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeInflater;
4201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
43c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindow;
44c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindowSession;
45c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
46bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohetimport com.android.layoutlib.bridge.bars.FakeActionBar;
47bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohetimport com.android.layoutlib.bridge.bars.PhoneSystemBar;
48bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohetimport com.android.layoutlib.bridge.bars.TabletSystemBar;
49bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohetimport com.android.layoutlib.bridge.bars.TitleBar;
5035ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohetimport com.android.resources.ResourceType;
5116584225125acba18b74920b902c798dfead0328Xavier Ducrohetimport com.android.resources.ScreenSize;
52b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohetimport com.android.util.Pair;
53c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
54bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohetimport org.xmlpull.v1.XmlPullParserException;
55bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
56e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.Animator;
572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.animation.AnimatorInflater;
58e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.LayoutTransition;
592b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
60c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.app.Fragment_Delegate;
61c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap;
62c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
63c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Canvas;
64c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.drawable.Drawable;
65c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.os.Handler;
66c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.util.DisplayMetrics;
67c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.util.TypedValue;
68c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View;
69c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.ViewGroup;
70c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.AttachInfo;
71c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.MeasureSpec;
7201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport android.view.ViewGroup.LayoutParams;
73c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.FrameLayout;
74796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.LinearLayout;
7531fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohetimport android.widget.QuickContactBadge;
76c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabHost;
77c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabWidget;
78796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.TabHost.TabSpec;
79c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
805a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohetimport java.awt.AlphaComposite;
81c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Color;
82c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Graphics2D;
83c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.image.BufferedImage;
84c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.ArrayList;
85c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.List;
86c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.Map;
87c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
88c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/**
8919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * Class implementing the render session.
90c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
9119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
9219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
93c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * be done on the layout.
94c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
95c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
96b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> {
97c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
98c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
99c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
100c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
101c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // scene state
10219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private RenderSession mScene;
103c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
104c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeInflater mInflater;
105ffb42f6c5043de226f02318a1311669d35a90711Xavier Ducrohet    private ResourceValue mWindowBackground;
106bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private ViewGroup mViewRoot;
107bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private FrameLayout mContentRoot;
1089eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private Canvas mCanvas;
1099eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1109eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenHeight = -1;
111bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private boolean mIsAlphaChannelImage;
112bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private boolean mWindowIsFloating;
11316584225125acba18b74920b902c798dfead0328Xavier Ducrohet
11416584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private int mStatusBarSize;
11516584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private int mSystemBarSize;
116bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private int mTitleBarSize;
117bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private int mActionBarSize;
11816584225125acba18b74920b902c798dfead0328Xavier Ducrohet
119c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
120c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // information being returned through the API
121c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BufferedImage mImage;
1227d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    private List<ViewInfo> mViewInfoList;
123c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
124c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final class PostInflateException extends Exception {
125c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        private static final long serialVersionUID = 1L;
126c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
127c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        public PostInflateException(String message) {
128c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            super(message);
129c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
130c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
131c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
132c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
133c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
134c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
13519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a
13619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
137c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     *
138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1401126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohet    public RenderSessionImpl(SessionParams params) {
141b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        super(new SessionParams(params));
1422eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
1432eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1442eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
1452eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
1462eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * inflater, and parser.
1472eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
1492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1502eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return whether the scene was prepared
1512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #acquire(long)
1532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #release()
1542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
155b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    @Override
15619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result init(long timeout) {
157b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Result result = super.init(timeout);
158b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (result.isSuccess() == false) {
1592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            return result;
1602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
161c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
162b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
163b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
164c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
165b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        RenderResources resources = getParams().getResources();
166b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        DisplayMetrics metrics = getContext().getMetrics();
167c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
16816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // use default of true in case it's not found to use alpha by default
16916584225125acba18b74920b902c798dfead0328Xavier Ducrohet        mIsAlphaChannelImage  = getBooleanThemeValue(resources,
17016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                "windowIsFloating", true /*defaultValue*/);
17116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
172bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        mWindowIsFloating = getBooleanThemeValue(resources, "windowIsFloating",
173bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                true /*defaultValue*/);
1742eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
17516584225125acba18b74920b902c798dfead0328Xavier Ducrohet        findBackground(resources);
17616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        findStatusBar(resources, metrics);
177bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        findActionBar(resources, metrics);
17816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        findSystemBar(resources, metrics);
179c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // build the inflater and parser.
181b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mInflater = new BridgeInflater(context, params.getProjectCallback());
182b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        context.setBridgeInflater(mInflater);
183b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mInflater.setFactory2(context);
1842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
185b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(),
186b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                context, false /* platformResourceFlag */);
1872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
188168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet        return SUCCESS.createResult();
189c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
190c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
191c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
192c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Inflates the layout.
193c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
1942eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
1952eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1962eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
1972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
198c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
19919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result inflate() {
2002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
2012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
202c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
203c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
204b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            SessionParams params = getParams();
205b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            BridgeContext context = getContext();
206b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
207b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            if (mWindowIsFloating || params.isForceNoDecor()) {
208b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                mViewRoot = mContentRoot = new FrameLayout(context);
209bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            } else {
210bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                /*
211bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                 * we're creating the following layout
212bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                 *
213bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   +-------------------------------------------------+
214bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   | System bar (only in phone UI)                   |
215bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   +-------------------------------------------------+
216bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   | Title/Action bar (optional)                     |
217bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   +-------------------------------------------------+
218bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   | Content, vertical extending                     |
219bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   |                                                 |
220bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   +-------------------------------------------------+
221bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   | System bar (only in tablet UI)                  |
222bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                   +-------------------------------------------------+
223bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
224bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                 */
225bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
226b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                LinearLayout topLayout = new LinearLayout(context);
227bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                mViewRoot = topLayout;
228bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                topLayout.setOrientation(LinearLayout.VERTICAL);
229bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
230bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                if (mStatusBarSize > 0) {
231bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    // system bar
232bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    try {
233b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                        PhoneSystemBar systemBar = new PhoneSystemBar(context,
234b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                                params.getDensity());
235bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        systemBar.setLayoutParams(
236bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                new LinearLayout.LayoutParams(
237bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                        LayoutParams.MATCH_PARENT, mStatusBarSize));
238bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        topLayout.addView(systemBar);
239bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    } catch (XmlPullParserException e) {
240bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
241bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    }
242bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                }
243bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
244bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                // if the theme says no title/action bar, then the size will be 0
245bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                if (mActionBarSize > 0) {
246bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    try {
247b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                        FakeActionBar actionBar = new FakeActionBar(context,
248b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                                params.getDensity(),
249b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                                params.getAppLabel(), params.getAppIcon());
250bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        actionBar.setLayoutParams(
251bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                new LinearLayout.LayoutParams(
252bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                        LayoutParams.MATCH_PARENT, mActionBarSize));
253bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        topLayout.addView(actionBar);
254bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    } catch (XmlPullParserException e) {
255bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
256bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    }
257bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                } else if (mTitleBarSize > 0) {
258bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    try {
259b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                        TitleBar titleBar = new TitleBar(context,
260b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                                params.getDensity(), params.getAppLabel());
261bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        titleBar.setLayoutParams(
262bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                new LinearLayout.LayoutParams(
263bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                        LayoutParams.MATCH_PARENT, mTitleBarSize));
264bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        topLayout.addView(titleBar);
265bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    } catch (XmlPullParserException e) {
266bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
267bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    }
268bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                }
269bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
270bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
271bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                // content frame
272b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                mContentRoot = new FrameLayout(context);
273b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
274bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
275b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                layoutParams.weight = 1;
276b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                mContentRoot.setLayoutParams(layoutParams);
277bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                topLayout.addView(mContentRoot);
278bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
279bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                if (mSystemBarSize > 0) {
280bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    // system bar
281bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    try {
282b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                        TabletSystemBar systemBar = new TabletSystemBar(context,
283b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                                params.getDensity());
284bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        systemBar.setLayoutParams(
285bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                new LinearLayout.LayoutParams(
286bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                                        LayoutParams.MATCH_PARENT, mSystemBarSize));
287bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        topLayout.addView(systemBar);
288bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    } catch (XmlPullParserException e) {
289bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
290bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    }
291bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                }
292bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
293bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            }
294bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
295c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
296c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
297c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // it can instantiate the custom Fragment.
298b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            Fragment_Delegate.setProjectCallback(params.getProjectCallback());
299c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
300bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            View view = mInflater.inflate(mBlockParser, mContentRoot);
301c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
302c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Fragment_Delegate.setProjectCallback(null);
303c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
304c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // set the AttachInfo on the root view.
305c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
306c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    new Handler(), null);
307c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            info.mHasWindowFocus = true;
308c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            info.mWindowVisibility = View.VISIBLE;
309c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            info.mInTouchMode = false; // this is so that we can display selections.
31046a329244db12b6f7afc3c9a6409d420241a1058Xavier Ducrohet            info.mHardwareAccelerated = false;
311c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            mViewRoot.dispatchAttachedToWindow(info, 0);
312c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
31333758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
314b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            postInflateProcess(view, params.getProjectCallback());
31533758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet
316c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the background drawable
317c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mWindowBackground != null) {
318b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
319bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                mContentRoot.setBackgroundDrawable(d);
320c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
321c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
32219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
323c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (PostInflateException e) {
32419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
325c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
326c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
327c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
328c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
329c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
330c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
331c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
33219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
333c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
334c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
335c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
336c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
337c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Renders the scene.
338c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
3392eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
3402eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
3415a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
3425a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
3435a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      animations.)
3445a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *
3452eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
3462eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
3479eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet     *
348bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderParams#getRenderingMode()
349bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#render(long)
350c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
3515a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet    public Result render(boolean freshRender) {
3522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
3532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
354b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
355b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
356c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
357c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mViewRoot == null) {
35819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
359c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
360c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // measure the views
361c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            int w_spec, h_spec;
362c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
363b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            RenderingMode renderingMode = params.getRenderingMode();
364fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet
3659eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // only do the screen measure when needed.
3669eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            boolean newRenderSize = false;
3679eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
3689eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                newRenderSize = true;
369b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                mMeasuredScreenWidth = params.getScreenWidth();
370b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                mMeasuredScreenHeight = params.getScreenHeight();
3719eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
3729eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
3739eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    // measure the full size needed by the layout.
3749eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth,
3759eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                            renderingMode.isHorizExpand() ?
3769eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
3779eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    : MeasureSpec.EXACTLY);
37816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight,
3799eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                            renderingMode.isVertExpand() ?
3809eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
3819eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                                    : MeasureSpec.EXACTLY);
3829eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    mViewRoot.measure(w_spec, h_spec);
3839eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
3849eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
3859eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
3869eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        if (neededWidth > mMeasuredScreenWidth) {
3879eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                            mMeasuredScreenWidth = neededWidth;
3889eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
389fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
390c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3919eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isVertExpand()) {
3929eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
39316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        if (neededHeight > mMeasuredScreenHeight) {
39416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenHeight = neededHeight;
3959eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
396fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
397c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
398c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
399c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
400c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // remeasure with the size we need
401c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // This must always be done before the call to layout
4029eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, MeasureSpec.EXACTLY);
40333758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet            h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight, MeasureSpec.EXACTLY);
404c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            mViewRoot.measure(w_spec, h_spec);
405c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
406c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // now do the layout.
40716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
408c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
40933758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet            mViewRoot.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
41033758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet
411c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // draw the views
412c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // create the BufferedImage into which the layout will be rendered.
4135a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            boolean newImage = false;
4149eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            if (newRenderSize || mCanvas == null) {
415b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                if (params.getImageFactory() != null) {
416b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                    mImage = params.getImageFactory().getImage(
41716584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenWidth,
418bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                            mMeasuredScreenHeight);
4199eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                } else {
42016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    mImage = new BufferedImage(
42116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            mMeasuredScreenWidth,
422bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                            mMeasuredScreenHeight,
42316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                            BufferedImage.TYPE_INT_ARGB);
4245a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    newImage = true;
4259eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
426c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
427b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                if (params.isBgColorOverridden()) {
4285a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    // since we override the content, it's the same as if it was a new image.
4295a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    newImage = true;
4309eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
431b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                    gc.setColor(new Color(params.getOverrideBgColor(), true));
4325a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
433bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
4349eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    gc.dispose();
4359eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
436c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4379eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                // create an Android bitmap around the BufferedImage
4389eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
439b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                        true /*isMutable*/, params.getDensity());
440c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4419eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                // create a Canvas around the Android bitmap
4429eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                mCanvas = new Canvas(bitmap);
443b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                mCanvas.setDensity(params.getDensity().getDpiValue());
4449eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            }
445c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4465a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            if (freshRender && newImage == false) {
4475a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                Graphics2D gc = mImage.createGraphics();
4485a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                gc.setComposite(AlphaComposite.Src);
44916584225125acba18b74920b902c798dfead0328Xavier Ducrohet
45016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                gc.setColor(new Color(0x00000000, true));
451bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                gc.fillRect(0, 0,
452bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        mMeasuredScreenWidth, mMeasuredScreenHeight);
45316584225125acba18b74920b902c798dfead0328Xavier Ducrohet
45416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // done
4555a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                gc.dispose();
4565a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            }
4575a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet
4589eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            mViewRoot.draw(mCanvas);
4599eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
460bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            mViewInfoList = startVisitingViews(mViewRoot, 0);
461c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
462c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // success!
46319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
464c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
465c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
466c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
467c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
468c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
469c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
470c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
47119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
472c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
473c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
474c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
475c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
4762eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Animate an object
4772eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * <p>
4782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
4792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
4802eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
4812eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
482e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
483bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
4842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
48519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
4862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
4872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
4882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
489b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
490b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
4912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // find the animation file.
492ffb42f6c5043de226f02318a1311669d35a90711Xavier Ducrohet        ResourceValue animationResource = null;
4932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        int animationId = 0;
4942eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (isFrameworkAnimation) {
495b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getFrameworkResource(
49635ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
4972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
498b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
4992eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } else {
501b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getProjectResource(
50235ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
5032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
504b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                animationId = context.getProjectCallback().getResourceId(
50535ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
5062eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5072eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5082eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
5092eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (animationResource != null) {
5102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            try {
511b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(context, animationId);
5122eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (anim != null) {
5132eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    anim.setTarget(targetObject);
5142eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
515e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
5162eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
51719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    return SUCCESS.createResult();
5182eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
5192eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            } catch (Exception e) {
520c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                // get the real cause of the exception.
521c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                Throwable t = e;
522c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                while (t.getCause() != null) {
523c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                    t = t.getCause();
524c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                }
525c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
52619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5272eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5282eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5292eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
53019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
531c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
532c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
533e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
534e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Insert a new child into an existing parent.
535e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
536e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
537e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
538e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
539e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
540e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
541bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
542e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
54319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
544e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final int index, IAnimationListener listener) {
545c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
546c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
547b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
548b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
549c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // create a block parser for the XML
550b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, context,
551c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                false /* platformResourceFlag */);
552c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
553c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
554c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
555c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // be created correctly.
556e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
557c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
558e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
559e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
560e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
561e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
562e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
563e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
56419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
565e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
566e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return addView(parentView, child, index);
567e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
568e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
569e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
570e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
571e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(null);
572e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
573e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
574e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
575e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
57619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(child);
5779eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        }
5789eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
579e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        // add it to the parentView in the correct location
58019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = addView(parentView, child, index);
581e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (result.isSuccess() == false) {
582e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
583e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
584c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
5855a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
586c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        if (result.isSuccess()) {
587e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(child);
588c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        }
589c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet
590c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        return result;
591c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
592c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
593e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
594e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Adds a given view to a given parent at a given index.
595e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
596e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param parent the parent to receive the view
597e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to add to the parent
598e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the index where to do the add.
599e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
60019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
60119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
602e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
603e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
60419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
605e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
606e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.addView(view, index);
60719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
608e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
609e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
61019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
611e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
612e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
613e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
614e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
615e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a view to a new parent at a given location
616e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
617e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
618e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
619e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
620e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
621e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
622bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
623e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
6242b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
625479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
626c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
627c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
628e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
629e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
63001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        LayoutParams layoutParams = null;
631e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (layoutParamsMap != null) {
632e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
6332b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
634e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
635e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
6369eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
6372b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        // get the current parent of the view that needs to be moved.
6382b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
6392b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
640e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
641e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final LayoutParams params = layoutParams;
64201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
643479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
644479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
645479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousParent != newParentView) {
646479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new Thread("not animated moveChild") {
647479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
648479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void run() {
649479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
650479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                params);
651479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (result.isSuccess() == false) {
652479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
653479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
654479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
655479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // ready to do the work, acquire the scene.
656479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        result = acquire(250);
657479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (result.isSuccess() == false) {
658479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
659479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            return;
660479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
661479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
662479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        try {
6635a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                            result = render(false /*freshRender*/);
664479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            if (result.isSuccess()) {
665479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
666479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            }
667479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        } finally {
668479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            release();
669479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
670479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
671479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        listener.done(result);
6722b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
673479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
674479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            } else {
675479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
6762b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
677479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
678479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public Result preAnimation() {
679479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // set up the transition for the parent.
680479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
681479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(transition);
6827550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet
683479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
684479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // animation playing just before).
685479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
686479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // on the LayoutTransition.
687479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
688479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
689479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
69001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
691479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
692479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
693479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
694479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
695479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
696479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
697479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
698479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
699479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
700479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
701479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
702479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
703479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void postAnimation() {
704479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(null);
705479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        newParentView.setLayoutTransition(null);
706479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
707479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
708479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            }
709e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
710e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
71119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
712c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
713c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7142b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
715e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (result.isSuccess() == false) {
716e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
717e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
718c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7195a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
72001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
721e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
72201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        }
72301811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
72401811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        return result;
725c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
726c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
727e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
728e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
729e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * an optional new {@link LayoutParams} instance
730e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
7312b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
7322b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param newParent the new parent
733479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet     * @param movedView the view to move
734e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the new location in the new parent
735e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
736e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
73719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
73819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
739e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
740e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
741479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
742479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
7439eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        try {
7442b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            // check if there is a transition on the previousParent.
745479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
746479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousTransition != null) {
7477550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
7487550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
7497550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
7507550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
7517550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // to handle).
7527550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
7537550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
7547550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // adding the child or the child will appear in its new location before the
7557550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // other children have made room for it.
7562b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7572b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
758479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
759479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    private int mChangeDisappearingCount = 0;
7602b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7612b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
7622b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
763479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
764479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount++;
765479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
7662b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
767e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
7682b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
7692b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
770479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
771479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount--;
772479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
773479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
774479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
775479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                mChangeDisappearingCount == 0) {
7762b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            // add it to the parentView in the correct location
7772b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            if (params != null) {
778479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index, params);
7792b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            } else {
780479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index);
7812b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            }
7822b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                        }
7832b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
7842b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                });
7852b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7862b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // remove the view from the current parent.
787479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
7882b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7892b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
7902b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
791e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            } else {
7922b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // standard code with no animation. pretty simple.
793479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
794e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
7952b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add it to the parentView in the correct location
7962b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                if (params != null) {
797479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index, params);
7982b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                } else {
799479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index);
8002b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                }
8012b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8022b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
8032b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            }
8049eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        } catch (UnsupportedOperationException e) {
8059eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
80619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
807c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
808e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
809e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
810e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
811e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a child from its current parent.
812e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
813e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
814e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
815e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
816e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
817e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
818bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#removeChild(Object, IAnimationListener)
819e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
82019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
821e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        checkLock();
822c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
8239eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        invalidateRenderingSize();
8249eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
825e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
826e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
827e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
828e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
829e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
830e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
83119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
832e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
833e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return removeView(parent, childView);
834e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
835e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
836e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
837e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
838e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(null);
839e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
840e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
841e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
842e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
84319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
844e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
845e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
84619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = removeView(parent, childView);
847e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (result.isSuccess() == false) {
848e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
849e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
850e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8515a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        return render(false /*freshRender*/);
8522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
8532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
8542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
855e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a given view from its current parent.
856e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
857e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to remove from its parent
858e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
85919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
86019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
861e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
862e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
86319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
864e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
865e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.removeView(view);
86619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
867e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
868e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
86919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
870e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
871e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
872e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
87416584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findBackground(RenderResources resources) {
875b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (getParams().isBgColorOverridden() == false) {
87616584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mWindowBackground = resources.findItemInTheme("windowBackground");
87716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            if (mWindowBackground != null) {
87816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                mWindowBackground = resources.resolveResValue(mWindowBackground);
87916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            }
88016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
88116584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
882c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
88316584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private boolean isTabletUi() {
884b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return getParams().getConfigScreenSize() == ScreenSize.XLARGE;
88516584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
886c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
88716584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
88816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (isTabletUi() == false) {
88916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            boolean windowFullscreen = getBooleanThemeValue(resources,
89016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    "windowFullscreen", false /*defaultValue*/);
89116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
892bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            if (windowFullscreen == false && mWindowIsFloating == false) {
89316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // default value
89416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
89516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
89616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                // get the real value
89735ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
89816584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        "status_bar_height");
89916584225125acba18b74920b902c798dfead0328Xavier Ducrohet
90016584225125acba18b74920b902c798dfead0328Xavier Ducrohet                if (value != null) {
90116584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
90216584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    if (typedValue != null) {
90316584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        // compute the pixel value based on the display metrics
90416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                        mStatusBarSize = (int)typedValue.getDimension(metrics);
90516584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    }
90616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                }
90716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            }
90816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
90916584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
91016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
911bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
912bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        if (mWindowIsFloating) {
913bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            return;
91416584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
91516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
91616584225125acba18b74920b902c798dfead0328Xavier Ducrohet        boolean windowActionBar = getBooleanThemeValue(resources,
91716584225125acba18b74920b902c798dfead0328Xavier Ducrohet                "windowActionBar", true /*defaultValue*/);
91816584225125acba18b74920b902c798dfead0328Xavier Ducrohet
91916584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // if there's a value and it's false (default is true)
92016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (windowActionBar) {
921c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
922c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // default size of the window title bar
923bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            mActionBarSize = DEFAULT_TITLE_BAR_HEIGHT;
924c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
925c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get value from the theme.
92616584225125acba18b74920b902c798dfead0328Xavier Ducrohet            ResourceValue value = resources.findItemInTheme("actionBarSize");
927c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
928c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // resolve it
92916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            value = resources.resolveResValue(value);
930c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
931c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (value != null) {
932c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                // get the numerical value, if available
933c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
934c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                if (typedValue != null) {
935c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    // compute the pixel value based on the display metrics
936bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    mActionBarSize = (int)typedValue.getDimension(metrics);
937c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
938c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
939bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        } else {
940bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            // action bar overrides title bar so only look for this one if action bar is hidden
941bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            boolean windowNoTitle = getBooleanThemeValue(resources,
942bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    "windowNoTitle", false /*defaultValue*/);
943c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
944bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            if (windowNoTitle == false) {
94516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
946bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                // default size of the window title bar
947bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
94816584225125acba18b74920b902c798dfead0328Xavier Ducrohet
949bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                // get value from the theme.
950bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                ResourceValue value = resources.findItemInTheme("windowTitleSize");
95116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
952bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                // resolve it
953bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                value = resources.resolveResValue(value);
954c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
955bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                if (value != null) {
956bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    // get the numerical value, if available
957bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
958bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    if (typedValue != null) {
959bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        // compute the pixel value based on the display metrics
960bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                        mTitleBarSize = (int)typedValue.getDimension(metrics);
961bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    }
96216584225125acba18b74920b902c798dfead0328Xavier Ducrohet                }
96316584225125acba18b74920b902c798dfead0328Xavier Ducrohet            }
964bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
96516584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
96616584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
96716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
96816584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private void findSystemBar(RenderResources resources, DisplayMetrics metrics) {
969bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        if (isTabletUi() && mWindowIsFloating == false) {
970c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
971c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // default value
972bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            mSystemBarSize = 48; // ??
973c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
974d1d6fafc7fc63543b10552dadf202dd6fa40fe6bXavier Ducrohet            // get the real value
97535ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet            ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
97616584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    "status_bar_height");
97716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
978c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (value != null) {
979c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
980c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                if (typedValue != null) {
981c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    // compute the pixel value based on the display metrics
98216584225125acba18b74920b902c798dfead0328Xavier Ducrohet                    mSystemBarSize = (int)typedValue.getDimension(metrics);
983c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
984c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
98516584225125acba18b74920b902c798dfead0328Xavier Ducrohet        }
98616584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
98716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
98816584225125acba18b74920b902c798dfead0328Xavier Ducrohet    private boolean getBooleanThemeValue(RenderResources resources,
98916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            String name, boolean defaultValue) {
99016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
99116584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // get the title bar flag from the current theme.
99216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        ResourceValue value = resources.findItemInTheme(name);
99316584225125acba18b74920b902c798dfead0328Xavier Ducrohet
99416584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // because it may reference something else, we resolve it.
99516584225125acba18b74920b902c798dfead0328Xavier Ducrohet        value = resources.resolveResValue(value);
996c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
99716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // if there's no value, return the default.
99816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        if (value == null || value.getValue() == null) {
99916584225125acba18b74920b902c798dfead0328Xavier Ducrohet            return defaultValue;
1000c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1001c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
100216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
1003c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1004c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1005c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
1006c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Post process on a view hierachy that was just inflated.
1007c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
1008c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
1009c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
1010c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root view to process.
1011c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param projectCallback callback to the project.
1012c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1013c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private void postInflateProcess(View view, IProjectCallback projectCallback)
1014c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1015c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof TabHost) {
1016c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            setupTabHost((TabHost)view, projectCallback);
101731fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
101831fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
101931fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            badge.setImageToDefault();
1020c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } else if (view instanceof ViewGroup) {
1021c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            ViewGroup group = (ViewGroup)view;
1022c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            final int count = group.getChildCount();
1023c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            for (int c = 0 ; c < count ; c++) {
1024c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                View child = group.getChildAt(c);
1025c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                postInflateProcess(child, projectCallback);
1026c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1027c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1028c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1029c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1030c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
1031c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Sets up a {@link TabHost} object.
1032c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param tabHost the TabHost to setup.
1033c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param projectCallback The project callback object to access the project R class.
1034c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @throws PostInflateException
1035c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1036c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
1037c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1038c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
1039c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
1040c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1041c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1042c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1043c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
1044c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1045c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1046c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if ((v instanceof TabWidget) == false) {
1047c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1048c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
1049c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
1050c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1051c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1052c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
1053c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1054c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1055c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
1056c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1057c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
1058c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1059c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1060c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if ((v instanceof FrameLayout) == false) {
1061c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1062c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
1063c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
1064c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1065c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1066c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
1067c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1068c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // now process the content of the framelayout and dynamically create tabs for it.
1069c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        final int count = content.getChildCount();
1070c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1071c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
1072c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // and FrameLayout.
1073c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        tabHost.setup();
1074c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1075796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        if (count == 0) {
1076796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // Create a dummy child to get a single tab
1077796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
1078796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
1079796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
1080796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        public View createTabContent(String tag) {
1081b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                            return new LinearLayout(getContext());
1082796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        }
1083796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    });
1084796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            tabHost.addTab(spec);
1085796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            return;
1086796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        } else {
1087796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // for each child of the framelayout, add a new TabSpec
1088796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            for (int i = 0 ; i < count ; i++) {
1089796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                View child = content.getChildAt(i);
1090796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
1091796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                int id = child.getId();
1092b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                Pair<ResourceType, String> resource = projectCallback.resolveResourceId(id);
1093796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String name;
1094796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                if (resource != null) {
1095b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                    name = resource.getSecond();
1096796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                } else {
1097796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1098796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                }
1099796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
1100c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1101c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1102c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1103c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1104bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private List<ViewInfo> startVisitingViews(View view, int offset) {
1105bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        if (view == null) {
1106bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            return null;
1107bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
1108bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
1109bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        // adjust the offset to this view.
1110bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        offset += view.getTop();
1111bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
1112bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        if (view == mContentRoot) {
1113bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            return visitAllChildren(mContentRoot, offset);
1114bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
1115bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
1116bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        // otherwise, look for mContentRoot in the children
1117bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        if (view instanceof ViewGroup) {
1118bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            ViewGroup group = ((ViewGroup) view);
1119bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
1120bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            for (int i = 0; i < group.getChildCount(); i++) {
1121bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset);
1122bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                if (list != null) {
1123bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                    return list;
1124bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet                }
1125bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            }
1126bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
1127bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
1128bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        return null;
1129bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    }
1130c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1131c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
1132c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Visits a View and its children and generate a {@link ViewInfo} containing the
1133c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * bounds of all the views.
1134c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root View
1135bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @param offset an offset for the view bounds.
1136c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1137bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private ViewInfo visit(View view, int offset) {
1138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view == null) {
1139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            return null;
1140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1142c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        ViewInfo result = new ViewInfo(view.getClass().getName(),
1143b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                getContext().getViewKey(view),
114416584225125acba18b74920b902c798dfead0328Xavier Ducrohet                view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
1145cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet                view, view.getLayoutParams());
1146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1147c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof ViewGroup) {
1148c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            ViewGroup group = ((ViewGroup) view);
1149bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            result.setChildren(visitAllChildren(group, 0 /*offset*/));
1150c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1151c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1152c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return result;
1153c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1154c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1155bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    /**
1156bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * Visits all the children of a given ViewGroup generate a list of {@link ViewInfo}
1157bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * containing the bounds of all the views.
1158bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @param view the root View
1159bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @param offset an offset for the view bounds.
1160bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     */
1161bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset) {
11627d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        if (viewGroup == null) {
11637d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet            return null;
11647d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        }
11657d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet
11667d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        List<ViewInfo> children = new ArrayList<ViewInfo>();
11677d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        for (int i = 0; i < viewGroup.getChildCount(); i++) {
1168bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            children.add(visit(viewGroup.getChildAt(i), offset));
11697d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        }
11707d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return children;
11717d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    }
11727d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet
11737d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet
11749eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private void invalidateRenderingSize() {
11759eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
11769eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    }
11779eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
1178c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    public BufferedImage getImage() {
1179c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return mImage;
1180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1181c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
118216584225125acba18b74920b902c798dfead0328Xavier Ducrohet    public boolean isAlphaChannelImage() {
118316584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return mIsAlphaChannelImage;
118416584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
118516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
11867d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    public List<ViewInfo> getViewInfos() {
11877d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return mViewInfoList;
1188c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1189cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet
119019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
1191b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return getContext().getDefaultPropMap(viewObject);
1192cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet    }
1193c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
119419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public void setScene(RenderSession session) {
119519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mScene = session;
1196c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1197c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
119819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public RenderSession getSession() {
1199c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        return mScene;
1200c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1201c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet}
1202