RenderSessionImpl.java revision a2378f55b81e7d29f451d7f65527de49417a3f0c
13bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/*
23bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
33bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
43bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
53bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * you may not use this file except in compliance with the License.
63bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * You may obtain a copy of the License at
73bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
83bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
93bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Unless required by applicable law or agreed to in writing, software
113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * See the License for the specific language governing permissions and
143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * limitations under the License.
153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */
163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetpackage com.android.layoutlib.bridge.impl;
183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
19ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
20ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
21ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
22ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
23ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
24ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
25ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
26ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
27ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet
28ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener;
29ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ILayoutPullParser;
30ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.IProjectCallback;
31907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohetimport com.android.ide.common.rendering.api.LayoutLog;
32ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Params;
330d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
34ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
35ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue;
36ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
37ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.StyleResourceValue;
38ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo;
39ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Params.RenderingMode;
400d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
41ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.internal.util.XmlUtils;
43ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeInflater;
46ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindow;
483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindowSession;
493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
50a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohetimport com.android.resources.Density;
511b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohetimport com.android.resources.ResourceType;
52a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohetimport com.android.resources.ScreenSize;
53947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohetimport com.android.util.Pair;
543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.Animator;
56ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.AnimatorInflater;
5733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.LayoutTransition;
5862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate;
603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap;
613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas;
633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.drawable.Drawable;
643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Handler;
653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.DisplayMetrics;
663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.TypedValue;
673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View;
683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.ViewGroup;
693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.AttachInfo;
703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec;
71ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport android.view.ViewGroup.LayoutParams;
723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout;
73f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.LinearLayout;
7462c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohetimport android.widget.QuickContactBadge;
753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost;
763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabWidget;
77f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.TabHost.TabSpec;
783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
794c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohetimport java.awt.AlphaComposite;
803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color;
813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D;
823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage;
833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList;
843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List;
853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map;
86ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.TimeUnit;
87ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.locks.ReentrantLock;
883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/**
90ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * Class implementing the render session.
913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
92ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
93ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout.
953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */
970d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetpublic class RenderSessionImpl extends FrameworkResourceIdProvider {
983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
1003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
1013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
102ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
103ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * The current context being rendered. This is set through {@link #acquire(long)} and
104ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #init(long)}, and unset in {@link #release()}.
105ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
106ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    private static BridgeContext sCurrentContext = null;
107ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
108ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private final Params mParams;
1093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // scene state
111ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private RenderSession mScene;
1123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeContext mContext;
1133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
1143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeInflater mInflater;
1156a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet    private ResourceValue mWindowBackground;
1163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private FrameLayout mViewRoot;
1171392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private Canvas mCanvas;
1181392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1191392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenHeight = -1;
120a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean mIsAlphaChannelImage = true;
121a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
122a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mStatusBarSize;
123a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mTopBarSize;
124a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mSystemBarSize;
125a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mTopOffset;
126a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mTotalBarSize;
127a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // information being returned through the API
1303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BufferedImage mImage;
131e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    private List<ViewInfo> mViewInfoList;
1323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final class PostInflateException extends Exception {
1343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        private static final long serialVersionUID = 1L;
1353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        public PostInflateException(String message) {
1373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            super(message);
1383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
1403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
1433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
144ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a
145ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
1463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     *
1473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
1483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
149ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSessionImpl(Params params) {
1503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // copy the params.
151ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mParams = new Params(params);
152ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
153ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
154ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
155ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
156ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * inflater, and parser.
157ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
158ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
159ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
160ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
161ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
162ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #acquire(long)
163ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
164ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
165ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result init(long timeout) {
166ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
167ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // the result.
168ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = acquireLock(timeout);
169ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (result != null) {
170ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
171ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
1723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // setup the display Metrics.
1743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        DisplayMetrics metrics = new DisplayMetrics();
1753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.densityDpi = mParams.getDensity();
1763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT;
1773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.scaledDensity = metrics.density;
1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.widthPixels = mParams.getScreenWidth();
1793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.heightPixels = mParams.getScreenHeight();
1803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.xdpi = mParams.getXdpi();
1813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.ydpi = mParams.getYdpi();
1823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1830d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        RenderResources resources = mParams.getResources();
1843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the context
1860d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
1870d8c2a8b1c307453a54211fdcebb68b564344feaXavier Ducrohet                mParams.getProjectCallback(), mParams.getTargetSdkVersion());
1883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
189a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // use default of true in case it's not found to use alpha by default
190a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        mIsAlphaChannelImage  = getBooleanThemeValue(resources,
191a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowIsFloating", true /*defaultValue*/);
192a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
193ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
1940d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        setUp();
1953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
196a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findBackground(resources);
197a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findStatusBar(resources, metrics);
198a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findTopBar(resources, metrics);
199a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findSystemBar(resources, metrics);
2003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
201a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        mTopOffset = mStatusBarSize + mTopBarSize;
202a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        mTotalBarSize = mTopOffset + mSystemBarSize;
2033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the inflater and parser.
2053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mInflater = new BridgeInflater(mContext, mParams.getProjectCallback());
2063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mContext.setBridgeInflater(mInflater);
2073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mInflater.setFactory2(mContext);
2083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
2103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                mContext, false /* platformResourceFlag */);
211ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
212ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return SUCCESS.createResult();
2133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
216ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Prepares the scene for action.
217ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
218ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * This call is blocking if another rendering/inflating is currently happening, and will return
219ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * whether the preparation worked.
220ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
221ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * The preparation can fail if another rendering took too long and the timeout was elapsed.
222ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
223ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * More than one call to this from the same thread will have no effect and will return
224ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * {@link Result#SUCCESS}.
225ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
226ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * After scene actions have taken place, only one call to {@link #release()} must be
227ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * done.
228ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
229ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
230ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
231ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
232ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
233ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
234ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
235ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if {@link #init(long)} was never called.
236ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
237ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result acquire(long timeout) {
238ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (mContext == null) {
239ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("After scene creation, #init() must be called");
240ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
241ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
242ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
243ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // the result.
244ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = acquireLock(timeout);
245ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (result != null) {
246ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
247ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
2483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2490d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        setUp();
250ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
2513054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet        return SUCCESS.createResult();
2523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
255ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Acquire the lock so that the scene can be acted upon.
2563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
257ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * This returns null if the lock was just acquired, otherwise it returns
258ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
259ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * instance (see {@link Result#getStatus()}) if an error occurred.
260ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
261ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
262ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return null if the lock was just acquire or another result depending on the state.
263ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
264ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
265ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene.
2663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
267ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result acquireLock(long timeout) {
268ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
269ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
270ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
271ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
272ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
273ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (acquired == false) {
2743054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet                    return ERROR_TIMEOUT.createResult();
275ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
276ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (InterruptedException e) {
2773054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet                return ERROR_LOCK_INTERRUPTED.createResult();
278ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
279ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
280ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // This thread holds the lock already. Checks that this wasn't for a different context.
281ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // If this is called by init, mContext will be null and so should sCurrentContext
282ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // anyway
283ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (mContext != sCurrentContext) {
284ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                throw new IllegalStateException("Acquiring different scenes from same thread without releases");
285ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
2863054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet            return SUCCESS.createResult();
287ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
2883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
289ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        return null;
290ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
291ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
292ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
293ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Cleans up the scene after an action.
294ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
295ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    public void release() {
296ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
297ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
298ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // with the use of finally blocks, it is possible to find ourself calling this
299ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // without a successful call to prepareScene. This test makes sure that unlock() will
300ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // not throw IllegalMonitorStateException.
301ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread()) {
3020d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            tearDown();
303ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            lock.unlock();
304ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
3053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
3063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
3080d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * Sets up the session for rendering.
3090d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * <p/>
3100d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * The counterpart is {@link #tearDown()}.
3110d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     */
3120d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    private void setUp() {
3130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // make sure the Resources object references the context (and other objects) for this
3140d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // scene
3150d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.initResources();
3160d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        sCurrentContext = mContext;
3170d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3180d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        LayoutLog currentLog = mParams.getLog();
3190d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        Bridge.setLog(currentLog);
3200d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
3210d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setLogger(currentLog);
3220d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
3230d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3240d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    /**
3250d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * Tear down the session after rendering.
3260d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * <p/>
3270d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * The counterpart is {@link #setUp()}.
3280d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     */
3290d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    private void tearDown() {
3300d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // Make sure to remove static references, otherwise we could not unload the lib
3310d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.disposeResources();
3320d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        sCurrentContext = null;
3330d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3340d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        Bridge.setLog(null);
3350d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(null);
3360d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setLogger(null);
33788aa1f36d93e9e214c3c64864a8c692d6a733892Xavier Ducrohet    }
3380d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
33988aa1f36d93e9e214c3c64864a8c692d6a733892Xavier Ducrohet    public static BridgeContext getCurrentContext() {
34088aa1f36d93e9e214c3c64864a8c692d6a733892Xavier Ducrohet        return sCurrentContext;
3410d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
3420d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3430d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    /**
3443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Inflates the layout.
3453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
346ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
347ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
348ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
349ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
3503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
351ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result inflate() {
352ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
353ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
3553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot = new FrameLayout(mContext);
3573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
3593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // it can instantiate the custom Fragment.
3603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Fragment_Delegate.setProjectCallback(mParams.getProjectCallback());
3613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            View view = mInflater.inflate(mBlockParser, mViewRoot);
3633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Fragment_Delegate.setProjectCallback(null);
3653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // set the AttachInfo on the root view.
3673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
3683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    new Handler(), null);
3693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mHasWindowFocus = true;
3703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mWindowVisibility = View.VISIBLE;
3713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mInTouchMode = false; // this is so that we can display selections.
37290f9956c17660c35ee6fe934815c16e97bf0d3f8Xavier Ducrohet            info.mHardwareAccelerated = false;
3733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot.dispatchAttachedToWindow(info, 0);
3743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
375a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
376a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet            postInflateProcess(view, mParams.getProjectCallback());
377a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet
3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the background drawable
3793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mWindowBackground != null) {
3803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                Drawable d = ResourceHelper.getDrawable(mWindowBackground,
3813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                        mContext, true /* isFramework */);
3823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                mViewRoot.setBackgroundDrawable(d);
3833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
385ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
3863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (PostInflateException e) {
387ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
3883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
3893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
3903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
3913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
3923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
3933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
395ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
3963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
3973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
3983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
4003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Renders the scene.
4013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
402ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
403ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
4044c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
4054c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
4064c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      animations.)
4074c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *
408ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
409ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
4101392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     *
4111392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     * @see SceneParams#getRenderingMode()
41233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#render(long)
4133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
4144c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet    public Result render(boolean freshRender) {
415ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
416ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
4173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
4183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mViewRoot == null) {
419ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
4203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // measure the views
4223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            int w_spec, h_spec;
4233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
424e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet            RenderingMode renderingMode = mParams.getRenderingMode();
425e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet
4261392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // only do the screen measure when needed.
4271392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            boolean newRenderSize = false;
4281392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
4291392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                newRenderSize = true;
4301392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mMeasuredScreenWidth = mParams.getScreenWidth();
431a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mMeasuredScreenHeight = mParams.getScreenHeight() - mTotalBarSize;
4321392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
4331392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
4341392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    // measure the full size needed by the layout.
4351392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth,
4361392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            renderingMode.isHorizExpand() ?
4371392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4381392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    : MeasureSpec.EXACTLY);
439a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight,
4401392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            renderingMode.isVertExpand() ?
4411392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4421392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    : MeasureSpec.EXACTLY);
4431392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    mViewRoot.measure(w_spec, h_spec);
4441392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
4451392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
4461392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
4471392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        if (neededWidth > mMeasuredScreenWidth) {
4481392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            mMeasuredScreenWidth = neededWidth;
4491392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
450e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
4513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4521392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isVertExpand()) {
4531392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
454a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        if (neededHeight > mMeasuredScreenHeight) {
455a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight = neededHeight;
4561392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
457e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
4583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
4593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // remeasure with the size we need
4623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // This must always be done before the call to layout
4631392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, MeasureSpec.EXACTLY);
464a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet            h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight, MeasureSpec.EXACTLY);
4653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot.measure(w_spec, h_spec);
4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // now do the layout.
468a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
4693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
470a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet            mViewRoot.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
471a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet
4723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // draw the views
4733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // create the BufferedImage into which the layout will be rendered.
4744c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            boolean newImage = false;
4751392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            if (newRenderSize || mCanvas == null) {
4761392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                if (mParams.getImageFactory() != null) {
477a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mImage = mParams.getImageFactory().getImage(
478a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenWidth,
479a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize);
4801392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                } else {
481a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mImage = new BufferedImage(
482a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenWidth,
483a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize,
484a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            BufferedImage.TYPE_INT_ARGB);
4854c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    newImage = true;
4861392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
4873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
488ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                if (mParams.isBgColorOverridden()) {
4894c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    // since we override the content, it's the same as if it was a new image.
4904c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    newImage = true;
4911392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
492ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    gc.setColor(new Color(mParams.getOverrideBgColor(), true));
4934c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
494a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth,
495a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize);
4961392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    gc.dispose();
4971392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
4983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4991392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                // create an Android bitmap around the BufferedImage
5001392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
5011392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        true /*isMutable*/,
502a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        Density.getEnum(mParams.getDensity()));
5033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5041392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                // create a Canvas around the Android bitmap
5051392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mCanvas = new Canvas(bitmap);
5061392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mCanvas.setDensity(mParams.getDensity());
507a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mCanvas.translate(0, mTopOffset);
5081392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            }
5093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5104c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            if (freshRender && newImage == false) {
5114c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                Graphics2D gc = mImage.createGraphics();
5124c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                gc.setComposite(AlphaComposite.Src);
513a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
514a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (mStatusBarSize > 0) {
515a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.setColor(new Color(0xFF3C3C3C, true));
516a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth, mStatusBarSize);
517a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
518a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
519a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (mTopBarSize > 0) {
520a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.setColor(new Color(0xFF7F7F7F, true));
521a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, mStatusBarSize, mMeasuredScreenWidth, mTopOffset);
522a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
523a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
524a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // erase the rest
525a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                gc.setColor(new Color(0x00000000, true));
526a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                gc.fillRect(0, mTopOffset,
527a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        mMeasuredScreenWidth, mMeasuredScreenHeight + mTopOffset);
528a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
529a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (mSystemBarSize > 0) {
530a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.setColor(new Color(0xFF3C3C3C, true));
531a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, mMeasuredScreenHeight + mTopOffset,
532a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenWidth, mMeasuredScreenHeight + mTotalBarSize);
533a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
534a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
535a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // done
5364c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                gc.dispose();
5374c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            }
5384c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet
5391392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            mViewRoot.draw(mCanvas);
5401392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
541a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mViewInfoList = visitAllChildren((ViewGroup)mViewRoot, mContext, mTopOffset);
5423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // success!
544ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
5453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
5463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
5473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
5483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
5493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
5503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
5513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
552ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
5543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
5553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
557ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Animate an object
558ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
559ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
560ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
561ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
562ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
56333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
56433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#animate(Object, String, boolean, IAnimationListener)
565ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
566ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
567ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
568ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
569ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
570ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // find the animation file.
5716a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet        ResourceValue animationResource = null;
572ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        int animationId = 0;
573ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (isFrameworkAnimation) {
5740d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            animationResource = mContext.getRenderResources().getFrameworkResource(
5751b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
576ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
577947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
578ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
579ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
5800d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            animationResource = mContext.getRenderResources().getProjectResource(
5811b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
582ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
583947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                animationId = mContext.getProjectCallback().getResourceId(
5841b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
585ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
586ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
587ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
588ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (animationResource != null) {
589ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
59033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(mContext, animationId);
591ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (anim != null) {
592ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                    anim.setTarget(targetObject);
593ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
59433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
595ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
596ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    return SUCCESS.createResult();
597ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
598ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (Exception e) {
599b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                // get the real cause of the exception.
600b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                Throwable t = e;
601b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                while (t.getCause() != null) {
602b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                    t = t.getCause();
603b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                }
604b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
605ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
606ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
607ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
608ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
609ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
610b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
611b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
61233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
61333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Insert a new child into an existing parent.
61433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
61533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
61633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
61733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
61833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
61933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
620ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @see LayoutScene#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
62133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
622ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
62333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final int index, IAnimationListener listener) {
624b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
625b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
626b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // create a block parser for the XML
627b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
628b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                false /* platformResourceFlag */);
629b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
630b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
631b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
632b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // be created correctly.
63333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
634b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
63533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
63633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
63733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
63833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
63933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
64033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
641ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
64233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
64333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return addView(parentView, child, index);
64433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
64533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
64633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
64733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
64833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(null);
64933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
65033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
65133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
65233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
653ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(child);
6541392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        }
6551392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
65633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        // add it to the parentView in the correct location
657ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = addView(parentView, child, index);
65833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
65933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
66033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
661b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
6624c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
6631766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        if (result.isSuccess()) {
66433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(child);
6651766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        }
6661766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet
6671766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        return result;
668b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
669b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
67033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
67133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Adds a given view to a given parent at a given index.
67233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
67333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param parent the parent to receive the view
67433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to add to the parent
67533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the index where to do the add.
67633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
677ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
678ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
67933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
68033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
681ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
68233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
68333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.addView(view, index);
684ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
68533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
68633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
687ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
68833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
68933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
69033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
69133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
69233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a view to a new parent at a given location
69333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
69433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
69533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
69633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
69733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
69833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
69933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener)
70033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
70162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
70224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
703b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
704b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
70533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
70633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
707ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        LayoutParams layoutParams = null;
70833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (layoutParamsMap != null) {
70933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
71062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
71133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
71233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
7131392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
71462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        // get the current parent of the view that needs to be moved.
71562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
71662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
71733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
71833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final LayoutParams params = layoutParams;
719ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
72024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
72124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
72224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousParent != newParentView) {
72324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new Thread("not animated moveChild") {
72424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
72524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void run() {
72624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
72724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                params);
72824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (result.isSuccess() == false) {
72924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
73024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
73124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
73224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // ready to do the work, acquire the scene.
73324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        result = acquire(250);
73424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (result.isSuccess() == false) {
73524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
73624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            return;
73724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
73824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
73924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        try {
7404c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                            result = render(false /*freshRender*/);
74124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            if (result.isSuccess()) {
74224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
74324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            }
74424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        } finally {
74524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            release();
74624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
74724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
74824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        listener.done(result);
74962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
75024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
75124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            } else {
75224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
75362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
75424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
75524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public Result preAnimation() {
75624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // set up the transition for the parent.
75724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
75824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(transition);
7595562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet
76024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
76124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // animation playing just before).
76224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
76324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // on the LayoutTransition.
76424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
76524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
76624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
767ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
76824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
76924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
77024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
77124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
77224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
77324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
77424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
77524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
77624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
77724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
77824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
77924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
78024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void postAnimation() {
78124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(null);
78224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        newParentView.setLayoutTransition(null);
78324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
78424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
78524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            }
78633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
78733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
788ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
789b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
790b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
79162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
79233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
79333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
79433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
795b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
7964c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
797ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
79833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
799ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        }
800ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
801ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        return result;
802b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
803b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
80433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
80533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
80633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * an optional new {@link LayoutParams} instance
80733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
80862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
80962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param newParent the new parent
81024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet     * @param movedView the view to move
81133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the new location in the new parent
81233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
81333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
814ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
815ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
81633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
81733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
81824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
81924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
8201392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        try {
82162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            // check if there is a transition on the previousParent.
82224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
82324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousTransition != null) {
8245562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
8255562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
8265562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
8275562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
8285562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // to handle).
8295562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
8305562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
8315562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // adding the child or the child will appear in its new location before the
8325562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // other children have made room for it.
83362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
83462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
83524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
83624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    private int mChangeDisappearingCount = 0;
83762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
83862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
83962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
84024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
84124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount++;
84224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
84362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
84433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
84562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
84662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
84724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
84824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount--;
84924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
85024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
85124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
85224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                mChangeDisappearingCount == 0) {
85362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            // add it to the parentView in the correct location
85462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            if (params != null) {
85524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index, params);
85662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            } else {
85724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index);
85862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            }
85962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                        }
86062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
86162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                });
86262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
86362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // remove the view from the current parent.
86424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
86562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
86662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
86762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
86833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            } else {
86962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // standard code with no animation. pretty simple.
87024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
87133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
87262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add it to the parentView in the correct location
87362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                if (params != null) {
87424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index, params);
87562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                } else {
87624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index);
87762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                }
87862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
87962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
88062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            }
8811392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        } catch (UnsupportedOperationException e) {
8821392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
883ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
884b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
88533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
88633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
88733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
88833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a child from its current parent.
88933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
89033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
89133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
89233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
89333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
89433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
89533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#removeChild(Object, IAnimationListener)
89633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
897ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
89833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        checkLock();
899b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
9001392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        invalidateRenderingSize();
9011392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
90233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
90333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
90433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
90533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
90633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
90733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
908ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
90933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
91033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return removeView(parent, childView);
91133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
91233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
91333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
91433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
91533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(null);
91633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
91733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
91833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
91933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
920ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
92133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
92233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
923ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = removeView(parent, childView);
92433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
92533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
92633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
92733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
9284c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        return render(false /*freshRender*/);
929ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
930ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
931ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
93233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a given view from its current parent.
93333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
93433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to remove from its parent
93533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
936ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
937ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
93833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
93933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
940ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
94133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
94233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.removeView(view);
943ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
94433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
94533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
946ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
94733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
94833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
94933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
95033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
951907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     * Returns the log associated with the session.
952907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     * @return the log or null if there are none.
953907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     */
954907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    public LayoutLog getLog() {
955907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        if (mParams != null) {
956907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet            return mParams.getLog();
957907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        }
958907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet
959907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        return null;
960907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    }
961907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet
962907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    /**
963ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Checks that the lock is owned by the current thread and that the current context is the one
964ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * from this scene.
965ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
966ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
967ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
968ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
969ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    private void checkLock() {
970ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
971ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
972ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
973ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
974ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (sCurrentContext != mContext) {
975ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
976ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
977ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
978ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
979a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findBackground(RenderResources resources) {
980a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (mParams.isBgColorOverridden() == false) {
981a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mWindowBackground = resources.findItemInTheme("windowBackground");
982a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (mWindowBackground != null) {
983a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mWindowBackground = resources.resolveResValue(mWindowBackground);
984a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
985a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
986a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
9873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
988a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean isTabletUi() {
989a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return mParams.getConfigScreenSize() == ScreenSize.XLARGE;
990a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
9913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
992a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean isHCApp() {
993a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        RenderResources resources = mContext.getRenderResources();
994a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
995a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // the app must say it targets 11+ and the theme name must extend Theme.Holo or
996a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // Theme.Holo.Light (which does not extend Theme.Holo, but Theme.Light)
997a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (mParams.getTargetSdkVersion() < 11) {
998a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return false;
999a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1000a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1001a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        StyleResourceValue currentTheme = resources.getCurrentTheme();
1002a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        StyleResourceValue holoTheme = resources.getTheme("Theme.Holo", true /*frameworkTheme*/);
1003a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1004a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (currentTheme == holoTheme ||
1005a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                resources.themeIsParentOf(holoTheme, currentTheme)) {
1006a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return true;
1007a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1008a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1009a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        StyleResourceValue holoLightTheme = resources.getTheme("Theme.Holo.Light",
1010a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                true /*frameworkTheme*/);
1011a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1012a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (currentTheme == holoLightTheme ||
1013a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                resources.themeIsParentOf(holoLightTheme, currentTheme)) {
1014a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return true;
1015a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1016a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1017a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return false;
1018a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1019a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1020a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
1021a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (isTabletUi() == false) {
1022a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            boolean windowFullscreen = getBooleanThemeValue(resources,
1023a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    "windowFullscreen", false /*defaultValue*/);
1024a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1025a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (windowFullscreen == false) {
1026a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // default value
1027a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
1028a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1029a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // get the real value
10301b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
1031a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        "status_bar_height");
1032a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1033a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (value != null) {
1034a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
1035a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    if (typedValue != null) {
1036a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        // compute the pixel value based on the display metrics
1037a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        mStatusBarSize = (int)typedValue.getDimension(metrics);
1038a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    }
1039a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
1040a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
1041a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1042a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1043a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1044a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findTopBar(RenderResources resources, DisplayMetrics metrics) {
1045a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        boolean windowIsFloating = getBooleanThemeValue(resources,
1046a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowIsFloating", true /*defaultValue*/);
1047a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1048a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (windowIsFloating == false) {
1049a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (isHCApp()) {
1050a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                findActionBar(resources, metrics);
1051a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            } else {
1052a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                findTitleBar(resources, metrics);
1053a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
1054a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1055a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1056a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1057a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
1058a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        boolean windowActionBar = getBooleanThemeValue(resources,
1059a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowActionBar", true /*defaultValue*/);
1060a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1061a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // if there's a value and it's false (default is true)
1062a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (windowActionBar) {
10633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // default size of the window title bar
1065a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
10663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get value from the theme.
1068a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            ResourceValue value = resources.findItemInTheme("actionBarSize");
10693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // resolve it
1071a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            value = resources.resolveResValue(value);
10723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (value != null) {
10743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                // get the numerical value, if available
10753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
10763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                if (typedValue != null) {
10773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    // compute the pixel value based on the display metrics
1078a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mTopBarSize = (int)typedValue.getDimension(metrics);
10793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
10803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
10813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1082a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
10833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1084a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findTitleBar(RenderResources resources, DisplayMetrics metrics) {
1085a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        boolean windowNoTitle = getBooleanThemeValue(resources,
1086a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowNoTitle", false /*defaultValue*/);
10873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1088a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (windowNoTitle == false) {
1089a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1090a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            // default size of the window title bar
1091a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
1092a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1093a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            // get value from the theme.
1094a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            ResourceValue value = resources.findItemInTheme("windowTitleSize");
1095a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1096a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            // resolve it
1097a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            value = resources.resolveResValue(value);
10983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1099a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (value != null) {
1100a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // get the numerical value, if available
1101a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
1102a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (typedValue != null) {
1103a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    // compute the pixel value based on the display metrics
1104a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mTopBarSize = (int)typedValue.getDimension(metrics);
1105a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
1106a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
1107a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1108a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1109a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1110a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findSystemBar(RenderResources resources, DisplayMetrics metrics) {
1111a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (isTabletUi() && getBooleanThemeValue(
1112a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                resources, "windowIsFloating", true /*defaultValue*/) == false) {
11133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // default value
1115a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mSystemBarSize = 56; // ??
11163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1117089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet            // get the real value
11181b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet            ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
1119a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    "status_bar_height");
1120a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
11213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (value != null) {
11223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
11233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                if (typedValue != null) {
11243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    // compute the pixel value based on the display metrics
1125a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mSystemBarSize = (int)typedValue.getDimension(metrics);
11263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
11273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
1128a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1129a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1130a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1131a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean getBooleanThemeValue(RenderResources resources,
1132a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            String name, boolean defaultValue) {
1133a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1134a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // get the title bar flag from the current theme.
1135a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        ResourceValue value = resources.findItemInTheme(name);
1136a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1137a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // because it may reference something else, we resolve it.
1138a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        value = resources.resolveResValue(value);
11393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1140a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // if there's no value, return the default.
1141a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (value == null || value.getValue() == null) {
1142a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return defaultValue;
11433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1145a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
11463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
11493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Post process on a view hierachy that was just inflated.
11503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
11513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
11523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
11533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root view to process.
11543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param projectCallback callback to the project.
11553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
11563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private void postInflateProcess(View view, IProjectCallback projectCallback)
11573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
11583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof TabHost) {
11593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            setupTabHost((TabHost)view, projectCallback);
116062c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
116162c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
116262c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            badge.setImageToDefault();
11633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } else if (view instanceof ViewGroup) {
11643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            ViewGroup group = (ViewGroup)view;
11653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            final int count = group.getChildCount();
11663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            for (int c = 0 ; c < count ; c++) {
11673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                View child = group.getChildAt(c);
11683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                postInflateProcess(child, projectCallback);
11693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
11703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
11743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Sets up a {@link TabHost} object.
11753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param tabHost the TabHost to setup.
11763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param projectCallback The project callback object to access the project R class.
11773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @throws PostInflateException
11783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
11793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
11803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
11813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
11823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
11833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
11853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
11863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
11873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if ((v instanceof TabWidget) == false) {
11903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
11913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
11923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
11933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
11963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
11983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
11993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
12003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
12013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if ((v instanceof FrameLayout) == false) {
12043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
12053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
12063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
12073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
12103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // now process the content of the framelayout and dynamically create tabs for it.
12123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        final int count = content.getChildCount();
12133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
12153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // and FrameLayout.
12163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        tabHost.setup();
12173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1218f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        if (count == 0) {
1219f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            // Create a dummy child to get a single tab
1220f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
1221f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
1222f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
1223f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                        public View createTabContent(String tag) {
1224f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                            return new LinearLayout(mContext);
1225f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                        }
1226f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    });
1227f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            tabHost.addTab(spec);
1228f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            return;
1229f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        } else {
1230f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            // for each child of the framelayout, add a new TabSpec
1231f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            for (int i = 0 ; i < count ; i++) {
1232f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                View child = content.getChildAt(i);
1233f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
1234f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                int id = child.getId();
1235947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                Pair<ResourceType, String> resource = projectCallback.resolveResourceId(id);
1236f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String name;
1237f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                if (resource != null) {
1238947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                    name = resource.getSecond();
1239f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                } else {
1240f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1241f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                }
1242f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
12433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
12443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
12493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Visits a View and its children and generate a {@link ViewInfo} containing the
12503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * bounds of all the views.
12513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root View
12523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param context the context.
12533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
1254a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private ViewInfo visit(View view, BridgeContext context, int offset) {
12553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view == null) {
12563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            return null;
12573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        ViewInfo result = new ViewInfo(view.getClass().getName(),
12603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                context.getViewKey(view),
1261a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
12622d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet                view, view.getLayoutParams());
12633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof ViewGroup) {
12653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            ViewGroup group = ((ViewGroup) view);
1266a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            result.setChildren(visitAllChildren(group, context, 0 /*offset*/));
12673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return result;
12703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1272a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, BridgeContext context,
1273a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            int offset) {
1274e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        if (viewGroup == null) {
1275e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet            return null;
1276e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        }
1277e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet
1278e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        List<ViewInfo> children = new ArrayList<ViewInfo>();
1279e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        for (int i = 0; i < viewGroup.getChildCount(); i++) {
1280a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            children.add(visit(viewGroup.getChildAt(i), context, offset));
1281e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        }
1282e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        return children;
1283e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    }
1284e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet
1285e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet
12861392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private void invalidateRenderingSize() {
12871392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
12881392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    }
12891392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
12903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    public BufferedImage getImage() {
12913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return mImage;
12923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1294a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    public boolean isAlphaChannelImage() {
1295a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return mIsAlphaChannelImage;
1296a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1297a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1298e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    public List<ViewInfo> getViewInfos() {
1299e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        return mViewInfoList;
13003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
13012d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet
1302ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
13032d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet        return mContext.getDefaultPropMap(viewObject);
13042d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet    }
1305b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1306ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public void setScene(RenderSession session) {
1307ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mScene = session;
1308b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
1309b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1310ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSession getSession() {
1311b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        return mScene;
1312b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
13130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
13140d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    // --- FrameworkResourceIdProvider methods
13150d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
13160d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    @Override
13171b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet    public Integer getId(ResourceType resType, String resName) {
1318947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet        return Bridge.getResourceId(resType, resName);
13190d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
13203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet}
1321