RenderSessionImpl.java revision 1b5ef2d19e1d7cb491c1c79f867e38ec0bde2770
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;
533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.Animator;
55ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.AnimatorInflater;
5633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.LayoutTransition;
5762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate;
593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap;
603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas;
623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.drawable.Drawable;
633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Handler;
643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.DisplayMetrics;
653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.TypedValue;
663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View;
673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.ViewGroup;
683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.AttachInfo;
693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec;
70ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport android.view.ViewGroup.LayoutParams;
713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout;
72f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.LinearLayout;
7362c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohetimport android.widget.QuickContactBadge;
743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost;
753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabWidget;
76f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.TabHost.TabSpec;
773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
784c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohetimport java.awt.AlphaComposite;
793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color;
803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D;
813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage;
823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList;
833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List;
843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map;
85ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.TimeUnit;
86ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.locks.ReentrantLock;
873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/**
89ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * Class implementing the render session.
903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
91ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
92ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout.
943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet *
953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */
960d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetpublic class RenderSessionImpl extends FrameworkResourceIdProvider {
973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
1003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
101ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
102ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * The current context being rendered. This is set through {@link #acquire(long)} and
103ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #init(long)}, and unset in {@link #release()}.
104ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
105ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    private static BridgeContext sCurrentContext = null;
106ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
107ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private final Params mParams;
1083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // scene state
110ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private RenderSession mScene;
1113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeContext mContext;
1123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
1133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeInflater mInflater;
1146a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet    private ResourceValue mWindowBackground;
1153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private FrameLayout mViewRoot;
1161392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private Canvas mCanvas;
1171392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1181392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenHeight = -1;
119a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean mIsAlphaChannelImage = true;
120a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
121a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mStatusBarSize;
122a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mTopBarSize;
123a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mSystemBarSize;
124a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mTopOffset;
125a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private int mTotalBarSize;
126a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // information being returned through the API
1293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BufferedImage mImage;
130e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    private List<ViewInfo> mViewInfoList;
1313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final class PostInflateException extends Exception {
1333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        private static final long serialVersionUID = 1L;
1343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        public PostInflateException(String message) {
1363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            super(message);
1373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
1393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
1423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
143ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a
144ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
1453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     *
1463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
1473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
148ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSessionImpl(Params params) {
1493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // copy the params.
150ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mParams = new Params(params);
151ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
152ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
153ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
154ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
155ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * inflater, and parser.
156ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
157ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
158ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
159ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
160ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
161ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #acquire(long)
162ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
163ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
164ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result init(long timeout) {
165ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
166ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // the result.
167ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = acquireLock(timeout);
168ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (result != null) {
169ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
170ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
1713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // setup the display Metrics.
1733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        DisplayMetrics metrics = new DisplayMetrics();
1743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.densityDpi = mParams.getDensity();
1753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT;
1763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.scaledDensity = metrics.density;
1773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.widthPixels = mParams.getScreenWidth();
1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.heightPixels = mParams.getScreenHeight();
1793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.xdpi = mParams.getXdpi();
1803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        metrics.ydpi = mParams.getYdpi();
1813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1820d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        RenderResources resources = mParams.getResources();
1833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the context
1850d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
1860d8c2a8b1c307453a54211fdcebb68b564344feaXavier Ducrohet                mParams.getProjectCallback(), mParams.getTargetSdkVersion());
1873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
188a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // use default of true in case it's not found to use alpha by default
189a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        mIsAlphaChannelImage  = getBooleanThemeValue(resources,
190a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowIsFloating", true /*defaultValue*/);
191a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
192ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
1930d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        setUp();
1943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
195a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findBackground(resources);
196a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findStatusBar(resources, metrics);
197a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findTopBar(resources, metrics);
198a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        findSystemBar(resources, metrics);
1993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
200a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        mTopOffset = mStatusBarSize + mTopBarSize;
201a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        mTotalBarSize = mTopOffset + mSystemBarSize;
2023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the inflater and parser.
2043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mInflater = new BridgeInflater(mContext, mParams.getProjectCallback());
2053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mContext.setBridgeInflater(mInflater);
2063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mInflater.setFactory2(mContext);
2073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
2093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                mContext, false /* platformResourceFlag */);
210ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
211ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return SUCCESS.createResult();
2123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
215ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Prepares the scene for action.
216ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
217ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * This call is blocking if another rendering/inflating is currently happening, and will return
218ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * whether the preparation worked.
219ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
220ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * The preparation can fail if another rendering took too long and the timeout was elapsed.
221ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
222ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * More than one call to this from the same thread will have no effect and will return
223ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * {@link Result#SUCCESS}.
224ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
225ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * After scene actions have taken place, only one call to {@link #release()} must be
226ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * done.
227ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
228ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
229ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
230ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
231ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
232ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
233ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
234ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if {@link #init(long)} was never called.
235ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
236ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result acquire(long timeout) {
237ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (mContext == null) {
238ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("After scene creation, #init() must be called");
239ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
240ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
241ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
242ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // the result.
243ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = acquireLock(timeout);
244ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (result != null) {
245ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
246ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
2473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2480d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        setUp();
249ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
2503054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet        return SUCCESS.createResult();
2513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
254ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Acquire the lock so that the scene can be acted upon.
2553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
256ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * This returns null if the lock was just acquired, otherwise it returns
257ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
258ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * instance (see {@link Result#getStatus()}) if an error occurred.
259ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
260ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
261ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return null if the lock was just acquire or another result depending on the state.
262ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
263ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
264ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene.
2653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
266ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result acquireLock(long timeout) {
267ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
268ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
269ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
270ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
271ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
272ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (acquired == false) {
2733054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet                    return ERROR_TIMEOUT.createResult();
274ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
275ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (InterruptedException e) {
2763054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet                return ERROR_LOCK_INTERRUPTED.createResult();
277ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
278ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
279ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // This thread holds the lock already. Checks that this wasn't for a different context.
280ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // If this is called by init, mContext will be null and so should sCurrentContext
281ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            // anyway
282ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (mContext != sCurrentContext) {
283ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                throw new IllegalStateException("Acquiring different scenes from same thread without releases");
284ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
2853054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet            return SUCCESS.createResult();
286ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
2873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
288ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        return null;
289ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
290ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
291ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
292ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Cleans up the scene after an action.
293ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
294ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    public void release() {
295ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
296ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
297ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // with the use of finally blocks, it is possible to find ourself calling this
298ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // without a successful call to prepareScene. This test makes sure that unlock() will
299ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // not throw IllegalMonitorStateException.
300ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread()) {
3010d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            tearDown();
302ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            lock.unlock();
303ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
3043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
3053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
3070d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * Sets up the session for rendering.
3080d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * <p/>
3090d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * The counterpart is {@link #tearDown()}.
3100d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     */
3110d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    private void setUp() {
3120d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // make sure the Resources object references the context (and other objects) for this
3130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // scene
3140d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.initResources();
3150d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        sCurrentContext = mContext;
3160d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3170d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        LayoutLog currentLog = mParams.getLog();
3180d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        Bridge.setLog(currentLog);
3190d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
3200d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setLogger(currentLog);
3210d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
3220d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3230d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    /**
3240d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * Tear down the session after rendering.
3250d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * <p/>
3260d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     * The counterpart is {@link #setUp()}.
3270d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet     */
3280d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    private void tearDown() {
3290d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        // Make sure to remove static references, otherwise we could not unload the lib
3300d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.disposeResources();
3310d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        sCurrentContext = null;
3320d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3330d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        Bridge.setLog(null);
3340d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(null);
3350d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        mContext.getRenderResources().setLogger(null);
3360d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3370d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
3380d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
3390d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    /**
3403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Inflates the layout.
3413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
342ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
343ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
344ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
345ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
3463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
347ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result inflate() {
348ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
349ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
3503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
3513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot = new FrameLayout(mContext);
3533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
3553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // it can instantiate the custom Fragment.
3563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Fragment_Delegate.setProjectCallback(mParams.getProjectCallback());
3573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            View view = mInflater.inflate(mBlockParser, mViewRoot);
3593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
3613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            postInflateProcess(view, mParams.getProjectCallback());
3623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Fragment_Delegate.setProjectCallback(null);
3643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // set the AttachInfo on the root view.
3663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
3673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    new Handler(), null);
3683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mHasWindowFocus = true;
3693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mWindowVisibility = View.VISIBLE;
3703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            info.mInTouchMode = false; // this is so that we can display selections.
37190f9956c17660c35ee6fe934815c16e97bf0d3f8Xavier Ducrohet            info.mHardwareAccelerated = false;
3723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot.dispatchAttachedToWindow(info, 0);
3733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the background drawable
3753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mWindowBackground != null) {
3763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                Drawable d = ResourceHelper.getDrawable(mWindowBackground,
3773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                        mContext, true /* isFramework */);
3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                mViewRoot.setBackgroundDrawable(d);
3793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
381ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
3823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (PostInflateException e) {
383ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
3843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
3853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
3863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
3873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
3883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
3893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
391ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
3923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
3933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
3943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
3963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Renders the scene.
3973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
398ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
399ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
4004c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
4014c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
4024c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      animations.)
4034c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *
404ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
405ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
4061392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     *
4071392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     * @see SceneParams#getRenderingMode()
40833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#render(long)
4093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
4104c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet    public Result render(boolean freshRender) {
411ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
412ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
4133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
4143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mViewRoot == null) {
415ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
4163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // measure the views
4183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            int w_spec, h_spec;
4193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
420e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet            RenderingMode renderingMode = mParams.getRenderingMode();
421e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet
4221392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // only do the screen measure when needed.
4231392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            boolean newRenderSize = false;
4241392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
4251392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                newRenderSize = true;
4261392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mMeasuredScreenWidth = mParams.getScreenWidth();
427a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mMeasuredScreenHeight = mParams.getScreenHeight() - mTotalBarSize;
4281392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
4291392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
4301392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    // measure the full size needed by the layout.
4311392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth,
4321392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            renderingMode.isHorizExpand() ?
4331392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4341392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    : MeasureSpec.EXACTLY);
435a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight,
4361392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            renderingMode.isVertExpand() ?
4371392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
4381392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                                    : MeasureSpec.EXACTLY);
4391392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    mViewRoot.measure(w_spec, h_spec);
4401392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
4411392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
4421392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
4431392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        if (neededWidth > mMeasuredScreenWidth) {
4441392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                            mMeasuredScreenWidth = neededWidth;
4451392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
446e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
4473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4481392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isVertExpand()) {
4491392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
450a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        if (neededHeight > mMeasuredScreenHeight) {
451a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight = neededHeight;
4521392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
453e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
4543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
4553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // remeasure with the size we need
4583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // This must always be done before the call to layout
4591392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, MeasureSpec.EXACTLY);
460a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight,
4613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    MeasureSpec.EXACTLY);
4623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            mViewRoot.measure(w_spec, h_spec);
4633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // now do the layout.
465a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // draw the views
4683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // create the BufferedImage into which the layout will be rendered.
4694c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            boolean newImage = false;
4701392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            if (newRenderSize || mCanvas == null) {
4711392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                if (mParams.getImageFactory() != null) {
472a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mImage = mParams.getImageFactory().getImage(
473a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenWidth,
474a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize);
4751392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                } else {
476a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mImage = new BufferedImage(
477a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenWidth,
478a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize,
479a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            BufferedImage.TYPE_INT_ARGB);
4804c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    newImage = true;
4811392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
4823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
483ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                if (mParams.isBgColorOverridden()) {
4844c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    // since we override the content, it's the same as if it was a new image.
4854c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    newImage = true;
4861392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
487ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    gc.setColor(new Color(mParams.getOverrideBgColor(), true));
4884c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
489a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth,
490a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenHeight + mTotalBarSize);
4911392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    gc.dispose();
4921392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
4933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4941392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                // create an Android bitmap around the BufferedImage
4951392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
4961392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        true /*isMutable*/,
497a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        Density.getEnum(mParams.getDensity()));
4983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4991392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                // create a Canvas around the Android bitmap
5001392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mCanvas = new Canvas(bitmap);
5011392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                mCanvas.setDensity(mParams.getDensity());
502a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mCanvas.translate(0, mTopOffset);
5031392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            }
5043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5054c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            if (freshRender && newImage == false) {
5064c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                Graphics2D gc = mImage.createGraphics();
5074c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                gc.setComposite(AlphaComposite.Src);
508a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
509a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (mStatusBarSize > 0) {
510a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.setColor(new Color(0xFF3C3C3C, true));
511a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, 0, mMeasuredScreenWidth, mStatusBarSize);
512a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
513a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
514a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (mTopBarSize > 0) {
515a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.setColor(new Color(0xFF7F7F7F, true));
516a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, mStatusBarSize, mMeasuredScreenWidth, mTopOffset);
517a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
518a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
519a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // erase the rest
520a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                gc.setColor(new Color(0x00000000, true));
521a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                gc.fillRect(0, mTopOffset,
522a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        mMeasuredScreenWidth, mMeasuredScreenHeight + mTopOffset);
523a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
524a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (mSystemBarSize > 0) {
525a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.setColor(new Color(0xFF3C3C3C, true));
526a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    gc.fillRect(0, mMeasuredScreenHeight + mTopOffset,
527a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                            mMeasuredScreenWidth, mMeasuredScreenHeight + mTotalBarSize);
528a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
529a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
530a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // done
5314c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                gc.dispose();
5324c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            }
5334c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet
5341392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            mViewRoot.draw(mCanvas);
5351392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
536a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mViewInfoList = visitAllChildren((ViewGroup)mViewRoot, mContext, mTopOffset);
5373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // success!
539ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
5403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
5413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
5423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
5433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
5443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
5453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
5463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
547ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
5493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
5503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
552ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Animate an object
553ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
554ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
555ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
556ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
557ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
55833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
55933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#animate(Object, String, boolean, IAnimationListener)
560ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
561ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
562ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
563ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
564ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
565ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // find the animation file.
5666a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet        ResourceValue animationResource = null;
567ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        int animationId = 0;
568ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (isFrameworkAnimation) {
5690d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            animationResource = mContext.getRenderResources().getFrameworkResource(
5701b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
571ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
5721b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                animationId = Bridge.getResourceValue(ResourceType.ANIMATOR, animationName);
573ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
574ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
5750d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet            animationResource = mContext.getRenderResources().getProjectResource(
5761b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
577ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
578551346323dace2bdb2509a7f5c9a0a200794b29cXavier Ducrohet                animationId = mContext.getProjectCallback().getResourceValue(
5791b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
580ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
581ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
582ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
583ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (animationResource != null) {
584ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
58533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(mContext, animationId);
586ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (anim != null) {
587ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                    anim.setTarget(targetObject);
588ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
58933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
590ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
591ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    return SUCCESS.createResult();
592ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
593ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (Exception e) {
594b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                // get the real cause of the exception.
595b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                Throwable t = e;
596b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                while (t.getCause() != null) {
597b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                    t = t.getCause();
598b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                }
599b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
600ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
601ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
602ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
603ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
604ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
605b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
606b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
60733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
60833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Insert a new child into an existing parent.
60933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
61033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
61133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
61233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
61333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
61433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
615ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @see LayoutScene#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
61633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
617ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
61833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final int index, IAnimationListener listener) {
619b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
620b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
621b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // create a block parser for the XML
622b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
623b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                false /* platformResourceFlag */);
624b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
625b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
626b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
627b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // be created correctly.
62833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
629b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
63033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
63133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
63233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
63333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
63433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
63533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
636ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
63733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
63833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return addView(parentView, child, index);
63933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
64033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
64133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
64233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
64333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(null);
64433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
64533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
64633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
64733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
648ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(child);
6491392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        }
6501392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
65133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        // add it to the parentView in the correct location
652ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = addView(parentView, child, index);
65333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
65433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
65533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
656b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
6574c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
6581766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        if (result.isSuccess()) {
65933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(child);
6601766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        }
6611766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet
6621766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        return result;
663b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
664b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
66533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
66633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Adds a given view to a given parent at a given index.
66733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
66833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param parent the parent to receive the view
66933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to add to the parent
67033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the index where to do the add.
67133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
672ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
673ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
67433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
67533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
676ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
67733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
67833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.addView(view, index);
679ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
68033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
68133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
682ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
68333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
68433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
68533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
68633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
68733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a view to a new parent at a given location
68833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
68933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
69033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
69133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
69233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
69333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
69433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener)
69533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
69662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
69724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
698b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
699b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
70033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
70133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
702ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        LayoutParams layoutParams = null;
70333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (layoutParamsMap != null) {
70433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
70562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
70633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
70733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
7081392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
70962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        // get the current parent of the view that needs to be moved.
71062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
71162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
71233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
71333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final LayoutParams params = layoutParams;
714ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
71524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
71624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
71724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousParent != newParentView) {
71824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new Thread("not animated moveChild") {
71924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
72024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void run() {
72124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
72224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                params);
72324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (result.isSuccess() == false) {
72424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
72524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
72624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
72724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // ready to do the work, acquire the scene.
72824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        result = acquire(250);
72924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (result.isSuccess() == false) {
73024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
73124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            return;
73224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
73324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
73424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        try {
7354c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                            result = render(false /*freshRender*/);
73624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            if (result.isSuccess()) {
73724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
73824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            }
73924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        } finally {
74024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            release();
74124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
74224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
74324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        listener.done(result);
74462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
74524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
74624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            } else {
74724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
74862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
74924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
75024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public Result preAnimation() {
75124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // set up the transition for the parent.
75224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
75324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(transition);
7545562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet
75524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
75624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // animation playing just before).
75724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
75824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // on the LayoutTransition.
75924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
76024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
76124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
762ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
76324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
76424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
76524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
76624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
76724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
76824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
76924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
77024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
77124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
77224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
77324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
77424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
77524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void postAnimation() {
77624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(null);
77724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        newParentView.setLayoutTransition(null);
77824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
77924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
78024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            }
78133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
78233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
783ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
784b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
785b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
78662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
78733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
78833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
78933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
790b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
7914c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
792ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
79333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
794ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        }
795ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
796ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        return result;
797b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
798b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
79933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
80033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
80133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * an optional new {@link LayoutParams} instance
80233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
80362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
80462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param newParent the new parent
80524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet     * @param movedView the view to move
80633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the new location in the new parent
80733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
80833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
809ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
810ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
81133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
81233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
81324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
81424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
8151392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        try {
81662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            // check if there is a transition on the previousParent.
81724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
81824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousTransition != null) {
8195562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
8205562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
8215562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
8225562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
8235562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // to handle).
8245562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
8255562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
8265562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // adding the child or the child will appear in its new location before the
8275562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // other children have made room for it.
82862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
82962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
83024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
83124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    private int mChangeDisappearingCount = 0;
83262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
83362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
83462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
83524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
83624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount++;
83724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
83862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
83933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
84062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
84162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
84224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
84324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount--;
84424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
84524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
84624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
84724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                mChangeDisappearingCount == 0) {
84862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            // add it to the parentView in the correct location
84962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            if (params != null) {
85024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index, params);
85162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            } else {
85224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index);
85362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            }
85462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                        }
85562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
85662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                });
85762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
85862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // remove the view from the current parent.
85924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
86062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
86162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
86262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
86333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            } else {
86462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // standard code with no animation. pretty simple.
86524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
86633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
86762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add it to the parentView in the correct location
86862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                if (params != null) {
86924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index, params);
87062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                } else {
87124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index);
87262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                }
87362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
87462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
87562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            }
8761392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        } catch (UnsupportedOperationException e) {
8771392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
878ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
879b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
88033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
88133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
88233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
88333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a child from its current parent.
88433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
88533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
88633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
88733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
88833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
88933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
89033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @see LayoutScene#removeChild(Object, IAnimationListener)
89133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
892ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
89333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        checkLock();
894b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
8951392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        invalidateRenderingSize();
8961392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
89733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
89833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
89933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
90033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
90133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
90233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
903ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
90433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
90533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return removeView(parent, childView);
90633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
90733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
90833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
90933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
91033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(null);
91133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
91233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
91333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
91433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
915ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
91633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
91733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
918ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = removeView(parent, childView);
91933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (result.isSuccess() == false) {
92033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
92133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
92233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
9234c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        return render(false /*freshRender*/);
924ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
925ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
926ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
92733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a given view from its current parent.
92833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
92933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to remove from its parent
93033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
931ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
932ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
93333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
93433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
935ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
93633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
93733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.removeView(view);
938ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
93933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
94033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
941ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
94233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
94333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
94433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
94533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
946907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     * Returns the log associated with the session.
947907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     * @return the log or null if there are none.
948907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet     */
949907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    public LayoutLog getLog() {
950907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        if (mParams != null) {
951907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet            return mParams.getLog();
952907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        }
953907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet
954907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet        return null;
955907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    }
956907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet
957907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet    /**
958ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Checks that the lock is owned by the current thread and that the current context is the one
959ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * from this scene.
960ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
961ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
962ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
963ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
964ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    private void checkLock() {
965ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
966ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
967ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
968ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
969ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (sCurrentContext != mContext) {
970ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
971ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
972ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
973ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
974a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findBackground(RenderResources resources) {
975a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (mParams.isBgColorOverridden() == false) {
976a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mWindowBackground = resources.findItemInTheme("windowBackground");
977a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (mWindowBackground != null) {
978a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mWindowBackground = resources.resolveResValue(mWindowBackground);
979a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
980a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
981a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
9823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
983a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean isTabletUi() {
984a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return mParams.getConfigScreenSize() == ScreenSize.XLARGE;
985a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
9863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
987a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean isHCApp() {
988a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        RenderResources resources = mContext.getRenderResources();
989a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
990a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // the app must say it targets 11+ and the theme name must extend Theme.Holo or
991a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // Theme.Holo.Light (which does not extend Theme.Holo, but Theme.Light)
992a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (mParams.getTargetSdkVersion() < 11) {
993a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return false;
994a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
995a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
996a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        StyleResourceValue currentTheme = resources.getCurrentTheme();
997a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        StyleResourceValue holoTheme = resources.getTheme("Theme.Holo", true /*frameworkTheme*/);
998a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
999a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (currentTheme == holoTheme ||
1000a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                resources.themeIsParentOf(holoTheme, currentTheme)) {
1001a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return true;
1002a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1003a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1004a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        StyleResourceValue holoLightTheme = resources.getTheme("Theme.Holo.Light",
1005a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                true /*frameworkTheme*/);
1006a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1007a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (currentTheme == holoLightTheme ||
1008a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                resources.themeIsParentOf(holoLightTheme, currentTheme)) {
1009a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return true;
1010a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1011a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1012a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return false;
1013a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1014a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1015a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
1016a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (isTabletUi() == false) {
1017a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            boolean windowFullscreen = getBooleanThemeValue(resources,
1018a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    "windowFullscreen", false /*defaultValue*/);
1019a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1020a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (windowFullscreen == false) {
1021a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // default value
1022a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
1023a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1024a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // get the real value
10251b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
1026a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        "status_bar_height");
1027a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1028a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (value != null) {
1029a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
1030a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    if (typedValue != null) {
1031a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        // compute the pixel value based on the display metrics
1032a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                        mStatusBarSize = (int)typedValue.getDimension(metrics);
1033a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    }
1034a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
1035a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
1036a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1037a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1038a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1039a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findTopBar(RenderResources resources, DisplayMetrics metrics) {
1040a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        boolean windowIsFloating = getBooleanThemeValue(resources,
1041a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowIsFloating", true /*defaultValue*/);
1042a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1043a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (windowIsFloating == false) {
1044a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (isHCApp()) {
1045a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                findActionBar(resources, metrics);
1046a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            } else {
1047a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                findTitleBar(resources, metrics);
1048a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
1049a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1050a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1051a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1052a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
1053a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        boolean windowActionBar = getBooleanThemeValue(resources,
1054a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowActionBar", true /*defaultValue*/);
1055a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1056a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // if there's a value and it's false (default is true)
1057a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (windowActionBar) {
10583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // default size of the window title bar
1060a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
10613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get value from the theme.
1063a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            ResourceValue value = resources.findItemInTheme("actionBarSize");
10643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // resolve it
1066a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            value = resources.resolveResValue(value);
10673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (value != null) {
10693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                // get the numerical value, if available
10703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
10713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                if (typedValue != null) {
10723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    // compute the pixel value based on the display metrics
1073a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mTopBarSize = (int)typedValue.getDimension(metrics);
10743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
10753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
10763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1077a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
10783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1079a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findTitleBar(RenderResources resources, DisplayMetrics metrics) {
1080a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        boolean windowNoTitle = getBooleanThemeValue(resources,
1081a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                "windowNoTitle", false /*defaultValue*/);
10823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1083a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (windowNoTitle == false) {
1084a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1085a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            // default size of the window title bar
1086a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
1087a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1088a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            // get value from the theme.
1089a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            ResourceValue value = resources.findItemInTheme("windowTitleSize");
1090a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1091a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            // resolve it
1092a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            value = resources.resolveResValue(value);
10933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1094a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            if (value != null) {
1095a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                // get the numerical value, if available
1096a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
1097a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                if (typedValue != null) {
1098a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    // compute the pixel value based on the display metrics
1099a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mTopBarSize = (int)typedValue.getDimension(metrics);
1100a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                }
1101a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            }
1102a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1103a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1104a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1105a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private void findSystemBar(RenderResources resources, DisplayMetrics metrics) {
1106a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (isTabletUi() && getBooleanThemeValue(
1107a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                resources, "windowIsFloating", true /*defaultValue*/) == false) {
11083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // default value
1110a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mSystemBarSize = 56; // ??
11113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1112089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet            // get the real value
11131b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet            ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
1114a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    "status_bar_height");
1115a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
11163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (value != null) {
11173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
11183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                if (typedValue != null) {
11193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    // compute the pixel value based on the display metrics
1120a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                    mSystemBarSize = (int)typedValue.getDimension(metrics);
11213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
11223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
1123a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        }
1124a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1125a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1126a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private boolean getBooleanThemeValue(RenderResources resources,
1127a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            String name, boolean defaultValue) {
1128a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1129a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // get the title bar flag from the current theme.
1130a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        ResourceValue value = resources.findItemInTheme(name);
1131a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1132a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // because it may reference something else, we resolve it.
1133a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        value = resources.resolveResValue(value);
11343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1135a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // if there's no value, return the default.
1136a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        if (value == null || value.getValue() == null) {
1137a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            return defaultValue;
11383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1140a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
11413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
11443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Post process on a view hierachy that was just inflated.
11453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
11463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
11473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
11483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root view to process.
11493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param projectCallback callback to the project.
11503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
11513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private void postInflateProcess(View view, IProjectCallback projectCallback)
11523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
11533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof TabHost) {
11543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            setupTabHost((TabHost)view, projectCallback);
115562c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
115662c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
115762c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            badge.setImageToDefault();
11583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } else if (view instanceof ViewGroup) {
11593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            ViewGroup group = (ViewGroup)view;
11603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            final int count = group.getChildCount();
11613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            for (int c = 0 ; c < count ; c++) {
11623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                View child = group.getChildAt(c);
11633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                postInflateProcess(child, projectCallback);
11643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
11653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
11693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Sets up a {@link TabHost} object.
11703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param tabHost the TabHost to setup.
11713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param projectCallback The project callback object to access the project R class.
11723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @throws PostInflateException
11733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
11743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
11753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
11763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
11773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
11783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
11803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
11813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
11823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if ((v instanceof TabWidget) == false) {
11853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
11863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
11873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
11883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
11913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
11933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
11943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
11953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
11963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if ((v instanceof FrameLayout) == false) {
11993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
12003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
12013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
12023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
12053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // now process the content of the framelayout and dynamically create tabs for it.
12073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        final int count = content.getChildCount();
12083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
12103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // and FrameLayout.
12113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        tabHost.setup();
12123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1213f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        if (count == 0) {
1214f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            // Create a dummy child to get a single tab
1215f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
1216f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
1217f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
1218f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                        public View createTabContent(String tag) {
1219f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                            return new LinearLayout(mContext);
1220f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                        }
1221f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    });
1222f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            tabHost.addTab(spec);
1223f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            return;
1224f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        } else {
1225f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            // for each child of the framelayout, add a new TabSpec
1226f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            for (int i = 0 ; i < count ; i++) {
1227f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                View child = content.getChildAt(i);
1228f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
1229f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                int id = child.getId();
1230f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String[] resource = projectCallback.resolveResourceValue(id);
1231f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String name;
1232f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                if (resource != null) {
1233f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    name = resource[0]; // 0 is resource name, 1 is resource type.
1234f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                } else {
1235f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1236f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                }
1237f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
12383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
12393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
12443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Visits a View and its children and generate a {@link ViewInfo} containing the
12453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * bounds of all the views.
12463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root View
12473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param context the context.
12483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
1249a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private ViewInfo visit(View view, BridgeContext context, int offset) {
12503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view == null) {
12513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            return null;
12523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        ViewInfo result = new ViewInfo(view.getClass().getName(),
12553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                context.getViewKey(view),
1256a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet                view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
12572d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet                view, view.getLayoutParams());
12583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof ViewGroup) {
12603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            ViewGroup group = ((ViewGroup) view);
1261a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            result.setChildren(visitAllChildren(group, context, 0 /*offset*/));
12623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return result;
12653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1267a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, BridgeContext context,
1268a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            int offset) {
1269e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        if (viewGroup == null) {
1270e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet            return null;
1271e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        }
1272e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet
1273e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        List<ViewInfo> children = new ArrayList<ViewInfo>();
1274e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        for (int i = 0; i < viewGroup.getChildCount(); i++) {
1275a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            children.add(visit(viewGroup.getChildAt(i), context, offset));
1276e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        }
1277e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        return children;
1278e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    }
1279e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet
1280e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet
12811392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private void invalidateRenderingSize() {
12821392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
12831392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    }
12841392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
12853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    public BufferedImage getImage() {
12863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return mImage;
12873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1289a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    public boolean isAlphaChannelImage() {
1290a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return mIsAlphaChannelImage;
1291a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1292a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1293e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    public List<ViewInfo> getViewInfos() {
1294e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        return mViewInfoList;
12953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12962d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet
1297ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
12982d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet        return mContext.getDefaultPropMap(viewObject);
12992d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet    }
1300b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1301ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public void setScene(RenderSession session) {
1302ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mScene = session;
1303b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
1304b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1305ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSession getSession() {
1306b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        return mScene;
1307b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
13080d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
13090d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    // --- FrameworkResourceIdProvider methods
13100d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet
13110d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    @Override
13121b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet    public Integer getId(ResourceType resType, String resName) {
13130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet        return Bridge.getResourceValue(resType, resName);
13140d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet    }
13153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet}
1316