RenderSessionImpl.java revision bca9e5623c820c9aa1e959e3874442de9a9a6c32
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
197062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.ide.common.rendering.api.AdapterBinding;
2064f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohetimport com.android.ide.common.rendering.api.HardwareConfig;
21ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener;
22ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ILayoutPullParser;
235cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perezimport com.android.ide.common.rendering.api.LayoutLog;
24b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutlibCallback;
250d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
26ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
277062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceReference;
28ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue;
29ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
30ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
31d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams;
32b32414fe256a6fe1d65e7a1443cd6ea77db8bd95Xavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams.RenderingMode;
33d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo;
3470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport com.android.ide.common.rendering.api.ViewType;
3541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.ActionMenuItemView;
3641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.BridgeMenuItemImpl;
3741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.IconMenuItemView;
3841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.ListMenuItemView;
3941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.MenuItemImpl;
4041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.MenuView;
41ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
43ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
45a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaevimport com.android.layoutlib.bridge.android.RenderParamsFlags;
46259504c6368e44adfffd4f56f7a838b2d5e73ff9Diego Perezimport com.android.layoutlib.bridge.android.graphics.NopCanvas;
47c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsenimport com.android.layoutlib.bridge.android.support.DesignLibUtil;
48b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perezimport com.android.layoutlib.bridge.android.support.SupportPreferencesUtil;
497062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeAdapter;
507062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
511b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohetimport com.android.resources.ResourceType;
52344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Guptaimport com.android.tools.layoutlib.java.System_Delegate;
53947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohetimport com.android.util.Pair;
5418be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Guptaimport com.android.util.PropertiesMap;
553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
56994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.animation.AnimationThread;
5733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.Animator;
58ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.AnimatorInflater;
5933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.LayoutTransition;
6062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
61442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.NonNull;
62442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.Nullable;
633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate;
643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap;
653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas;
67e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perezimport android.os.Looper;
688a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Guptaimport android.preference.Preference_Delegate;
69994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.view.AttachInfo_Accessor;
70994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.view.BridgeInflater;
71344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Guptaimport android.view.Choreographer_Delegate;
7276f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohetimport android.view.IWindowManager;
7364f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohetimport android.view.IWindowManagerImpl;
7476f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohetimport android.view.Surface;
753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View;
763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec;
77d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport android.view.ViewGroup;
78ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport android.view.ViewGroup.LayoutParams;
796208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohetimport android.view.ViewGroup.MarginLayoutParams;
8070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport android.view.ViewParent;
8176f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohetimport android.view.WindowManagerGlobal_Delegate;
827062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AbsListView;
837062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AbsSpinner;
8470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport android.widget.ActionMenuView;
857062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AdapterView;
867062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.ExpandableListView;
873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout;
88f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.LinearLayout;
897062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.ListView;
9062c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohetimport android.widget.QuickContactBadge;
913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost;
92f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.TabHost.TabSpec;
93d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport android.widget.TabWidget;
943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
954c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohetimport java.awt.AlphaComposite;
963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color;
973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D;
983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage;
993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList;
1003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List;
1013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map;
1023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
103b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
104b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
105b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
106b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
107b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
108b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
109baf88de1f5c435a788f6c38720354b2dbaa19e60Deepanshu Guptaimport static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
110b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta
1113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/**
112ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * Class implementing the render session.
113952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta * <p/>
114ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
115ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
1163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout.
1173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */
1180fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> {
1193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
120259504c6368e44adfffd4f56f7a838b2d5e73ff9Diego Perez    private static final Canvas NOP_CANVAS = new NopCanvas();
121259504c6368e44adfffd4f56f7a838b2d5e73ff9Diego Perez
1223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // scene state
123ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private RenderSession mScene;
1243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
1253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeInflater mInflater;
126799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    private ViewGroup mViewRoot;
127799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    private FrameLayout mContentRoot;
1281392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private Canvas mCanvas;
1291392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1301392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenHeight = -1;
131799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    private boolean mIsAlphaChannelImage;
132344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    /** If >= 0, a frame will be executed */
133344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    private long mElapsedFrameTimeNanos = -1;
134344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    /** True if one frame has been already executed to start the animations */
135344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    private boolean mFirstFrameExecuted = false;
136a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // information being returned through the API
1383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BufferedImage mImage;
139e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    private List<ViewInfo> mViewInfoList;
14085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    private List<ViewInfo> mSystemViewInfoList;
1418b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta    private Layout.Builder mLayoutBuilder;
1426e1b7e3e383e12d36356841130647b846e4c8467Diego Perez    private boolean mNewRenderSize;
1433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final class PostInflateException extends Exception {
1453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        private static final long serialVersionUID = 1L;
1463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
147bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez        private PostInflateException(String message) {
1483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            super(message);
1493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
1513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
1543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
1558d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)},
1568d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * which act as a
157ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
1583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     *
1598d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * @see Bridge#createSession(SessionParams)
1603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
161b32414fe256a6fe1d65e7a1443cd6ea77db8bd95Xavier Ducrohet    public RenderSessionImpl(SessionParams params) {
1620fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        super(new SessionParams(params));
163ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
164ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
165ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
166ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
167ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * inflater, and parser.
168ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
169ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
170ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
171ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
172ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
173ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #acquire(long)
174ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
175ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
1760fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet    @Override
177ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result init(long timeout) {
1780fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        Result result = super.init(timeout);
179952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
180ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
181ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
1823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1830fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        SessionParams params = getParams();
1840fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        BridgeContext context = getContext();
1853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
186a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // use default of true in case it's not found to use alpha by default
187300f4893351a9974fa3380c513b29d4a7883cd74Deepanshu Gupta        mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(),
188300f4893351a9974fa3380c513b29d4a7883cd74Deepanshu Gupta                "windowIsFloating", true, true);
189ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
1908b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta        mLayoutBuilder = new Layout.Builder(params, context);
1913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
19276f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        // FIXME: find those out, and possibly add them to the render params
19376f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        boolean hasNavigationBar = true;
194952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        //noinspection ConstantConditions
19576f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
1968b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta                context.getMetrics(), Surface.ROTATION_0, hasNavigationBar);
19776f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
19876f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet
1993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the inflater and parser.
200b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta        mInflater = new BridgeInflater(context, params.getLayoutlibCallback());
2010fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        context.setBridgeInflater(mInflater);
202ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
2038b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false);
204ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
2053054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet        return SUCCESS.createResult();
2063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
2096e1b7e3e383e12d36356841130647b846e4c8467Diego Perez     * Measures the the current layout if needed (see {@link #invalidateRenderingSize}).
2106e1b7e3e383e12d36356841130647b846e4c8467Diego Perez     */
2117bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez    private void measureLayout(@NonNull SessionParams params) {
2126e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        // only do the screen measure when needed.
2136e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        if (mMeasuredScreenWidth != -1) {
2146e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            return;
2156e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        }
2166e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2176e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        RenderingMode renderingMode = params.getRenderingMode();
2186e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        HardwareConfig hardwareConfig = params.getHardwareConfig();
2196e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2206e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        mNewRenderSize = true;
2216e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
2226e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
2236e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2246e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        if (renderingMode != RenderingMode.NORMAL) {
2256e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
2266e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
2276e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    : MeasureSpec.EXACTLY;
2286e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            int heightMeasureSpecMode = renderingMode.isVertExpand() ?
2296e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
2306e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    : MeasureSpec.EXACTLY;
2316e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2326e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // We used to compare the measured size of the content to the screen size but
2336e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // this does not work anymore due to the 2 following issues:
2346e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // - If the content is in a decor (system bar, title/action bar), the root view
2356e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            //   will not resize even with the UNSPECIFIED because of the embedded layout.
2366e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // - If there is no decor, but a dialog frame, then the dialog padding prevents
2376e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            //   comparing the size of the content to the screen frame (as it would not
2386e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            //   take into account the dialog padding).
2396e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2406e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // The solution is to first get the content size in a normal rendering, inside
2416e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // the decor or the dialog padding.
2426e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // Then measure only the content with UNSPECIFIED to see the size difference
2436e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // and apply this to the screen size.
2446e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
245bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez            View measuredView = mContentRoot.getChildAt(0);
246bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez
2476e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // first measure the full layout, with EXACTLY to get the size of the
2486e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // content as it is inside the decor/dialog
2496e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            @SuppressWarnings("deprecation")
2506e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            Pair<Integer, Integer> exactMeasure = measureView(
251bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez                    mViewRoot, measuredView,
2526e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
2536e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
2546e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2556e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // now measure the content only using UNSPECIFIED (where applicable, based on
2566e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // the rendering mode). This will give us the size the content needs.
2576e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            @SuppressWarnings("deprecation")
2586e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            Pair<Integer, Integer> result = measureView(
2596e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mContentRoot, mContentRoot.getChildAt(0),
2606e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenWidth, widthMeasureSpecMode,
2616e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenHeight, heightMeasureSpecMode);
2626e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
263bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez            // If measuredView is not null, exactMeasure nor result will be null.
264bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez            assert exactMeasure != null;
265bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez            assert result != null;
266bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez
2676e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            // now look at the difference and add what is needed.
2686e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            if (renderingMode.isHorizExpand()) {
2696e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                int measuredWidth = exactMeasure.getFirst();
2706e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                int neededWidth = result.getFirst();
2716e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                if (neededWidth > measuredWidth) {
2726e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenWidth += neededWidth - measuredWidth;
2736e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                }
2746e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                if (mMeasuredScreenWidth < measuredWidth) {
2756e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    // If the screen width is less than the exact measured width,
2766e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    // expand to match.
2776e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenWidth = measuredWidth;
2786e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                }
2796e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            }
2806e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2816e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            if (renderingMode.isVertExpand()) {
2826e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                int measuredHeight = exactMeasure.getSecond();
2836e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                int neededHeight = result.getSecond();
2846e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                if (neededHeight > measuredHeight) {
2856e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenHeight += neededHeight - measuredHeight;
2866e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                }
2876e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                if (mMeasuredScreenHeight < measuredHeight) {
2886e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    // If the screen height is less than the exact measured height,
2896e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    // expand to match.
2906e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenHeight = measuredHeight;
2916e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                }
2926e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            }
2936e1b7e3e383e12d36356841130647b846e4c8467Diego Perez        }
2946e1b7e3e383e12d36356841130647b846e4c8467Diego Perez    }
2956e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
2966e1b7e3e383e12d36356841130647b846e4c8467Diego Perez    /**
2973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Inflates the layout.
2983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
299ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
300ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
301ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
302ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
3033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
304ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result inflate() {
305ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
306ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
3073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
3088b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta            mViewRoot = new Layout(mLayoutBuilder);
3098b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta            mLayoutBuilder = null;  // Done with the builder.
3108b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta            mContentRoot = ((Layout) mViewRoot).getContentRoot();
3110fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            SessionParams params = getParams();
3120fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            BridgeContext context = getContext();
3133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3145cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez            if (Bridge.isLocaleRtl(params.getLocale())) {
3155cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                if (!params.isRtlSupported()) {
3165cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                    Bridge.getLog().warning(LayoutLog.TAG_RTL_NOT_ENABLED,
3175cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                            "You are using a right-to-left " +
3185cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                                    "(RTL) locale but RTL is not enabled", null);
3195cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                } else if (params.getSimulatedPlatformVersion() < 17) {
3205cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                    // This will render ok because we are using the latest layoutlib but at least
3215cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                    // warn the user that this might fail in a real device.
3225cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                    Bridge.getLog().warning(LayoutLog.TAG_RTL_NOT_SUPPORTED, "You are using a " +
3235cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                            "right-to-left " +
3245cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                            "(RTL) locale but RTL is not supported for API level < 17", null);
3255cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez                }
3265cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez            }
3275cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez
3283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
3293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // it can instantiate the custom Fragment.
330b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback());
3313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
332a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaev            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
3338a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            boolean isPreference = "PreferenceScreen".equals(rootTag);
3348a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            View view;
3358a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            if (isPreference) {
336b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez                // First try to use the support library inflater. If something fails, fallback
337b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez                // to the system preference inflater.
338b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez                view = SupportPreferencesUtil.inflatePreference(getContext(), mBlockParser,
3398b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta                        mContentRoot);
340b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez                if (view == null) {
341b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez                    view = Preference_Delegate.inflatePreference(getContext(), mBlockParser,
342b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez                            mContentRoot);
343b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez                }
3448a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            } else {
3458a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                view = mInflater.inflate(mBlockParser, mContentRoot);
3468a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            }
3473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3487062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            // done with the parser, pop it.
3497062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            context.popParser();
3507062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
351b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(null);
3523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // set the AttachInfo on the root view.
354994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohet            AttachInfo_Accessor.setAttachInfo(mViewRoot);
3553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
356a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
357b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
3589028fa93da0f9c7dad2176de347cd6e705084c9fDeepanshu Gupta            mInflater.onDoneInflation();
359a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet
360c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            setActiveToolbar(view, context, params);
361c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
3627bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez            measureLayout(params);
3636e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            measureView(mViewRoot, null /*measuredView*/,
3646e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
3656e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
3666e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
367e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez            mSystemViewInfoList =
368e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                    visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
3696e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    false);
3706e1b7e3e383e12d36356841130647b846e4c8467Diego Perez
371ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
3723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (PostInflateException e) {
373ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
3743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
3753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
3763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
3773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
3793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
381ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
3823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
3833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
3843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
386344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta     * Sets the time for which the next frame will be selected. The time is the elapsed time from
387344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta     * the current system nanos time. You
388344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta     */
389344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    public void setElapsedFrameTimeNanos(long nanos) {
390344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta        mElapsedFrameTimeNanos = nanos;
391344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    }
392344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta
393344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    /**
394f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez     * Runs a layout pass for the given view root
3950685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez     */
396f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez    private static void doLayout(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot,
397f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez            int width, int height) {
3980685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        // measure again with the size we need
3990685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        // This must always be done before the call to layout
4000685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        measureView(viewRoot, null /*measuredView*/,
4010685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez                width, MeasureSpec.EXACTLY,
4020685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez                height, MeasureSpec.EXACTLY);
4030685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez
4040685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        // now do the layout.
4050685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        viewRoot.layout(0, 0, width, height);
4060685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        handleScrolling(context, viewRoot);
407f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez    }
4080685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez
409f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez    /**
410f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez     * Renders the given view hierarchy to the passed canvas and returns the result of the render
411f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez     * operation.
412f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez     * @param canvas an optional canvas to render the views to. If null, only the measure and
413f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez     * layout steps will be executed.
414f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez     */
415bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez    private static Result renderAndBuildResult(@NonNull ViewGroup viewRoot, @Nullable Canvas canvas) {
4160685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        if (canvas == null) {
4170685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez            return SUCCESS.createResult();
4180685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        }
4190685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez
4200685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        AttachInfo_Accessor.dispatchOnPreDraw(viewRoot);
4210685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        viewRoot.draw(canvas);
4220685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez
4230685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez        return SUCCESS.createResult();
4240685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez    }
4250685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez
4260685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez    /**
4273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Renders the scene.
4283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
429ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
430ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
4314c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
4324c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
4334c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      animations.)
4344c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *
435ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
436ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
4371392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     *
4388d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * @see SessionParams#getRenderingMode()
439799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#render(long)
4403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
4414c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet    public Result render(boolean freshRender) {
4427bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez        return renderAndBuildResult(freshRender, false);
4437bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez    }
4447bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez
4457bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez    /**
4467bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * Measures the layout
4477bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * <p>
4487bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * {@link #acquire(long)} must have been called before this.
4497bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *
4507bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * @throws IllegalStateException if the current context is different than the one owned by
4517bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *      the scene, or if {@link #acquire(long)} was not called.
4527bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *
4537bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * @see SessionParams#getRenderingMode()
4547bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * @see RenderSession#render(long)
4557bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     */
4567bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez    public Result measure() {
4577bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez        return renderAndBuildResult(false, true);
4587bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez    }
4597bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez
4607bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez    /**
4617bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * Renders the scene.
4627bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * <p>
4637bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * {@link #acquire(long)} must have been called before this.
4647bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *
4657bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
4667bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *      the case where bitmaps are reused). This is typically needed when not playing
4677bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *      animations.)
4687bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *
4697bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * @throws IllegalStateException if the current context is different than the one owned by
4707bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *      the scene, or if {@link #acquire(long)} was not called.
4717bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     *
4727bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * @see SessionParams#getRenderingMode()
4737bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     * @see RenderSession#render(long)
4747bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez     */
4757bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez    private Result renderAndBuildResult(boolean freshRender, boolean onlyMeasure) {
476ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
477ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
4780fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        SessionParams params = getParams();
4790fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet
4803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
4813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mViewRoot == null) {
482ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
4833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4857bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez            measureLayout(params);
4863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4876e1b7e3e383e12d36356841130647b846e4c8467Diego Perez            HardwareConfig hardwareConfig = params.getHardwareConfig();
4880685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez            Result renderResult = SUCCESS.createResult();
4897bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez            if (onlyMeasure) {
490f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                // delete the canvas and image to reset them on the next full rendering
491f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                mImage = null;
492f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                mCanvas = null;
493f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez                doLayout(getContext(), mViewRoot, mMeasuredScreenWidth, mMeasuredScreenHeight);
494f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet            } else {
495f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                // draw the views
496f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                // create the BufferedImage into which the layout will be rendered.
497f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                boolean newImage = false;
498e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez
499e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // When disableBitmapCaching is true, we do not reuse mImage and
500e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // we create a new one in every render.
501e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // This is useful when mImage is just a wrapper of Graphics2D so
502e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // it doesn't get cached.
503e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
504a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaev                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
5056e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                if (mNewRenderSize || mCanvas == null || disableBitmapCaching) {
5066e1b7e3e383e12d36356841130647b846e4c8467Diego Perez                    mNewRenderSize = false;
507f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    if (params.getImageFactory() != null) {
508f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        mImage = params.getImageFactory().getImage(
509f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenWidth,
510f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenHeight);
511f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    } else {
512f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        mImage = new BufferedImage(
513f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenWidth,
514f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenHeight,
515f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                BufferedImage.TYPE_INT_ARGB);
516f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        newImage = true;
517f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    }
518f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet
519f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    if (params.isBgColorOverridden()) {
520f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        // since we override the content, it's the same as if it was a new image.
521f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        newImage = true;
522f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        Graphics2D gc = mImage.createGraphics();
523f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.setColor(new Color(params.getOverrideBgColor(), true));
524f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.setComposite(AlphaComposite.Src);
525f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
526f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.dispose();
527f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    }
528f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet
529f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    // create an Android bitmap around the BufferedImage
530f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
53164f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet                            true /*isMutable*/, hardwareConfig.getDensity());
532f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet
533e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                    if (mCanvas == null) {
534e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                        // create a Canvas around the Android bitmap
535e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                        mCanvas = new Canvas(bitmap);
536e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                    } else {
537e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                        mCanvas.setBitmap(bitmap);
538e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                    }
53964f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
5401392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
5413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
542952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                if (freshRender && !newImage) {
5431392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
5444c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
5453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
546f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    gc.setColor(new Color(0x00000000, true));
547f4978e031c3ad565f02d5a4c65f87ae4477f3613Deepanshu Gupta                    gc.fillRect(0, 0,
548f4978e031c3ad565f02d5a4c65f87ae4477f3613Deepanshu Gupta                            mMeasuredScreenWidth, mMeasuredScreenHeight);
549a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
550f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    // done
551f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    gc.dispose();
552f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                }
553a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
554f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez                doLayout(getContext(), mViewRoot, mMeasuredScreenWidth, mMeasuredScreenHeight);
555344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                if (mElapsedFrameTimeNanos >= 0) {
556344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    long initialTime = System_Delegate.nanoTime();
557344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    if (!mFirstFrameExecuted) {
5580685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez                        // We need to run an initial draw call to initialize the animations
559bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez                        renderAndBuildResult(mViewRoot, NOP_CANVAS);
5600685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez
561344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                        // The first frame will initialize the animations
562344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                        Choreographer_Delegate.doFrame(initialTime);
563344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                        mFirstFrameExecuted = true;
564344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    }
565344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    // Second frame will move the animations
566344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
567344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                }
568bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez                renderResult = renderAndBuildResult(mViewRoot, mCanvas);
5694c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            }
5704c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet
571e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez            mSystemViewInfoList =
572e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                    visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
57341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta                    false);
5743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // success!
5760685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez            return renderResult;
5773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
5783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
5793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
5803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
5813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
5823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
5833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
584ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
5863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
5873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
5883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
5898ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
5908ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
5918ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     *
5928ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
5938ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
5948ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     *
5958ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param viewToMeasure the view on which to execute measure().
5968ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param measuredView if non null, the view to query for its measured width/height.
5978ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param width the width to use in the MeasureSpec.
5988ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param widthMode the MeasureSpec mode to use for the width.
5998ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param height the height to use in the MeasureSpec.
6008ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param heightMode the MeasureSpec mode to use for the height.
6018ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @return the measured width/height if measuredView is non-null, null otherwise.
6028ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     */
603952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
6040685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez    private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
6058ae691c1148038995d1185716f629b82c582897fXavier Ducrohet            int width, int widthMode, int height, int heightMode) {
6068ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
6078ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
6088ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        viewToMeasure.measure(w_spec, h_spec);
6098ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
6108ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        if (measuredView != null) {
6118ae691c1148038995d1185716f629b82c582897fXavier Ducrohet            return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight());
6128ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        }
6138ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
6148ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        return null;
6158ae691c1148038995d1185716f629b82c582897fXavier Ducrohet    }
6168ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
6178ae691c1148038995d1185716f629b82c582897fXavier Ducrohet    /**
618ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Animate an object
619ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
620ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
621ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
622ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
623ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
62433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
625799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
626ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
627ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
628ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
629ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
630ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
6310fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        BridgeContext context = getContext();
6320fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet
633ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // find the animation file.
634952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        ResourceValue animationResource;
635ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        int animationId = 0;
636ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (isFrameworkAnimation) {
6370fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            animationResource = context.getRenderResources().getFrameworkResource(
6381b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
639ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
640947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
641ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
642ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
6430fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            animationResource = context.getRenderResources().getProjectResource(
6441b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
645ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
646b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                animationId = context.getLayoutlibCallback().getResourceId(
6471b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
648ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
649ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
650ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
651ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (animationResource != null) {
652ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
6530fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(context, animationId);
654ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (anim != null) {
655ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                    anim.setTarget(targetObject);
656ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
65733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
658ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
659ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    return SUCCESS.createResult();
660ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
661ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (Exception e) {
662b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                // get the real cause of the exception.
663b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                Throwable t = e;
664b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                while (t.getCause() != null) {
665b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                    t = t.getCause();
666b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                }
667b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
668ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
669ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
670ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
671ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
672ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
673b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
674b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
67533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
67633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Insert a new child into an existing parent.
67733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
67833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
67933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
68033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
68133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
68233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
683799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
68433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
685ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
68633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final int index, IAnimationListener listener) {
687b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
688b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
6890fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        BridgeContext context = getContext();
6900fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet
691b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // create a block parser for the XML
692a732a0101ad07b28e828bbbc8fb81be0580d53b5Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
693a732a0101ad07b28e828bbbc8fb81be0580d53b5Xavier Ducrohet                childXml, context, false /* platformResourceFlag */);
694b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
695b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
696b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
697b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // be created correctly.
69833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
699a732a0101ad07b28e828bbbc8fb81be0580d53b5Xavier Ducrohet        blockParser.ensurePopped();
700b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
70133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
70233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
70333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
70433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
70533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
70633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
707ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
70833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
70933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return addView(parentView, child, index);
71033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
71133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
71233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
71333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
71433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(null);
71533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
71633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
71733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
71833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
719ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(child);
7201392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        }
7211392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
72233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        // add it to the parentView in the correct location
723ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = addView(parentView, child, index);
724952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
72533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
72633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
727b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
7284c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
7291766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        if (result.isSuccess()) {
73033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(child);
7311766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        }
7321766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet
7331766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        return result;
734b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
735b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
73633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
73733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Adds a given view to a given parent at a given index.
73833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
73933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param parent the parent to receive the view
74033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to add to the parent
74133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the index where to do the add.
74233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
743ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
744ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
74533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
74633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
747ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
74833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
74933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.addView(view, index);
750ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
75133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
75233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
753ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
75433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
75533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
75633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
75733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
75833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a view to a new parent at a given location
75933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
76033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
76133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
76233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
76333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
76433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
765799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
76633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
76762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
76824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
769b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
770b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
77133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
77233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
773ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        LayoutParams layoutParams = null;
77433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (layoutParamsMap != null) {
77533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
77662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
77733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
77833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
7791392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
78062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        // get the current parent of the view that needs to be moved.
78162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
78262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
78333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
78433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final LayoutParams params = layoutParams;
785ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
78624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
78724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
78824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousParent != newParentView) {
78924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new Thread("not animated moveChild") {
79024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
79124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void run() {
79224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
79324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                params);
794952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                        if (!result.isSuccess()) {
79524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
79624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
79724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
79824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // ready to do the work, acquire the scene.
79924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        result = acquire(250);
800952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                        if (!result.isSuccess()) {
80124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
80224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            return;
80324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
80424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
80524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        try {
8064c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                            result = render(false /*freshRender*/);
80724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            if (result.isSuccess()) {
80824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
80924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            }
81024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        } finally {
81124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            release();
81224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
81324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
81424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        listener.done(result);
81562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
81624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
81724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            } else {
81824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
81962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
82024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
82124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public Result preAnimation() {
82224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // set up the transition for the parent.
82324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
82424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(transition);
8255562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet
82624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
82724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // animation playing just before).
82824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
82924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // on the LayoutTransition.
83024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
83124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
83224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
833ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
83424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
83524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
83624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
83724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
83824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
83924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
84024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
84124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
84224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
84324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
84424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
84524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
84624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void postAnimation() {
84724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(null);
84824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        newParentView.setLayoutTransition(null);
84924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
85024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
85124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            }
85233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
85333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
854ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
855b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
856b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
85762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
858952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
85933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
86033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
861b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
8624c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
863ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
86433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
865ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        }
866ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
867ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        return result;
868b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
869b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
87033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
87133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
87233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * an optional new {@link LayoutParams} instance
87333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
87462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
87562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param newParent the new parent
87624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet     * @param movedView the view to move
87733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the new location in the new parent
87833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
87933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
880ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
881ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
88233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
88333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
88424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
88524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
8861392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        try {
88762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            // check if there is a transition on the previousParent.
88824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
88924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousTransition != null) {
8905562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
8915562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
8925562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
8935562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
8945562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // to handle).
8955562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
8965562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
8975562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // adding the child or the child will appear in its new location before the
8985562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // other children have made room for it.
89962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
90062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
90124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
90224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    private int mChangeDisappearingCount = 0;
90362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
904d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohet                    @Override
90562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
90662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
90724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
90824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount++;
90924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
91062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
91133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
912d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohet                    @Override
91362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
91462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
91524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
91624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount--;
91724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
91824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
91924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
92024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                mChangeDisappearingCount == 0) {
92162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            // add it to the parentView in the correct location
92262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            if (params != null) {
92324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index, params);
92462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            } else {
92524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index);
92662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            }
92762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                        }
92862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
92962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                });
93062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
93162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // remove the view from the current parent.
93224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
93362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
93462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
93562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
93633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            } else {
93762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // standard code with no animation. pretty simple.
93824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
93933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
94062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add it to the parentView in the correct location
94162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                if (params != null) {
94224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index, params);
94362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                } else {
94424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index);
94562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                }
94662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
94762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
94862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            }
9491392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        } catch (UnsupportedOperationException e) {
9501392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
951ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
952b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
95333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
95433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
95533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
95633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a child from its current parent.
95733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
95833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
95933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
96033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
96133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
96233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
963799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#removeChild(Object, IAnimationListener)
96433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
965ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
96633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        checkLock();
967b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
9681392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        invalidateRenderingSize();
9691392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
97033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
97133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
97233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
97333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
97433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
97533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
976ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
97733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
97833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return removeView(parent, childView);
97933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
98033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
98133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
98233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
98333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(null);
98433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
98533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
98633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
98733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
988ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
98933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
99033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
991ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = removeView(parent, childView);
992952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
99333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
99433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
99533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
9964c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        return render(false /*freshRender*/);
997ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
998ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
999ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
100033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a given view from its current parent.
100133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
100233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to remove from its parent
100333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
1004ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
1005ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
100633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
100733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
1008ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
100933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
101033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.removeView(view);
1011ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
101233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
101333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
1014ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
101533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
101633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
101733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
10183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1019952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta     * Post process on a view hierarchy that was just inflated.
1020952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta     * <p/>
1021952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta     * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
10223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
10233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
10243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root view to process.
1025b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta     * @param layoutlibCallback callback to the project.
10268a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta     * @param skip the view and it's children are not processed.
10273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
1028952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
1029b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta    private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip)
10303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
10318a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta        if (view == skip) {
10328a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            return;
10338a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta        }
10343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof TabHost) {
1035b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            setupTabHost((TabHost) view, layoutlibCallback);
103662c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
103762c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
103862c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            badge.setImageToDefault();
10397062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet        } else if (view instanceof AdapterView<?>) {
10407062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            // get the view ID.
10417062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            int id = view.getId();
10427062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10437062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            BridgeContext context = getContext();
10447062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10457062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            // get a ResourceReference from the integer ID.
10467062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            ResourceReference listRef = context.resolveId(id);
10477062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10487062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            if (listRef != null) {
10497062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                SessionParams params = getParams();
10507062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                AdapterBinding binding = params.getAdapterBindings().get(listRef);
10517062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10527062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                // if there was no adapter binding, trying to get it from the call back.
10537062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                if (binding == null) {
1054b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                    binding = layoutlibCallback.getAdapterBinding(
1055b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                            listRef, context.getViewKey(view), view);
10567062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                }
10577062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10587062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                if (binding != null) {
10597062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10607062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                    if (view instanceof AbsListView) {
10617062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) &&
10627062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                view instanceof ListView) {
10637062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            ListView list = (ListView) view;
10647062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10657062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            boolean skipCallbackParser = false;
10667062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10677062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            int count = binding.getHeaderCount();
10688a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                            for (int i = 0; i < count; i++) {
10697062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
10707062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                        binding.getHeaderAt(i),
1071b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                        list, false, skipCallbackParser);
10727062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                if (pair.getFirst() != null) {
10737062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                    list.addHeaderView(pair.getFirst());
10747062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                }
10757062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10767062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                skipCallbackParser |= pair.getSecond();
10777062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            }
10787062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10797062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            count = binding.getFooterCount();
10808a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                            for (int i = 0; i < count; i++) {
10817062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
10827062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                        binding.getFooterAt(i),
1083b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                        list, false, skipCallbackParser);
10847062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                if (pair.getFirst() != null) {
10857062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                    list.addFooterView(pair.getFirst());
10867062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                }
10877062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10887062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                skipCallbackParser |= pair.getSecond();
10897062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            }
10907062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        }
10917062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
10927062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        if (view instanceof ExpandableListView) {
10937062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            ((ExpandableListView) view).setAdapter(
1094b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                    new FakeExpandableAdapter(listRef, binding, layoutlibCallback));
10957062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        } else {
10967062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            ((AbsListView) view).setAdapter(
1097b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                    new FakeAdapter(listRef, binding, layoutlibCallback));
10987062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        }
10997062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                    } else if (view instanceof AbsSpinner) {
11007062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        ((AbsSpinner) view).setAdapter(
1101b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                new FakeAdapter(listRef, binding, layoutlibCallback));
11027062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                    }
11037062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                }
11047062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            }
11053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } else if (view instanceof ViewGroup) {
11069028fa93da0f9c7dad2176de347cd6e705084c9fDeepanshu Gupta            mInflater.postInflateProcess(view);
11078a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            ViewGroup group = (ViewGroup) view;
11083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            final int count = group.getChildCount();
11098a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            for (int c = 0; c < count; c++) {
11103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                View child = group.getChildAt(c);
1111b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                postInflateProcess(child, layoutlibCallback, skip);
11123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
11133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1117c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     * If the root layout is a CoordinatorLayout with an AppBar:
1118c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     * Set the title of the AppBar to the title of the activity context.
1119c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     */
1120c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
1121c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
1122c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (coordinatorLayout == null) {
1123c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1124c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1125c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
1126c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (appBar == null) {
1127c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1128c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1129c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup collapsingToolbar =
1130c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
1131c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (collapsingToolbar == null) {
1132c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1133c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1134c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!hasToolbar(collapsingToolbar)) {
1135c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1136c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1137c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        RenderResources res = context.getRenderResources();
1138c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        String title = params.getAppLabel();
1139c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ResourceValue titleValue = res.findResValue(title, false);
1140c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (titleValue != null && titleValue.getValue() != null) {
1141c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            title = titleValue.getValue();
1142c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1143c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        DesignLibUtil.setTitle(collapsingToolbar, title);
1144c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1145c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1146c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    private View findChildView(View view, String className) {
1147c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
1148c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return null;
1149c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1150c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
1151c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
1152c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), className)) {
1153c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                return group.getChildAt(i);
1154c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1155c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1156c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        return null;
1157c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1158c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1159c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    private boolean hasToolbar(View collapsingToolbar) {
1160c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!(collapsingToolbar instanceof ViewGroup)) {
1161c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return false;
1162c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1163c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup group = (ViewGroup) collapsingToolbar;
1164c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
1165c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
1166c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                return true;
1167c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1168c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1169c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        return false;
1170c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1171c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1172c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    /**
1173777163c3facaed668b43061d726a572fd58f6f60Diego Perez     * Set the scroll position on all the components with the "scrollX" and "scrollY" attribute. If
1174777163c3facaed668b43061d726a572fd58f6f60Diego Perez     * the component supports nested scrolling attempt that first, then use the unconsumed scroll
1175777163c3facaed668b43061d726a572fd58f6f60Diego Perez     * part to scroll the content in the component.
1176c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     */
11770685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez    private static void handleScrolling(BridgeContext context, View view) {
1178777163c3facaed668b43061d726a572fd58f6f60Diego Perez        int scrollPosX = context.getScrollXPos(view);
1179777163c3facaed668b43061d726a572fd58f6f60Diego Perez        int scrollPosY = context.getScrollYPos(view);
1180777163c3facaed668b43061d726a572fd58f6f60Diego Perez        if (scrollPosX != 0 || scrollPosY != 0) {
1181c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            if (view.isNestedScrollingEnabled()) {
1182c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                int[] consumed = new int[2];
1183777163c3facaed668b43061d726a572fd58f6f60Diego Perez                int axis = scrollPosX != 0 ? View.SCROLL_AXIS_HORIZONTAL : 0;
1184777163c3facaed668b43061d726a572fd58f6f60Diego Perez                axis |= scrollPosY != 0 ? View.SCROLL_AXIS_VERTICAL : 0;
1185777163c3facaed668b43061d726a572fd58f6f60Diego Perez                if (view.startNestedScroll(axis)) {
1186777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    view.dispatchNestedPreScroll(scrollPosX, scrollPosY, consumed, null);
1187777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    view.dispatchNestedScroll(consumed[0], consumed[1], scrollPosX, scrollPosY,
1188777163c3facaed668b43061d726a572fd58f6f60Diego Perez                            null);
1189c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                    view.stopNestedScroll();
1190777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    scrollPosX -= consumed[0];
1191777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    scrollPosY -= consumed[1];
1192c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                }
1193c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1194777163c3facaed668b43061d726a572fd58f6f60Diego Perez            if (scrollPosX != 0 || scrollPosY != 0) {
11950685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez                view.scrollTo(scrollPosX, scrollPosY);
1196c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1197c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1198c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1199c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
1200c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1201c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1202c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
1203c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
1204c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            View child = group.getChildAt(i);
12050685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez            handleScrolling(context, child);
1206c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1207c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1208c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1209c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    /**
12103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Sets up a {@link TabHost} object.
12113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param tabHost the TabHost to setup.
1212b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta     * @param layoutlibCallback The project callback object to access the project R class.
1213bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez     * @throws PostInflateException if TabHost is missing the required ids for TabHost
12143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
1215b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta    private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback)
12163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
12173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
12183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
12193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
12213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
12223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
12233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1225952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!(v instanceof TabWidget)) {
12263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
12273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
12283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
12293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
12323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
1234952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
1235952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            //noinspection SpellCheckingInspection
12363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
12373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
12383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1240952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!(v instanceof FrameLayout)) {
1241952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            //noinspection SpellCheckingInspection
12423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
12433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
12443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
12453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
12483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1249952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        // now process the content of the frameLayout and dynamically create tabs for it.
12503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        final int count = content.getChildCount();
12513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
12533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // and FrameLayout.
12543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        tabHost.setup();
12553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1256f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        if (count == 0) {
1257f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            // Create a dummy child to get a single tab
12586257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta            TabSpec spec = tabHost.newTabSpec("tag")
12596257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta                    .setIndicator("Tab Label", tabHost.getResources()
12606257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta                            .getDrawable(android.R.drawable.ic_menu_info_details, null))
1261bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez                    .setContent(tag -> new LinearLayout(getContext()));
1262f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            tabHost.addTab(spec);
1263f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        } else {
1264952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            // for each child of the frameLayout, add a new TabSpec
1265f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            for (int i = 0 ; i < count ; i++) {
1266f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                View child = content.getChildAt(i);
1267f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
12688a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                @SuppressWarnings("ConstantConditions")  // child cannot be null.
1269f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                int id = child.getId();
1270952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                @SuppressWarnings("deprecation")
1271b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                Pair<ResourceType, String> resource = layoutlibCallback.resolveResourceId(id);
1272f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String name;
1273f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                if (resource != null) {
1274947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                    name = resource.getSecond();
1275f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                } else {
1276f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1277f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                }
1278f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
12793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
12803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
12823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
128385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    /**
128485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
128585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * bounds of all the views.
128685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
128785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param view the root View
1288e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * @param hOffset horizontal offset for the view bounds.
1289e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * @param vOffset vertical offset for the view bounds.
129085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
129185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
129285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *                       content frame.
129385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
129485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
129585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     */
1296e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez    private ViewInfo visit(View view, int hOffset, int vOffset, boolean setExtendedInfo,
129785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            boolean isContentFrame) {
1298e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez        ViewInfo result = createViewInfo(view, hOffset, vOffset, setExtendedInfo, isContentFrame);
1299799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
130085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (view instanceof ViewGroup) {
130185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            ViewGroup group = ((ViewGroup) view);
1302e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez            result.setChildren(visitAllChildren(group, isContentFrame ? 0 : hOffset,
1303e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                    isContentFrame ? 0 : vOffset,
130485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                    setExtendedInfo, isContentFrame));
130585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
130685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        return result;
130785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
1308799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
130985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    /**
131085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
13118d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with
131285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * the children of the {@code mContentRoot}.
131385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
131485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param viewGroup the root View
1315e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * @param hOffset horizontal offset from the top for the content view frame.
1316e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * @param vOffset vertical offset from the top for the content view frame.
131785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
131885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
131985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *                       content frame. {@code false} if the {@code ViewInfo} to be created is
132085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *                       part of the system decor.
132185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     */
1322e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int hOffset, int vOffset,
132385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            boolean setExtendedInfo, boolean isContentFrame) {
132485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (viewGroup == null) {
132585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return null;
1326799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet        }
1327799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
132885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (!isContentFrame) {
1329e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez            vOffset += viewGroup.getTop();
1330e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez            hOffset += viewGroup.getLeft();
133185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
1332799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
133385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        int childCount = viewGroup.getChildCount();
133485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (viewGroup == mContentRoot) {
1335bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez            List<ViewInfo> childrenWithoutOffset = new ArrayList<>(childCount);
1336bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez            List<ViewInfo> childrenWithOffset = new ArrayList<>(childCount);
133785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            for (int i = 0; i < childCount; i++) {
1338e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                ViewInfo[] childViewInfo =
1339e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                        visitContentRoot(viewGroup.getChildAt(i), hOffset, vOffset,
13406208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                        setExtendedInfo);
134185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                childrenWithoutOffset.add(childViewInfo[0]);
134285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                childrenWithOffset.add(childViewInfo[1]);
1343799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet            }
134485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            mViewInfoList = childrenWithOffset;
134585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return childrenWithoutOffset;
134685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        } else {
1347bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez            List<ViewInfo> children = new ArrayList<>(childCount);
134885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            for (int i = 0; i < childCount; i++) {
1349e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                children.add(visit(viewGroup.getChildAt(i), hOffset, vOffset, setExtendedInfo,
135085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                        isContentFrame));
135185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            }
135285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return children;
1353799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet        }
135485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
1355799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
135685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    /**
135785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
135885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
135985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * one with the {@code offset} and other without the {@code offset}. The offset is needed to
136085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * get the right bounds if the {@code ViewInfo} hierarchy is accessed from
136185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
136285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * offset is not needed.
136385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
136485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
136585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *         index 1 is with the offset.
136685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     */
1367432578acb80cf2fa827ddb9595cf46edf0b340b0Deepanshu Gupta    @NonNull
1368e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez    private ViewInfo[] visitContentRoot(View view, int hOffset, int vOffset,
1369e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez            boolean setExtendedInfo) {
137085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        ViewInfo[] result = new ViewInfo[2];
137185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (view == null) {
137285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return result;
137385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
137485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta
1375e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez        result[0] = createViewInfo(view, 0, 0, setExtendedInfo, true);
1376e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez        result[1] = createViewInfo(view, hOffset, vOffset, setExtendedInfo, true);
137785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (view instanceof ViewGroup) {
1378e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez            List<ViewInfo> children =
1379e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                    visitAllChildren((ViewGroup) view, 0, 0, setExtendedInfo, true);
138085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            result[0].setChildren(children);
138185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            result[1].setChildren(children);
138285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
138385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        return result;
1384799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    }
13853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
13863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
138785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
138885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
138985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * set.
1390e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * @param hOffset horizontal offset for the view bounds. Used only if view is part of the
1391e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * content frame.
1392e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * @param vOffset vertial an offset for the view bounds. Used only if view is part of the
1393e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez     * content frame.
13943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
1395e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez    private ViewInfo createViewInfo(View view, int hOffset, int vOffset, boolean setExtendedInfo,
139685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            boolean isContentFrame) {
13973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view == null) {
13983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            return null;
13993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
14003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1401777163c3facaed668b43061d726a572fd58f6f60Diego Perez        ViewParent parent = view.getParent();
140285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        ViewInfo result;
140385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (isContentFrame) {
1404777163c3facaed668b43061d726a572fd58f6f60Diego Perez            // Account for parent scroll values when calculating the bounding box
1405777163c3facaed668b43061d726a572fd58f6f60Diego Perez            int scrollX = parent != null ? ((View)parent).getScrollX() : 0;
1406777163c3facaed668b43061d726a572fd58f6f60Diego Perez            int scrollY = parent != null ? ((View)parent).getScrollY() : 0;
1407777163c3facaed668b43061d726a572fd58f6f60Diego Perez
140870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // The view is part of the layout added by the user. Hence,
140970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // the ViewCookie may be obtained only through the Context.
141085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            result = new ViewInfo(view.getClass().getName(),
1411e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                    getContext().getViewKey(view), -scrollX + view.getLeft() + hOffset,
1412e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                    -scrollY + view.getTop() + vOffset, -scrollX + view.getRight() + hOffset,
1413e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez                    -scrollY + view.getBottom() + vOffset,
1414777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    view, view.getLayoutParams());
141585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        } else {
141670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // We are part of the system decor.
141770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
141841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta                    getViewKey(view),
141985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                    view.getLeft(), view.getTop(), view.getRight(),
142085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                    view.getBottom(), view, view.getLayoutParams());
142170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            result = r;
142270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // We currently mark three kinds of views:
142370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // 1. Menus in the Action Bar
142470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // 2. Menus in the Overflow popup.
142570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // 3. The overflow popup button.
142670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            if (view instanceof ListMenuItemView) {
142770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                // Mark 2.
142870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                // All menus in the popup are of type ListMenuItemView.
142970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                r.setViewType(ViewType.ACTION_BAR_OVERFLOW_MENU);
143070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            } else {
143170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                // Mark 3.
143270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                ViewGroup.LayoutParams lp = view.getLayoutParams();
143370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                if (lp instanceof ActionMenuView.LayoutParams &&
143470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        ((ActionMenuView.LayoutParams) lp).isOverflowButton) {
143570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    r.setViewType(ViewType.ACTION_BAR_OVERFLOW);
143670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                } else {
143770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // Mark 1.
143870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // A view is a menu in the Action Bar is it is not the overflow button and of
143970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // its parent is of type ActionMenuView. We can also check if the view is
144070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // instanceof ActionMenuItemView but that will fail for menus using
144170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // actionProviderClass.
144270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    while (parent != mViewRoot && parent instanceof ViewGroup) {
144370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        if (parent instanceof ActionMenuView) {
144470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                            r.setViewType(ViewType.ACTION_BAR_MENU);
144570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                            break;
144670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        }
144770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        parent = parent.getParent();
144870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    }
144970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                }
145070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            }
145185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
14523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
14536208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet        if (setExtendedInfo) {
14546208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            MarginLayoutParams marginParams = null;
14556208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            LayoutParams params = view.getLayoutParams();
14566208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            if (params instanceof MarginLayoutParams) {
14576208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                marginParams = (MarginLayoutParams) params;
14586208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            }
14596208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            result.setExtendedInfo(view.getBaseline(),
14606208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.leftMargin : 0,
14616208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.topMargin : 0,
14626208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.rightMargin : 0,
14636208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.bottomMargin : 0);
14646208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet        }
14656208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet
14663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return result;
14673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
14683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
146970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta    /* (non-Javadoc)
147041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta     * The cookie for menu items are stored in menu item and not in the map from View stored in
147141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta     * BridgeContext.
147241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta     */
1473432578acb80cf2fa827ddb9595cf46edf0b340b0Deepanshu Gupta    @Nullable
147441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta    private Object getViewKey(View view) {
147541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        BridgeContext context = getContext();
147641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        if (!(view instanceof MenuView.ItemView)) {
147741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            return context.getViewKey(view);
147841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        }
147941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        MenuItemImpl menuItem;
148041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        if (view instanceof ActionMenuItemView) {
148141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = ((ActionMenuItemView) view).getItemData();
148241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        } else if (view instanceof ListMenuItemView) {
148341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = ((ListMenuItemView) view).getItemData();
148441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        } else if (view instanceof IconMenuItemView) {
148541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = ((IconMenuItemView) view).getItemData();
148641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        } else {
148741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = null;
148841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        }
148941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        if (menuItem instanceof BridgeMenuItemImpl) {
149041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            return ((BridgeMenuItemImpl) menuItem).getViewCookie();
149141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        }
149241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta
149341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        return null;
149441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta    }
149541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta
1496620f80a7ee9796c2c41ec0a42d10d2913fc50c90Diego Perez    public void invalidateRenderingSize() {
149785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
149885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
149985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta
15003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    public BufferedImage getImage() {
15013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return mImage;
15023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
15033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1504a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    public boolean isAlphaChannelImage() {
1505a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return mIsAlphaChannelImage;
1506a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1507a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1508e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    public List<ViewInfo> getViewInfos() {
1509e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        return mViewInfoList;
15103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
15112d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet
151285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    public List<ViewInfo> getSystemViewInfos() {
151385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        return mSystemViewInfoList;
151485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
151585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta
151618be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta    public Map<Object, PropertiesMap> getDefaultProperties() {
151718be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta        return getContext().getDefaultProperties();
151818be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta    }
151918be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta
1520ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public void setScene(RenderSession session) {
1521ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mScene = session;
1522b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
1523b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1524ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSession getSession() {
1525b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        return mScene;
1526b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
152795eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez
152895eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez    public void dispose() {
1529e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        boolean createdLooper = false;
1530e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        if (Looper.myLooper() == null) {
1531e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            // Detaching the root view from the window will try to stop any running animations.
1532e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            // The stop method checks that it can run in the looper so, if there is no current
1533e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            // looper, we create a temporary one to complete the shutdown.
1534e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            Bridge.prepareThread();
1535e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            createdLooper = true;
1536e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        }
153795eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        AttachInfo_Accessor.detachFromWindow(mViewRoot);
153895eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        if (mCanvas != null) {
153995eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mCanvas.release();
154095eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mCanvas = null;
154195eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        }
154295eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        if (mViewInfoList != null) {
154395eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mViewInfoList.clear();
154495eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        }
154595eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        if (mSystemViewInfoList != null) {
154695eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mSystemViewInfoList.clear();
154795eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        }
154895eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        mImage = null;
154995eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        mViewRoot = null;
155095eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        mContentRoot = null;
1551e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez
1552e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        if (createdLooper) {
1553e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            Bridge.cleanupThread();
1554405d10472d7b8ba7ff86f46e734195128709a829Deepanshu Gupta            Choreographer_Delegate.dispose();
1555e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        }
155695eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez    }
15573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet}
1558