RenderSessionImpl.java revision 777163c3facaed668b43061d726a572fd58f6f60
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;
23b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutlibCallback;
240d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
25ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
267062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceReference;
27ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue;
28ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
29ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
30d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams;
31b32414fe256a6fe1d65e7a1443cd6ea77db8bd95Xavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams.RenderingMode;
32d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo;
3370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport com.android.ide.common.rendering.api.ViewType;
3441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.ActionMenuItemView;
3541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.BridgeMenuItemImpl;
3641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.IconMenuItemView;
3741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.ListMenuItemView;
3841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.MenuItemImpl;
3941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.MenuView;
40ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
42ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
44a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaevimport com.android.layoutlib.bridge.android.RenderParamsFlags;
45c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsenimport com.android.layoutlib.bridge.android.support.DesignLibUtil;
467062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeAdapter;
477062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
481b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohetimport com.android.resources.ResourceType;
49344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Guptaimport com.android.tools.layoutlib.java.System_Delegate;
50947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohetimport com.android.util.Pair;
513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
52994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.animation.AnimationThread;
5333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.Animator;
54ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.AnimatorInflater;
5533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.LayoutTransition;
5662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
57442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.NonNull;
58442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.Nullable;
593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate;
603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap;
613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas;
63e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perezimport android.os.Looper;
648a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Guptaimport android.preference.Preference_Delegate;
65994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.view.AttachInfo_Accessor;
66994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.view.BridgeInflater;
67344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Guptaimport android.view.Choreographer_Delegate;
6876f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohetimport android.view.IWindowManager;
6964f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohetimport android.view.IWindowManagerImpl;
7076f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohetimport android.view.Surface;
713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View;
723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec;
73d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport android.view.ViewGroup;
74ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport android.view.ViewGroup.LayoutParams;
756208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohetimport android.view.ViewGroup.MarginLayoutParams;
7670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport android.view.ViewParent;
7776f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohetimport android.view.WindowManagerGlobal_Delegate;
787062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AbsListView;
797062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AbsSpinner;
8070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport android.widget.ActionMenuView;
817062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AdapterView;
827062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.ExpandableListView;
833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout;
84f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.LinearLayout;
857062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.ListView;
8662c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohetimport android.widget.QuickContactBadge;
873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost;
88f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.TabHost.TabSpec;
89d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport android.widget.TabWidget;
903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
914c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohetimport java.awt.AlphaComposite;
923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color;
933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D;
943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage;
953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList;
963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List;
973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map;
983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
99b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
100b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
101b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
102b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
103b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
104b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
105baf88de1f5c435a788f6c38720354b2dbaa19e60Deepanshu Guptaimport static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
106b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta
1073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/**
108ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * Class implementing the render session.
109952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta * <p/>
110ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
111ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
1123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout.
1133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */
1140fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> {
1153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // scene state
117ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private RenderSession mScene;
1183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
1193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BridgeInflater mInflater;
120799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    private ViewGroup mViewRoot;
121799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    private FrameLayout mContentRoot;
1221392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private Canvas mCanvas;
1231392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1241392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet    private int mMeasuredScreenHeight = -1;
125799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    private boolean mIsAlphaChannelImage;
126344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    /** If >= 0, a frame will be executed */
127344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    private long mElapsedFrameTimeNanos = -1;
128344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    /** True if one frame has been already executed to start the animations */
129344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    private boolean mFirstFrameExecuted = false;
130a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    // information being returned through the API
1323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private BufferedImage mImage;
133e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    private List<ViewInfo> mViewInfoList;
13485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    private List<ViewInfo> mSystemViewInfoList;
1358b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta    private Layout.Builder mLayoutBuilder;
1363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    private static final class PostInflateException extends Exception {
1383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        private static final long serialVersionUID = 1L;
1393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        public PostInflateException(String message) {
1413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            super(message);
1423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
1433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
1443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
1473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
1488d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)},
1498d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * which act as a
150ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
1513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     *
1528d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * @see Bridge#createSession(SessionParams)
1533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
154b32414fe256a6fe1d65e7a1443cd6ea77db8bd95Xavier Ducrohet    public RenderSessionImpl(SessionParams params) {
1550fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        super(new SessionParams(params));
156ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
157ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
158ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
159ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
160ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * inflater, and parser.
161ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
162ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
163ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
164ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @return whether the scene was prepared
165ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
166ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #acquire(long)
167ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @see #release()
168ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
1690fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet    @Override
170ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result init(long timeout) {
1710fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        Result result = super.init(timeout);
172952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
173ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            return result;
174ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
1753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1760fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        SessionParams params = getParams();
1770fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        BridgeContext context = getContext();
1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
179a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        // use default of true in case it's not found to use alpha by default
180300f4893351a9974fa3380c513b29d4a7883cd74Deepanshu Gupta        mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(),
181300f4893351a9974fa3380c513b29d4a7883cd74Deepanshu Gupta                "windowIsFloating", true, true);
182ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
1838b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta        mLayoutBuilder = new Layout.Builder(params, context);
1843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
18576f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        // FIXME: find those out, and possibly add them to the render params
18676f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        boolean hasNavigationBar = true;
187952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        //noinspection ConstantConditions
18876f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
1898b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta                context.getMetrics(), Surface.ROTATION_0, hasNavigationBar);
19076f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet        WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
19176f4c3e91d8579a580569c3d079da99511309727Xavier Ducrohet
1923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // build the inflater and parser.
193b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta        mInflater = new BridgeInflater(context, params.getLayoutlibCallback());
1940fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        context.setBridgeInflater(mInflater);
195ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
1968b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false);
197ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
1983054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet        return SUCCESS.createResult();
1993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
2023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Inflates the layout.
2033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
204ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
205ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
206ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
207ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
2083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
209ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result inflate() {
210ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
211ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
2123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
2138b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta            mViewRoot = new Layout(mLayoutBuilder);
2148b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta            mLayoutBuilder = null;  // Done with the builder.
2158b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta            mContentRoot = ((Layout) mViewRoot).getContentRoot();
2160fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            SessionParams params = getParams();
2170fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            BridgeContext context = getContext();
2183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
2203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // it can instantiate the custom Fragment.
221b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback());
2223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
223a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaev            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
2248a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            boolean isPreference = "PreferenceScreen".equals(rootTag);
2258a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            View view;
2268a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            if (isPreference) {
2278a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                view = Preference_Delegate.inflatePreference(getContext(), mBlockParser,
2288b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta                        mContentRoot);
2298a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            } else {
2308a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                view = mInflater.inflate(mBlockParser, mContentRoot);
2318a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            }
2323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2337062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            // done with the parser, pop it.
2347062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            context.popParser();
2357062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
236b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(null);
2373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // set the AttachInfo on the root view.
239994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohet            AttachInfo_Accessor.setAttachInfo(mViewRoot);
2403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
241a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
242b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
2439028fa93da0f9c7dad2176de347cd6e705084c9fDeepanshu Gupta            mInflater.onDoneInflation();
244a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet
245c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            setActiveToolbar(view, context, params);
246c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
247ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
2483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (PostInflateException e) {
249ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
2503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
2513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
2523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
2533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
2543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
2553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
2563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
257ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
2583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
2593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
2603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
262344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta     * Sets the time for which the next frame will be selected. The time is the elapsed time from
263344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta     * the current system nanos time. You
264344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta     */
265344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    public void setElapsedFrameTimeNanos(long nanos) {
266344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta        mElapsedFrameTimeNanos = nanos;
267344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    }
268344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta
269344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta    /**
2703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Renders the scene.
2713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * <p>
272ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
273ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
2744c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
2754c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
2764c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *      animations.)
2774c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet     *
278ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
279ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
2801392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet     *
2818d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * @see SessionParams#getRenderingMode()
282799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#render(long)
2833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
2844c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet    public Result render(boolean freshRender) {
285ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
286ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
2870fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        SessionParams params = getParams();
2880fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet
2893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        try {
2903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            if (mViewRoot == null) {
291ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
2923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
2933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
2940fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            RenderingMode renderingMode = params.getRenderingMode();
29564f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet            HardwareConfig hardwareConfig = params.getHardwareConfig();
296e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet
2971392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // only do the screen measure when needed.
2981392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            boolean newRenderSize = false;
2991392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
3001392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                newRenderSize = true;
30164f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet                mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
30264f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet                mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
3031392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
3041392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
3058ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
3068ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
3078ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            : MeasureSpec.EXACTLY;
3088ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    int heightMeasureSpecMode = renderingMode.isVertExpand() ?
3098ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
3108ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            : MeasureSpec.EXACTLY;
3118ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
3128ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // We used to compare the measured size of the content to the screen size but
3138ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // this does not work anymore due to the 2 following issues:
3148ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // - If the content is in a decor (system bar, title/action bar), the root view
3158ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    //   will not resize even with the UNSPECIFIED because of the embedded layout.
3168ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // - If there is no decor, but a dialog frame, then the dialog padding prevents
3178ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    //   comparing the size of the content to the screen frame (as it would not
3188ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    //   take into account the dialog padding).
3198ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
3208ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // The solution is to first get the content size in a normal rendering, inside
3218ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // the decor or the dialog padding.
3228ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // Then measure only the content with UNSPECIFIED to see the size difference
3238ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // and apply this to the screen size.
3248ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
3258ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // first measure the full layout, with EXACTLY to get the size of the
3268ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // content as it is inside the decor/dialog
327952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                    @SuppressWarnings("deprecation")
3288ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    Pair<Integer, Integer> exactMeasure = measureView(
3298ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mViewRoot, mContentRoot.getChildAt(0),
3308ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mMeasuredScreenWidth, MeasureSpec.EXACTLY,
3318ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mMeasuredScreenHeight, MeasureSpec.EXACTLY);
3328ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
3338ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // now measure the content only using UNSPECIFIED (where applicable, based on
3348ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // the rendering mode). This will give us the size the content needs.
335952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                    @SuppressWarnings("deprecation")
3368ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    Pair<Integer, Integer> result = measureView(
3378ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mContentRoot, mContentRoot.getChildAt(0),
3388ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mMeasuredScreenWidth, widthMeasureSpecMode,
3398ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mMeasuredScreenHeight, heightMeasureSpecMode);
3408ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
3418ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    // now look at the difference and add what is needed.
3421392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
3438ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                        int measuredWidth = exactMeasure.getFirst();
3448ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                        int neededWidth = result.getFirst();
3458ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                        if (neededWidth > measuredWidth) {
3468ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mMeasuredScreenWidth += neededWidth - measuredWidth;
3471392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
34892d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                        if (mMeasuredScreenWidth < measuredWidth) {
34992d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                            // If the screen width is less than the exact measured width,
35092d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                            // expand to match.
35192d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                            mMeasuredScreenWidth = measuredWidth;
35292d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                        }
353e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3551392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    if (renderingMode.isVertExpand()) {
3568ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                        int measuredHeight = exactMeasure.getSecond();
3578ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                        int neededHeight = result.getSecond();
3588ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                        if (neededHeight > measuredHeight) {
3598ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                            mMeasuredScreenHeight += neededHeight - measuredHeight;
3601392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                        }
36192d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                        if (mMeasuredScreenHeight < measuredHeight) {
36292d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                            // If the screen height is less than the exact measured height,
36392d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                            // expand to match.
36492d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                            mMeasuredScreenHeight = measuredHeight;
36592d9c3fa220868d6641b5831b24a0a72af7c6751Diego Perez                        }
366e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet                    }
3673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                }
3683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
3693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3708ae691c1148038995d1185716f629b82c582897fXavier Ducrohet            // measure again with the size we need
3713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // This must always be done before the call to layout
3728ae691c1148038995d1185716f629b82c582897fXavier Ducrohet            measureView(mViewRoot, null /*measuredView*/,
3738ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
3748ae691c1148038995d1185716f629b82c582897fXavier Ducrohet                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
3753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
3763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // now do the layout.
377a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
379c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            handleScrolling(mViewRoot);
380c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
381f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet            if (params.isLayoutOnly()) {
382f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                // delete the canvas and image to reset them on the next full rendering
383f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                mImage = null;
384f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                mCanvas = null;
385f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet            } else {
386994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohet                AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot);
387f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet
388f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                // draw the views
389f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                // create the BufferedImage into which the layout will be rendered.
390f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                boolean newImage = false;
391e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez
392e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // When disableBitmapCaching is true, we do not reuse mImage and
393e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // we create a new one in every render.
394e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // This is useful when mImage is just a wrapper of Graphics2D so
395e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                // it doesn't get cached.
396e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
397a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaev                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
398e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                if (newRenderSize || mCanvas == null || disableBitmapCaching) {
399f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    if (params.getImageFactory() != null) {
400f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        mImage = params.getImageFactory().getImage(
401f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenWidth,
402f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenHeight);
403f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    } else {
404f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        mImage = new BufferedImage(
405f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenWidth,
406f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                mMeasuredScreenHeight,
407f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                                BufferedImage.TYPE_INT_ARGB);
408f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        newImage = true;
409f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    }
410f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet
411f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    if (params.isBgColorOverridden()) {
412f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        // since we override the content, it's the same as if it was a new image.
413f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        newImage = true;
414f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        Graphics2D gc = mImage.createGraphics();
415f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.setColor(new Color(params.getOverrideBgColor(), true));
416f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.setComposite(AlphaComposite.Src);
417f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
418f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                        gc.dispose();
419f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    }
420f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet
421f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    // create an Android bitmap around the BufferedImage
422f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
42364f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet                            true /*isMutable*/, hardwareConfig.getDensity());
424f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet
425e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                    if (mCanvas == null) {
426e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                        // create a Canvas around the Android bitmap
427e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                        mCanvas = new Canvas(bitmap);
428e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                    } else {
429e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                        mCanvas.setBitmap(bitmap);
430e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez                    }
43164f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
4321392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                }
4333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
434952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                if (freshRender && !newImage) {
4351392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
4364c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
4373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
438f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    gc.setColor(new Color(0x00000000, true));
439f4978e031c3ad565f02d5a4c65f87ae4477f3613Deepanshu Gupta                    gc.fillRect(0, 0,
440f4978e031c3ad565f02d5a4c65f87ae4477f3613Deepanshu Gupta                            mMeasuredScreenWidth, mMeasuredScreenHeight);
441a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
442f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    // done
443f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                    gc.dispose();
444f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                }
445a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
446344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                if (mElapsedFrameTimeNanos >= 0) {
447344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    long initialTime = System_Delegate.nanoTime();
448344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    if (!mFirstFrameExecuted) {
449344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                        // The first frame will initialize the animations
450344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                        Choreographer_Delegate.doFrame(initialTime);
451344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                        mFirstFrameExecuted = true;
452344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    }
453344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    // Second frame will move the animations
454344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                    Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
455344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta                }
456f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet                mViewRoot.draw(mCanvas);
4574c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet            }
4584c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet
45941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
46041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta                    false);
4613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // success!
463ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
4643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } catch (Throwable e) {
4653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            // get the real cause of the exception.
4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            Throwable t = e;
4673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            while (t.getCause() != null) {
4683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                t = t.getCause();
4693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
4703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
471ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
4723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
4733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
4743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
4753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
4768ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
4778ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
4788ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     *
4798ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
4808ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
4818ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     *
4828ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param viewToMeasure the view on which to execute measure().
4838ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param measuredView if non null, the view to query for its measured width/height.
4848ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param width the width to use in the MeasureSpec.
4858ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param widthMode the MeasureSpec mode to use for the width.
4868ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param height the height to use in the MeasureSpec.
4878ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @param heightMode the MeasureSpec mode to use for the height.
4888ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     * @return the measured width/height if measuredView is non-null, null otherwise.
4898ae691c1148038995d1185716f629b82c582897fXavier Ducrohet     */
490952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
4918ae691c1148038995d1185716f629b82c582897fXavier Ducrohet    private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
4928ae691c1148038995d1185716f629b82c582897fXavier Ducrohet            int width, int widthMode, int height, int heightMode) {
4938ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
4948ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
4958ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        viewToMeasure.measure(w_spec, h_spec);
4968ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
4978ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        if (measuredView != null) {
4988ae691c1148038995d1185716f629b82c582897fXavier Ducrohet            return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight());
4998ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        }
5008ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
5018ae691c1148038995d1185716f629b82c582897fXavier Ducrohet        return null;
5028ae691c1148038995d1185716f629b82c582897fXavier Ducrohet    }
5038ae691c1148038995d1185716f629b82c582897fXavier Ducrohet
5048ae691c1148038995d1185716f629b82c582897fXavier Ducrohet    /**
505ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * Animate an object
506ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * <p>
507ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
508ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *
509ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
510ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
51133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
512799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
513ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet     */
514ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
515ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
516ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        checkLock();
517ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
5180fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        BridgeContext context = getContext();
5190fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet
520ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        // find the animation file.
521952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        ResourceValue animationResource;
522ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        int animationId = 0;
523ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (isFrameworkAnimation) {
5240fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            animationResource = context.getRenderResources().getFrameworkResource(
5251b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
526ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
527947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
528ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
529ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        } else {
5300fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet            animationResource = context.getRenderResources().getProjectResource(
5311b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
532ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            if (animationResource != null) {
533b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                animationId = context.getLayoutlibCallback().getResourceId(
5341b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
535ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
536ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
537ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
538ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        if (animationResource != null) {
539ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            try {
5400fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(context, animationId);
541ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                if (anim != null) {
542ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                    anim.setTarget(targetObject);
543ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
54433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
545ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
546ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                    return SUCCESS.createResult();
547ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet                }
548ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            } catch (Exception e) {
549b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                // get the real cause of the exception.
550b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                Throwable t = e;
551b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                while (t.getCause() != null) {
552b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                    t = t.getCause();
553b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet                }
554b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
555ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
556ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet            }
557ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet        }
558ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
559ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
560b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
561b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
56233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
56333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Insert a new child into an existing parent.
56433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
56533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
56633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
56733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
56833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
56933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
570799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
57133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
572ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
57333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final int index, IAnimationListener listener) {
574b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
575b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
5760fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        BridgeContext context = getContext();
5770fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet
578b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // create a block parser for the XML
579a732a0101ad07b28e828bbbc8fb81be0580d53b5Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
580a732a0101ad07b28e828bbbc8fb81be0580d53b5Xavier Ducrohet                childXml, context, false /* platformResourceFlag */);
581b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
582b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
583b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
584b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        // be created correctly.
58533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
586a732a0101ad07b28e828bbbc8fb81be0580d53b5Xavier Ducrohet        blockParser.ensurePopped();
587b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
58833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
58933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
59033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
59133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
59233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
59333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
594ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
59533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
59633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return addView(parentView, child, index);
59733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
59833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
59933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
60033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
60133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parentView.setLayoutTransition(null);
60233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
60333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
60433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
60533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
606ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(child);
6071392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        }
6081392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
60933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        // add it to the parentView in the correct location
610ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = addView(parentView, child, index);
611952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
61233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
61333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
614b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
6154c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
6161766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        if (result.isSuccess()) {
61733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(child);
6181766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        }
6191766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet
6201766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet        return result;
621b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
622b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
62333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
62433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Adds a given view to a given parent at a given index.
62533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
62633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param parent the parent to receive the view
62733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to add to the parent
62833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the index where to do the add.
62933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
630ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
631ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
63233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
63333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
634ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
63533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
63633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.addView(view, index);
637ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
63833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
63933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
640ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
64133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
64233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
64333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
64433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
64533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a view to a new parent at a given location
64633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
64733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
64833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
64933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
65033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
65133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
652799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
65333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
65462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
65524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
656b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        checkLock();
657b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
65833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        invalidateRenderingSize();
65933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
660ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        LayoutParams layoutParams = null;
66133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (layoutParamsMap != null) {
66233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
66362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
66433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
66533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
6661392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
66762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        // get the current parent of the view that needs to be moved.
66862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
66962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
67033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
67133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            final LayoutParams params = layoutParams;
672ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
67324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
67424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
67524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousParent != newParentView) {
67624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new Thread("not animated moveChild") {
67724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
67824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void run() {
67924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
68024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                params);
681952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                        if (!result.isSuccess()) {
68224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
68324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
68424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
68524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // ready to do the work, acquire the scene.
68624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        result = acquire(250);
687952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                        if (!result.isSuccess()) {
68824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            listener.done(result);
68924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            return;
69024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
69124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
69224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        try {
6934c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet                            result = render(false /*freshRender*/);
69424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            if (result.isSuccess()) {
69524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
69624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            }
69724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        } finally {
69824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            release();
69924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
70024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
70124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        listener.done(result);
70262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
70324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
70424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            } else {
70524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
70662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
70724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
70824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public Result preAnimation() {
70924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // set up the transition for the parent.
71024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
71124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(transition);
7125562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet
71324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
71424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // animation playing just before).
71524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
71624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // on the LayoutTransition.
71724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
71824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
71924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
720ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
72124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
72224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
72324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
72424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
72524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
72624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
72724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
72824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
72924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
73024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
73124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
73224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    @Override
73324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    public void postAnimation() {
73424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        previousParent.setLayoutTransition(null);
73524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        newParentView.setLayoutTransition(null);
73624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    }
73724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                }.start();
73824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            }
73933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
74033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
741ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
742b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
743b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
74462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
745952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
74633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
74733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
748b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
7494c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        result = render(false /*freshRender*/);
750ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
75133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
752ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        }
753ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet
754ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet        return result;
755b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
756b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
75733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
75833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
75933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * an optional new {@link LayoutParams} instance
76033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
76162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
76262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet     * @param newParent the new parent
76324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet     * @param movedView the view to move
76433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param index the new location in the new parent
76533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
76633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
767ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
768ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
76933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
77033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
77124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
77224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
7731392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        try {
77462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            // check if there is a transition on the previousParent.
77524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
77624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet            if (previousTransition != null) {
7775562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
7785562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
7795562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
7805562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
7815562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // to handle).
7825562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
7835562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
7845562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // adding the child or the child will appear in its new location before the
7855562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet                // other children have made room for it.
78662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
78762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
78824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
78924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    private int mChangeDisappearingCount = 0;
79062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
791d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohet                    @Override
79262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
79362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
79424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
79524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount++;
79624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
79762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
79833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
799d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohet                    @Override
80062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
80162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            View view, int transitionType) {
80224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
80324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                            mChangeDisappearingCount--;
80424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        }
80524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet
80624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
80724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                mChangeDisappearingCount == 0) {
80862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            // add it to the parentView in the correct location
80962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            if (params != null) {
81024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index, params);
81162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            } else {
81224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                                newParent.addView(movedView, index);
81362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                            }
81462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                        }
81562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                    }
81662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                });
81762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
81862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // remove the view from the current parent.
81924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
82062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
82162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
82262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
82333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            } else {
82462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // standard code with no animation. pretty simple.
82524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                previousParent.removeView(movedView);
82633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
82762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                // add it to the parentView in the correct location
82862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                if (params != null) {
82924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index, params);
83062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                } else {
83124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet                    newParent.addView(movedView, index);
83262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                }
83362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet
83462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet                return SUCCESS.createResult();
83562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet            }
8361392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        } catch (UnsupportedOperationException e) {
8371392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
838ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
839b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        }
84033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
84133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
84233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    /**
84333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a child from its current parent.
84433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * <p>
84533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
84633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
84733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
84833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
84933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
850799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet     * @see RenderSession#removeChild(Object, IAnimationListener)
85133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
852ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
85333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        checkLock();
854b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
8551392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet        invalidateRenderingSize();
8561392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet
85733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
85833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
85933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        if (listener != null) {
86033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
86133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
86233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
863ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet                public Result preAnimation() {
86433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
86533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    return removeView(parent, childView);
86633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
86733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
86833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                @Override
86933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                public void postAnimation() {
87033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                    parent.setLayoutTransition(null);
87133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet                }
87233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            }.start();
87333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
87433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // always return success since the real status will come through the listener.
875ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
87633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
87733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
878ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        Result result = removeView(parent, childView);
879952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!result.isSuccess()) {
88033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            return result;
88133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
88233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
8834c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet        return render(false /*freshRender*/);
884ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    }
885ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet
886ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet    /**
88733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * Removes a given view from its current parent.
88833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
88933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     * @param view the view to remove from its parent
89033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *
891ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
892ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
89333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     *     adding views.
89433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet     */
895ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
89633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        try {
89733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            parent.removeView(view);
898ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return SUCCESS.createResult();
89933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        } catch (UnsupportedOperationException e) {
90033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
901ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
90233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet        }
90333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet    }
90433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet
9053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
906952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta     * Post process on a view hierarchy that was just inflated.
907952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta     * <p/>
908952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta     * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
9093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
9103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
9113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param view the root view to process.
912b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta     * @param layoutlibCallback callback to the project.
9138a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta     * @param skip the view and it's children are not processed.
9143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
915952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
916b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta    private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip)
9173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
9188a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta        if (view == skip) {
9198a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            return;
9208a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta        }
9213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view instanceof TabHost) {
922b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta            setupTabHost((TabHost) view, layoutlibCallback);
92362c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
92462c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
92562c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet            badge.setImageToDefault();
9267062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet        } else if (view instanceof AdapterView<?>) {
9277062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            // get the view ID.
9287062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            int id = view.getId();
9297062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9307062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            BridgeContext context = getContext();
9317062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9327062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            // get a ResourceReference from the integer ID.
9337062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            ResourceReference listRef = context.resolveId(id);
9347062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9357062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            if (listRef != null) {
9367062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                SessionParams params = getParams();
9377062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                AdapterBinding binding = params.getAdapterBindings().get(listRef);
9387062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9397062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                // if there was no adapter binding, trying to get it from the call back.
9407062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                if (binding == null) {
941b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                    binding = layoutlibCallback.getAdapterBinding(
942b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                            listRef, context.getViewKey(view), view);
9437062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                }
9447062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9457062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                if (binding != null) {
9467062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9477062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                    if (view instanceof AbsListView) {
9487062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) &&
9497062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                view instanceof ListView) {
9507062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            ListView list = (ListView) view;
9517062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9527062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            boolean skipCallbackParser = false;
9537062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9547062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            int count = binding.getHeaderCount();
9558a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                            for (int i = 0; i < count; i++) {
9567062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
9577062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                        binding.getHeaderAt(i),
958b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                        list, false, skipCallbackParser);
9597062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                if (pair.getFirst() != null) {
9607062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                    list.addHeaderView(pair.getFirst());
9617062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                }
9627062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9637062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                skipCallbackParser |= pair.getSecond();
9647062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            }
9657062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9667062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            count = binding.getFooterCount();
9678a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                            for (int i = 0; i < count; i++) {
9687062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
9697062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                        binding.getFooterAt(i),
970b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                        list, false, skipCallbackParser);
9717062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                if (pair.getFirst() != null) {
9727062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                    list.addFooterView(pair.getFirst());
9737062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                }
9747062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9757062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                                skipCallbackParser |= pair.getSecond();
9767062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            }
9777062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        }
9787062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet
9797062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        if (view instanceof ExpandableListView) {
9807062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            ((ExpandableListView) view).setAdapter(
981b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                    new FakeExpandableAdapter(listRef, binding, layoutlibCallback));
9827062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        } else {
9837062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                            ((AbsListView) view).setAdapter(
984b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                    new FakeAdapter(listRef, binding, layoutlibCallback));
9857062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        }
9867062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                    } else if (view instanceof AbsSpinner) {
9877062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                        ((AbsSpinner) view).setAdapter(
988b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                                new FakeAdapter(listRef, binding, layoutlibCallback));
9897062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                    }
9907062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet                }
9917062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet            }
9923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        } else if (view instanceof ViewGroup) {
9939028fa93da0f9c7dad2176de347cd6e705084c9fDeepanshu Gupta            mInflater.postInflateProcess(view);
9948a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            ViewGroup group = (ViewGroup) view;
9953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            final int count = group.getChildCount();
9968a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta            for (int c = 0; c < count; c++) {
9973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                View child = group.getChildAt(c);
998b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                postInflateProcess(child, layoutlibCallback, skip);
9993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
10003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
10013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
10023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
10033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
1004c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     * If the root layout is a CoordinatorLayout with an AppBar:
1005c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     * Set the title of the AppBar to the title of the activity context.
1006c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     */
1007c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
1008c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
1009c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (coordinatorLayout == null) {
1010c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1011c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1012c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
1013c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (appBar == null) {
1014c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1015c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1016c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup collapsingToolbar =
1017c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
1018c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (collapsingToolbar == null) {
1019c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1020c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1021c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!hasToolbar(collapsingToolbar)) {
1022c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1023c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1024c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        RenderResources res = context.getRenderResources();
1025c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        String title = params.getAppLabel();
1026c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ResourceValue titleValue = res.findResValue(title, false);
1027c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (titleValue != null && titleValue.getValue() != null) {
1028c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            title = titleValue.getValue();
1029c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1030c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        DesignLibUtil.setTitle(collapsingToolbar, title);
1031c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1032c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1033c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    private View findChildView(View view, String className) {
1034c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
1035c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return null;
1036c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1037c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
1038c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
1039c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), className)) {
1040c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                return group.getChildAt(i);
1041c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1042c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1043c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        return null;
1044c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1045c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1046c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    private boolean hasToolbar(View collapsingToolbar) {
1047c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!(collapsingToolbar instanceof ViewGroup)) {
1048c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return false;
1049c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1050c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup group = (ViewGroup) collapsingToolbar;
1051c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
1052c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
1053c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                return true;
1054c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1055c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1056c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        return false;
1057c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1058c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1059c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    /**
1060777163c3facaed668b43061d726a572fd58f6f60Diego Perez     * Set the scroll position on all the components with the "scrollX" and "scrollY" attribute. If
1061777163c3facaed668b43061d726a572fd58f6f60Diego Perez     * the component supports nested scrolling attempt that first, then use the unconsumed scroll
1062777163c3facaed668b43061d726a572fd58f6f60Diego Perez     * part to scroll the content in the component.
1063c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen     */
1064c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    private void handleScrolling(View view) {
1065c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        BridgeContext context = getContext();
1066777163c3facaed668b43061d726a572fd58f6f60Diego Perez        int scrollPosX = context.getScrollXPos(view);
1067777163c3facaed668b43061d726a572fd58f6f60Diego Perez        int scrollPosY = context.getScrollYPos(view);
1068777163c3facaed668b43061d726a572fd58f6f60Diego Perez        if (scrollPosX != 0 || scrollPosY != 0) {
1069c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            if (view.isNestedScrollingEnabled()) {
1070c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                int[] consumed = new int[2];
1071777163c3facaed668b43061d726a572fd58f6f60Diego Perez                int axis = scrollPosX != 0 ? View.SCROLL_AXIS_HORIZONTAL : 0;
1072777163c3facaed668b43061d726a572fd58f6f60Diego Perez                axis |= scrollPosY != 0 ? View.SCROLL_AXIS_VERTICAL : 0;
1073777163c3facaed668b43061d726a572fd58f6f60Diego Perez                if (view.startNestedScroll(axis)) {
1074777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    view.dispatchNestedPreScroll(scrollPosX, scrollPosY, consumed, null);
1075777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    view.dispatchNestedScroll(consumed[0], consumed[1], scrollPosX, scrollPosY,
1076777163c3facaed668b43061d726a572fd58f6f60Diego Perez                            null);
1077c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                    view.stopNestedScroll();
1078777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    scrollPosX -= consumed[0];
1079777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    scrollPosY -= consumed[1];
1080c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen                }
1081c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1082777163c3facaed668b43061d726a572fd58f6f60Diego Perez            if (scrollPosX != 0 || scrollPosY != 0) {
1083777163c3facaed668b43061d726a572fd58f6f60Diego Perez                view.scrollBy(scrollPosX, scrollPosY);
1084c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            }
1085c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1086c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1087c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
1088c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            return;
1089c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1090c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
1091c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
1092c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            View child = group.getChildAt(i);
1093c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen            handleScrolling(child);
1094c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen        }
1095c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    }
1096c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen
1097c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen    /**
10983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * Sets up a {@link TabHost} object.
10993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @param tabHost the TabHost to setup.
1100b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta     * @param layoutlibCallback The project callback object to access the project R class.
11013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     * @throws PostInflateException
11023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
1103b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta    private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback)
11043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throws PostInflateException {
11053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
11063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
11073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
11093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
11103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
11113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1113952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!(v instanceof TabWidget)) {
11143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
11153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
11163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
11173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
11203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (v == null) {
1122952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
1123952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            //noinspection SpellCheckingInspection
11243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(
11253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
11263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1128952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        if (!(v instanceof FrameLayout)) {
1129952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            //noinspection SpellCheckingInspection
11303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            throw new PostInflateException(String.format(
11313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
11323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
11333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
11363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1137952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta        // now process the content of the frameLayout and dynamically create tabs for it.
11383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        final int count = content.getChildCount();
11393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
11403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
11413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        // and FrameLayout.
11423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        tabHost.setup();
11433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1144f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        if (count == 0) {
1145f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            // Create a dummy child to get a single tab
11466257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta            TabSpec spec = tabHost.newTabSpec("tag")
11476257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta                    .setIndicator("Tab Label", tabHost.getResources()
11486257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta                            .getDrawable(android.R.drawable.ic_menu_info_details, null))
1149f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
1150d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohet                        @Override
1151f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                        public View createTabContent(String tag) {
11520fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet                            return new LinearLayout(getContext());
1153f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                        }
1154f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    });
1155f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            tabHost.addTab(spec);
1156f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye        } else {
1157952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta            // for each child of the frameLayout, add a new TabSpec
1158f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye            for (int i = 0 ; i < count ; i++) {
1159f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                View child = content.getChildAt(i);
1160f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
11618a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta                @SuppressWarnings("ConstantConditions")  // child cannot be null.
1162f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                int id = child.getId();
1163952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta                @SuppressWarnings("deprecation")
1164b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta                Pair<ResourceType, String> resource = layoutlibCallback.resolveResourceId(id);
1165f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                String name;
1166f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                if (resource != null) {
1167947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet                    name = resource.getSecond();
1168f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                } else {
1169f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1170f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                }
1171f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
11723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            }
11733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
11743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
11753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
117685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    /**
117785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
117885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * bounds of all the views.
117985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
118085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param view the root View
118185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param offset an offset for the view bounds.
118285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
118385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
118485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *                       content frame.
118585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
118685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
118785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     */
118885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
118985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            boolean isContentFrame) {
119085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
1191799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
119285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (view instanceof ViewGroup) {
119385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            ViewGroup group = ((ViewGroup) view);
119485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
119585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                    setExtendedInfo, isContentFrame));
119685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
119785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        return result;
119885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
1199799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
120085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    /**
120185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
12028d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta     * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with
120385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * the children of the {@code mContentRoot}.
120485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
120585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param viewGroup the root View
120685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param offset an offset from the top for the content view frame.
120785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
120885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
120985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *                       content frame. {@code false} if the {@code ViewInfo} to be created is
121085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *                       part of the system decor.
121185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     */
121285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
121385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            boolean setExtendedInfo, boolean isContentFrame) {
121485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (viewGroup == null) {
121585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return null;
1216799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet        }
1217799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
121885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (!isContentFrame) {
121985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            offset += viewGroup.getTop();
122085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
1221799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
122285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        int childCount = viewGroup.getChildCount();
122385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (viewGroup == mContentRoot) {
122485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
122585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
122685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            for (int i = 0; i < childCount; i++) {
122785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
12286208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                        setExtendedInfo);
122985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                childrenWithoutOffset.add(childViewInfo[0]);
123085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                childrenWithOffset.add(childViewInfo[1]);
1231799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet            }
123285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            mViewInfoList = childrenWithOffset;
123385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return childrenWithoutOffset;
123485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        } else {
123585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
123685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            for (int i = 0; i < childCount; i++) {
123785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
123885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                        isContentFrame));
123985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            }
124085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return children;
1241799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet        }
124285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
1243799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet
124485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    /**
124585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
124685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
124785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * one with the {@code offset} and other without the {@code offset}. The offset is needed to
124885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * get the right bounds if the {@code ViewInfo} hierarchy is accessed from
124985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
125085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * offset is not needed.
125185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *
125285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
125385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     *         index 1 is with the offset.
125485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     */
1255432578acb80cf2fa827ddb9595cf46edf0b340b0Deepanshu Gupta    @NonNull
125685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
125785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        ViewInfo[] result = new ViewInfo[2];
125885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (view == null) {
125985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            return result;
126085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
126185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta
126285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        result[0] = createViewInfo(view, 0, setExtendedInfo, true);
126385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        result[1] = createViewInfo(view, offset, setExtendedInfo, true);
126485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (view instanceof ViewGroup) {
126585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
126685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            result[0].setChildren(children);
126785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            result[1].setChildren(children);
126885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
126985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        return result;
1270799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet    }
12713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
12723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    /**
127385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
127485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
127585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * set.
127685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta     * @param offset an offset for the view bounds. Used only if view is part of the content frame.
12773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet     */
127885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
127985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            boolean isContentFrame) {
12803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        if (view == null) {
12813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet            return null;
12823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        }
12833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1284777163c3facaed668b43061d726a572fd58f6f60Diego Perez        ViewParent parent = view.getParent();
128585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        ViewInfo result;
128685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        if (isContentFrame) {
1287777163c3facaed668b43061d726a572fd58f6f60Diego Perez            // Account for parent scroll values when calculating the bounding box
1288777163c3facaed668b43061d726a572fd58f6f60Diego Perez            int scrollX = parent != null ? ((View)parent).getScrollX() : 0;
1289777163c3facaed668b43061d726a572fd58f6f60Diego Perez            int scrollY = parent != null ? ((View)parent).getScrollY() : 0;
1290777163c3facaed668b43061d726a572fd58f6f60Diego Perez
129170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // The view is part of the layout added by the user. Hence,
129270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // the ViewCookie may be obtained only through the Context.
129385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta            result = new ViewInfo(view.getClass().getName(),
129470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    getContext().getViewKey(view),
1295777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    -scrollX + view.getLeft(), -scrollY + view.getTop() + offset,
1296777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    -scrollX + view.getRight(), -scrollY + view.getBottom() + offset,
1297777163c3facaed668b43061d726a572fd58f6f60Diego Perez                    view, view.getLayoutParams());
129885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        } else {
129970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // We are part of the system decor.
130070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
130141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta                    getViewKey(view),
130285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                    view.getLeft(), view.getTop(), view.getRight(),
130385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta                    view.getBottom(), view, view.getLayoutParams());
130470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            result = r;
130570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // We currently mark three kinds of views:
130670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // 1. Menus in the Action Bar
130770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // 2. Menus in the Overflow popup.
130870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            // 3. The overflow popup button.
130970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            if (view instanceof ListMenuItemView) {
131070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                // Mark 2.
131170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                // All menus in the popup are of type ListMenuItemView.
131270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                r.setViewType(ViewType.ACTION_BAR_OVERFLOW_MENU);
131370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            } else {
131470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                // Mark 3.
131570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                ViewGroup.LayoutParams lp = view.getLayoutParams();
131670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                if (lp instanceof ActionMenuView.LayoutParams &&
131770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        ((ActionMenuView.LayoutParams) lp).isOverflowButton) {
131870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    r.setViewType(ViewType.ACTION_BAR_OVERFLOW);
131970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                } else {
132070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // Mark 1.
132170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // A view is a menu in the Action Bar is it is not the overflow button and of
132270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // its parent is of type ActionMenuView. We can also check if the view is
132370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // instanceof ActionMenuItemView but that will fail for menus using
132470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    // actionProviderClass.
132570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    while (parent != mViewRoot && parent instanceof ViewGroup) {
132670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        if (parent instanceof ActionMenuView) {
132770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                            r.setViewType(ViewType.ACTION_BAR_MENU);
132870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                            break;
132970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        }
133070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                        parent = parent.getParent();
133170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                    }
133270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta                }
133370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta            }
133485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        }
13353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
13366208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet        if (setExtendedInfo) {
13376208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            MarginLayoutParams marginParams = null;
13386208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            LayoutParams params = view.getLayoutParams();
13396208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            if (params instanceof MarginLayoutParams) {
13406208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                marginParams = (MarginLayoutParams) params;
13416208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            }
13426208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet            result.setExtendedInfo(view.getBaseline(),
13436208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.leftMargin : 0,
13446208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.topMargin : 0,
13456208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.rightMargin : 0,
13466208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet                    marginParams != null ? marginParams.bottomMargin : 0);
13476208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet        }
13486208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet
13493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return result;
13503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
13513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
135270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta    /* (non-Javadoc)
135341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta     * The cookie for menu items are stored in menu item and not in the map from View stored in
135441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta     * BridgeContext.
135541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta     */
1356432578acb80cf2fa827ddb9595cf46edf0b340b0Deepanshu Gupta    @Nullable
135741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta    private Object getViewKey(View view) {
135841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        BridgeContext context = getContext();
135941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        if (!(view instanceof MenuView.ItemView)) {
136041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            return context.getViewKey(view);
136141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        }
136241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        MenuItemImpl menuItem;
136341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        if (view instanceof ActionMenuItemView) {
136441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = ((ActionMenuItemView) view).getItemData();
136541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        } else if (view instanceof ListMenuItemView) {
136641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = ((ListMenuItemView) view).getItemData();
136741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        } else if (view instanceof IconMenuItemView) {
136841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = ((IconMenuItemView) view).getItemData();
136941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        } else {
137041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            menuItem = null;
137141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        }
137241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        if (menuItem instanceof BridgeMenuItemImpl) {
137341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta            return ((BridgeMenuItemImpl) menuItem).getViewCookie();
137441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        }
137541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta
137641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta        return null;
137741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta    }
137841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta
1379620f80a7ee9796c2c41ec0a42d10d2913fc50c90Diego Perez    public void invalidateRenderingSize() {
138085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
138185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
138285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta
13833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    public BufferedImage getImage() {
13843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet        return mImage;
13853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
13863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet
1387a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    public boolean isAlphaChannelImage() {
1388a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet        return mIsAlphaChannelImage;
1389a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet    }
1390a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet
1391e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet    public List<ViewInfo> getViewInfos() {
1392e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet        return mViewInfoList;
13933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet    }
13942d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet
139585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    public List<ViewInfo> getSystemViewInfos() {
139685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta        return mSystemViewInfoList;
139785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta    }
139885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta
1399ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
14000fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet        return getContext().getDefaultPropMap(viewObject);
14012d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet    }
1402b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1403ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public void setScene(RenderSession session) {
1404ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet        mScene = session;
1405b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
1406b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet
1407ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet    public RenderSession getSession() {
1408b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet        return mScene;
1409b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet    }
141095eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez
141195eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez    public void dispose() {
1412e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        boolean createdLooper = false;
1413e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        if (Looper.myLooper() == null) {
1414e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            // Detaching the root view from the window will try to stop any running animations.
1415e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            // The stop method checks that it can run in the looper so, if there is no current
1416e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            // looper, we create a temporary one to complete the shutdown.
1417e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            Bridge.prepareThread();
1418e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            createdLooper = true;
1419e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        }
142095eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        AttachInfo_Accessor.detachFromWindow(mViewRoot);
142195eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        if (mCanvas != null) {
142295eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mCanvas.release();
142395eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mCanvas = null;
142495eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        }
142595eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        if (mViewInfoList != null) {
142695eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mViewInfoList.clear();
142795eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        }
142895eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        if (mSystemViewInfoList != null) {
142995eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez            mSystemViewInfoList.clear();
143095eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        }
143195eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        mImage = null;
143295eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        mViewRoot = null;
143395eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez        mContentRoot = null;
1434e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez
1435e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        if (createdLooper) {
1436e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez            Bridge.cleanupThread();
1437e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez        }
143895eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez    }
14393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet}
1440