1c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/*
2c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
3c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
4c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
5c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * you may not use this file except in compliance with the License.
6c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * You may obtain a copy of the License at
7c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
8c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
9c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet *
10c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * Unless required by applicable law or agreed to in writing, software
11c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
12c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * See the License for the specific language governing permissions and
14c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * limitations under the License.
15c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
16c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
17c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetpackage com.android.layoutlib.bridge.impl;
18c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
192fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport com.android.ide.common.rendering.api.AdapterBinding;
20891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohetimport com.android.ide.common.rendering.api.HardwareConfig;
2119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener;
2219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ILayoutPullParser;
2337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutlibCallback;
2470552fb92dbc5cb5b1d53b20f92f2a64969a50c4Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
2519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession;
262fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport com.android.ide.common.rendering.api.ResourceReference;
2719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue;
2819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
2919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status;
3046d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams;
311126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams.RenderingMode;
3246d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo;
33bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport com.android.ide.common.rendering.api.ViewType;
345ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Guptaimport com.android.internal.view.menu.ActionMenuItemView;
355ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Guptaimport com.android.internal.view.menu.BridgeMenuItemImpl;
365ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Guptaimport com.android.internal.view.menu.IconMenuItemView;
375ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Guptaimport com.android.internal.view.menu.ListMenuItemView;
385ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Guptaimport com.android.internal.view.menu.MenuItemImpl;
395ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Guptaimport com.android.internal.view.menu.MenuView;
402eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
41c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
4201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
43c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
441f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaevimport com.android.layoutlib.bridge.android.RenderParamsFlags;
455ca21e4ceca42be633031809b8ee43fd8688389bDiego Perezimport com.android.layoutlib.bridge.android.graphics.NopCanvas;
464dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsenimport com.android.layoutlib.bridge.android.support.DesignLibUtil;
472fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeAdapter;
482fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
4935ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohetimport com.android.resources.ResourceType;
5029ed07524ce0fc2e5950f5340d306247145d0efaDiego Perezimport com.android.tools.layoutlib.java.System_Delegate;
51b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohetimport com.android.util.Pair;
52eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Guptaimport com.android.util.PropertiesMap;
53c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
547f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.animation.AnimationThread;
55e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.Animator;
562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.animation.AnimatorInflater;
57e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.LayoutTransition;
582b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
59476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull;
60476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable;
61c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.app.Fragment_Delegate;
62c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap;
63c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
64c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Canvas;
655d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perezimport android.os.Looper;
6610bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Guptaimport android.preference.Preference_Delegate;
677f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.AttachInfo_Accessor;
687f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.BridgeInflater;
6929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perezimport android.view.Choreographer_Delegate;
706dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.IWindowManager;
71891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohetimport android.view.IWindowManagerImpl;
726dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.Surface;
73c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View;
74c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.MeasureSpec;
7546d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.view.ViewGroup;
7601811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport android.view.ViewGroup.LayoutParams;
7705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohetimport android.view.ViewGroup.MarginLayoutParams;
78bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.view.ViewParent;
796dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.WindowManagerGlobal_Delegate;
802fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsListView;
812fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsSpinner;
82bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.widget.ActionMenuView;
832fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AdapterView;
842fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ExpandableListView;
85c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.FrameLayout;
86796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.LinearLayout;
872fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ListView;
8831fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohetimport android.widget.QuickContactBadge;
89c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabHost;
90796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.TabHost.TabSpec;
9146d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.widget.TabWidget;
92c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
935a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohetimport java.awt.AlphaComposite;
94c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Color;
95c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Graphics2D;
96c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.image.BufferedImage;
97c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.ArrayList;
98c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.List;
99c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.Map;
100c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
10137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
10237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
10337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
10437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
10537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
10637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
10761f23e9bf7d784e7a52168196758c4f6c6853e77Deepanshu Guptaimport static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
10837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta
109c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/**
11019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * Class implementing the render session.
1111ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta * <p/>
11219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
11319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
114c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * be done on the layout.
115c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
116b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> {
117c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1185ca21e4ceca42be633031809b8ee43fd8688389bDiego Perez    private static final Canvas NOP_CANVAS = new NopCanvas();
1195ca21e4ceca42be633031809b8ee43fd8688389bDiego Perez
120c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // scene state
12119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private RenderSession mScene;
122c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
123c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeInflater mInflater;
124bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private ViewGroup mViewRoot;
125bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private FrameLayout mContentRoot;
1269eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private Canvas mCanvas;
1279eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1289eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenHeight = -1;
129bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private boolean mIsAlphaChannelImage;
13029ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /** If >= 0, a frame will be executed */
13129ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    private long mElapsedFrameTimeNanos = -1;
13229ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /** True if one frame has been already executed to start the animations */
13329ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    private boolean mFirstFrameExecuted = false;
13416584225125acba18b74920b902c798dfead0328Xavier Ducrohet
135c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // information being returned through the API
136c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BufferedImage mImage;
1377d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    private List<ViewInfo> mViewInfoList;
1384ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> mSystemViewInfoList;
139b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta    private Layout.Builder mLayoutBuilder;
14039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    private boolean mNewRenderSize;
141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
142c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final class PostInflateException extends Exception {
143c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        private static final long serialVersionUID = 1L;
144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
145c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        public PostInflateException(String message) {
146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            super(message);
147c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
148c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
149c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
150c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
151c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
152c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
1531b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)},
1541b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * which act as a
15519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
156c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     *
1571b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see Bridge#createSession(SessionParams)
158c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1591126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohet    public RenderSessionImpl(SessionParams params) {
160b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        super(new SessionParams(params));
1612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
1622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
1642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
1652eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * inflater, and parser.
1662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
1682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return whether the scene was prepared
1702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #acquire(long)
1722eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #release()
1732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
174b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    @Override
17519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result init(long timeout) {
176b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Result result = super.init(timeout);
1771ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
1782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            return result;
1792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
181b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
182b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
183c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
18416584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // use default of true in case it's not found to use alpha by default
185fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(),
186fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta                "windowIsFloating", true, true);
1872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
188b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mLayoutBuilder = new Layout.Builder(params, context);
189c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1906dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        // FIXME: find those out, and possibly add them to the render params
1916dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        boolean hasNavigationBar = true;
1921ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        //noinspection ConstantConditions
1936dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
194b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                context.getMetrics(), Surface.ROTATION_0, hasNavigationBar);
1956dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
1966dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet
197c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // build the inflater and parser.
19837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta        mInflater = new BridgeInflater(context, params.getLayoutlibCallback());
199b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        context.setBridgeInflater(mInflater);
2002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
201b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false);
2022eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
203168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet        return SUCCESS.createResult();
204c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
205c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
206c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
20739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez     * Measures the the current layout if needed (see {@link #invalidateRenderingSize}).
20839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez     */
20939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    private void measure(@NonNull SessionParams params) {
21039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        // only do the screen measure when needed.
21139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        if (mMeasuredScreenWidth != -1) {
21239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            return;
21339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        }
21439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
21539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        RenderingMode renderingMode = params.getRenderingMode();
21639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        HardwareConfig hardwareConfig = params.getHardwareConfig();
21739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
21839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        mNewRenderSize = true;
21939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
22039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
22139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
22239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        if (renderingMode != RenderingMode.NORMAL) {
22339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
22439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
22539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    : MeasureSpec.EXACTLY;
22639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            int heightMeasureSpecMode = renderingMode.isVertExpand() ?
22739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
22839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    : MeasureSpec.EXACTLY;
22939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
23039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // We used to compare the measured size of the content to the screen size but
23139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // this does not work anymore due to the 2 following issues:
23239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // - If the content is in a decor (system bar, title/action bar), the root view
23339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            //   will not resize even with the UNSPECIFIED because of the embedded layout.
23439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // - If there is no decor, but a dialog frame, then the dialog padding prevents
23539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            //   comparing the size of the content to the screen frame (as it would not
23639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            //   take into account the dialog padding).
23739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
23839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // The solution is to first get the content size in a normal rendering, inside
23939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // the decor or the dialog padding.
24039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // Then measure only the content with UNSPECIFIED to see the size difference
24139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // and apply this to the screen size.
24239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
24339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // first measure the full layout, with EXACTLY to get the size of the
24439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // content as it is inside the decor/dialog
24539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            @SuppressWarnings("deprecation")
24639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            Pair<Integer, Integer> exactMeasure = measureView(
24739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mViewRoot, mContentRoot.getChildAt(0),
24839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
24939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
25039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
25139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // now measure the content only using UNSPECIFIED (where applicable, based on
25239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // the rendering mode). This will give us the size the content needs.
25339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            @SuppressWarnings("deprecation")
25439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            Pair<Integer, Integer> result = measureView(
25539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mContentRoot, mContentRoot.getChildAt(0),
25639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth, widthMeasureSpecMode,
25739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight, heightMeasureSpecMode);
25839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
25939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // now look at the difference and add what is needed.
26039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            if (renderingMode.isHorizExpand()) {
26139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int measuredWidth = exactMeasure.getFirst();
26239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int neededWidth = result.getFirst();
26339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (neededWidth > measuredWidth) {
26439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth += neededWidth - measuredWidth;
26539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
26639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (mMeasuredScreenWidth < measuredWidth) {
26739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // If the screen width is less than the exact measured width,
26839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // expand to match.
26939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth = measuredWidth;
27039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
27139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            }
27239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
27339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            if (renderingMode.isVertExpand()) {
27439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int measuredHeight = exactMeasure.getSecond();
27539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int neededHeight = result.getSecond();
27639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (neededHeight > measuredHeight) {
27739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight += neededHeight - measuredHeight;
27839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
27939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (mMeasuredScreenHeight < measuredHeight) {
28039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // If the screen height is less than the exact measured height,
28139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // expand to match.
28239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight = measuredHeight;
28339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
28439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            }
28539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        }
28639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    }
28739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
28839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    /**
289c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Inflates the layout.
290c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
2912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
2922eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
2942eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
295c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
29619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result inflate() {
2972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
2982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
299c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
300b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mViewRoot = new Layout(mLayoutBuilder);
301b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mLayoutBuilder = null;  // Done with the builder.
302b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mContentRoot = ((Layout) mViewRoot).getContentRoot();
303b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            SessionParams params = getParams();
304b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            BridgeContext context = getContext();
305c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
306c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
307c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // it can instantiate the custom Fragment.
30837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback());
309c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3101f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
31110bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            boolean isPreference = "PreferenceScreen".equals(rootTag);
31210bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            View view;
31310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            if (isPreference) {
31410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = Preference_Delegate.inflatePreference(getContext(), mBlockParser,
315b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                        mContentRoot);
31610bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            } else {
31710bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = mInflater.inflate(mBlockParser, mContentRoot);
31810bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            }
319c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3202fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // done with the parser, pop it.
3212fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            context.popParser();
3222fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
32337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(null);
324c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
325c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // set the AttachInfo on the root view.
3267f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet            AttachInfo_Accessor.setAttachInfo(mViewRoot);
327c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
32833758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
32937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
330ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.onDoneInflation();
33133758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet
3324dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            setActiveToolbar(view, context, params);
3334dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
33439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            measure(params);
33539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            measureView(mViewRoot, null /*measuredView*/,
33639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
33739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
33839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
33939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
34039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    false);
34139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
34219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
343c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (PostInflateException e) {
34419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
345c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
346c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
347c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
348c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
349c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
350c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
351c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
35219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
353c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
354c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
355c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
356c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
35729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     * Sets the time for which the next frame will be selected. The time is the elapsed time from
35829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     * the current system nanos time. You
35929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     */
36029ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    public void setElapsedFrameTimeNanos(long nanos) {
36129ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez        mElapsedFrameTimeNanos = nanos;
36229ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    }
36329ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez
36429ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /**
3652605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * Renders the given view hierarchy to the passed canvas and returns the result of the render
3662605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * operation.
3672605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * @param canvas an optional canvas to render the views to. If null, only the measure and
3682605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * layout steps will be executed.
3692605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     */
3702605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    private static Result render(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot,
3712605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            @Nullable Canvas canvas, int width, int height) {
3722605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        // measure again with the size we need
3732605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        // This must always be done before the call to layout
3742605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        measureView(viewRoot, null /*measuredView*/,
3752605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                width, MeasureSpec.EXACTLY,
3762605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                height, MeasureSpec.EXACTLY);
3772605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3782605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        // now do the layout.
3792605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        viewRoot.layout(0, 0, width, height);
3802605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        handleScrolling(context, viewRoot);
3812605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3822605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        if (canvas == null) {
3832605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            return SUCCESS.createResult();
3842605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        }
3852605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3862605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        AttachInfo_Accessor.dispatchOnPreDraw(viewRoot);
3872605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        viewRoot.draw(canvas);
3882605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3892605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        return SUCCESS.createResult();
3902605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    }
3912605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3922605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    /**
393c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Renders the scene.
394c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
3952eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
3962eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
3975a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
3985a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
3995a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      animations.)
4005a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *
4012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
4022eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
4039eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet     *
4041b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see SessionParams#getRenderingMode()
405bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#render(long)
406c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
4075a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet    public Result render(boolean freshRender) {
4082eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
4092eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
410b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
411b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
412c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
413c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mViewRoot == null) {
41419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
415c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
416c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
41739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            measure(params);
418c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
41939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            HardwareConfig hardwareConfig = params.getHardwareConfig();
4202605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            Result renderResult = SUCCESS.createResult();
42110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            if (params.isLayoutOnly()) {
42210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // delete the canvas and image to reset them on the next full rendering
42310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mImage = null;
42410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mCanvas = null;
42510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            } else {
42610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // draw the views
42710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // create the BufferedImage into which the layout will be rendered.
42810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                boolean newImage = false;
4292c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez
4302c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // When disableBitmapCaching is true, we do not reuse mImage and
4312c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // we create a new one in every render.
4322c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // This is useful when mImage is just a wrapper of Graphics2D so
4332c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // it doesn't get cached.
4342c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
4351f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
43639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (mNewRenderSize || mCanvas == null || disableBitmapCaching) {
43739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mNewRenderSize = false;
43810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.getImageFactory() != null) {
43910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = params.getImageFactory().getImage(
44010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
44110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight);
44210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    } else {
44310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = new BufferedImage(
44410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
44510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight,
44610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                BufferedImage.TYPE_INT_ARGB);
44710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
44810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
44910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
45010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.isBgColorOverridden()) {
45110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        // since we override the content, it's the same as if it was a new image.
45210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
45310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        Graphics2D gc = mImage.createGraphics();
45410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setColor(new Color(params.getOverrideBgColor(), true));
45510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setComposite(AlphaComposite.Src);
45610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
45710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.dispose();
45810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
45910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
46010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // create an Android bitmap around the BufferedImage
46110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
462891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                            true /*isMutable*/, hardwareConfig.getDensity());
46310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
4642c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    if (mCanvas == null) {
4652c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        // create a Canvas around the Android bitmap
4662c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas = new Canvas(bitmap);
4672c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    } else {
4682c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas.setBitmap(bitmap);
4692c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    }
470891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
4719eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
472c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4731ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                if (freshRender && !newImage) {
4749eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
4755a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
476c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
47710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.setColor(new Color(0x00000000, true));
4784ea74d2960688db6aa13452765dd5f2d07a40189Deepanshu Gupta                    gc.fillRect(0, 0,
4794ea74d2960688db6aa13452765dd5f2d07a40189Deepanshu Gupta                            mMeasuredScreenWidth, mMeasuredScreenHeight);
48016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
48110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // done
48210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.dispose();
48310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                }
48416584225125acba18b74920b902c798dfead0328Xavier Ducrohet
48529ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                if (mElapsedFrameTimeNanos >= 0) {
48629ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    long initialTime = System_Delegate.nanoTime();
48729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    if (!mFirstFrameExecuted) {
4882605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                        // We need to run an initial draw call to initialize the animations
4895ca21e4ceca42be633031809b8ee43fd8688389bDiego Perez                        render(getContext(), mViewRoot, NOP_CANVAS, mMeasuredScreenWidth, mMeasuredScreenHeight);
4902605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
49129ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        // The first frame will initialize the animations
49229ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        Choreographer_Delegate.doFrame(initialTime);
49329ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        mFirstFrameExecuted = true;
49429ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    }
49529ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    // Second frame will move the animations
49629ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
49729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                }
4982605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                renderResult = render(getContext(), mViewRoot, mCanvas, mMeasuredScreenWidth,
4992605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                        mMeasuredScreenHeight);
5005a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            }
5015a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet
5025ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
5035ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    false);
504c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
505c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // success!
5062605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            return renderResult;
507c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
508c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
509c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
510c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
511c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
512c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
513c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
51419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
515c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
516c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
517c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
518c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
519c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
520c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
521c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
522c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
523c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
524c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
525c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param viewToMeasure the view on which to execute measure().
526c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param measuredView if non null, the view to query for its measured width/height.
527c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param width the width to use in the MeasureSpec.
528c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param widthMode the MeasureSpec mode to use for the width.
529c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param height the height to use in the MeasureSpec.
530c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param heightMode the MeasureSpec mode to use for the height.
531c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @return the measured width/height if measuredView is non-null, null otherwise.
532c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     */
5331ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
5342605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
535c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            int width, int widthMode, int height, int heightMode) {
536c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
537c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
538c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        viewToMeasure.measure(w_spec, h_spec);
539c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
540c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        if (measuredView != null) {
541c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight());
542c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        }
543c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
544c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        return null;
545c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    }
546c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
547c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    /**
5482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Animate an object
5492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * <p>
5502eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
5512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
5522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
5532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
554e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
555bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
5562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
55719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
5582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
5592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
5602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
561b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
562b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
5632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // find the animation file.
5641ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        ResourceValue animationResource;
5652eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        int animationId = 0;
5662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (isFrameworkAnimation) {
567b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getFrameworkResource(
56835ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
5692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
570b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
5712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5722eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } else {
573b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getProjectResource(
57435ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
5752eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
57637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                animationId = context.getLayoutlibCallback().getResourceId(
57735ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
5782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5802eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
5812eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (animationResource != null) {
5822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            try {
583b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(context, animationId);
5842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (anim != null) {
5852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    anim.setTarget(targetObject);
5862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
587e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
5882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
58919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    return SUCCESS.createResult();
5902eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
5912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            } catch (Exception e) {
592c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                // get the real cause of the exception.
593c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                Throwable t = e;
594c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                while (t.getCause() != null) {
595c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                    t = t.getCause();
596c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                }
597c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
59819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5992eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
6002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
6012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
60219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
603c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
604c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
605e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
606e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Insert a new child into an existing parent.
607e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
608e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
609e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
610e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
611e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
612e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
613bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
614e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
61519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
616e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final int index, IAnimationListener listener) {
617c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
618c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
619b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
620b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
621c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // create a block parser for the XML
62202d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
62302d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet                childXml, context, false /* platformResourceFlag */);
624c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
625c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
626c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
627c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // be created correctly.
628e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
62902d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        blockParser.ensurePopped();
630c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
631e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
632e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
633e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
634e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
635e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
636e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
63719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
638e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
639e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return addView(parentView, child, index);
640e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
641e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
642e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
643e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
644e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(null);
645e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
646e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
647e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
648e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
64919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(child);
6509eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        }
6519eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
652e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        // add it to the parentView in the correct location
65319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = addView(parentView, child, index);
6541ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
655e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
656e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
657c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
6585a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
659c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        if (result.isSuccess()) {
660e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(child);
661c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        }
662c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet
663c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        return result;
664c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
665c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
666e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
667e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Adds a given view to a given parent at a given index.
668e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
669e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param parent the parent to receive the view
670e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to add to the parent
671e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the index where to do the add.
672e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
67319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
67419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
675e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
676e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
67719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
678e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
679e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.addView(view, index);
68019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
681e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
682e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
68319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
684e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
685e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
686e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
687e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
688e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a view to a new parent at a given location
689e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
690e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
691e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
692e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
693e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
694e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
695bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
696e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
6972b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
698479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
699c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
700c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
701e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
702e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
70301811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        LayoutParams layoutParams = null;
704e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (layoutParamsMap != null) {
705e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
7062b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
707e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
708e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
7099eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
7102b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        // get the current parent of the view that needs to be moved.
7112b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
7122b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
713e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
714e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final LayoutParams params = layoutParams;
71501811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
716479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
717479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
718479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousParent != newParentView) {
719479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new Thread("not animated moveChild") {
720479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
721479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void run() {
722479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
723479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                params);
7241ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
725479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
726479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
727479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
728479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // ready to do the work, acquire the scene.
729479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        result = acquire(250);
7301ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
731479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
732479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            return;
733479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
734479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
735479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        try {
7365a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                            result = render(false /*freshRender*/);
737479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            if (result.isSuccess()) {
738479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
739479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            }
740479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        } finally {
741479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            release();
742479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
743479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
744479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        listener.done(result);
7452b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
746479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
747479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            } else {
748479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
7492b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
750479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
751479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public Result preAnimation() {
752479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // set up the transition for the parent.
753479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
754479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(transition);
7557550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet
756479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
757479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // animation playing just before).
758479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
759479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // on the LayoutTransition.
760479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
761479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
762479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
76301811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
764479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
765479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
766479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
767479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
768479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
769479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
770479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
771479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
772479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
773479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
774479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
775479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
776479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void postAnimation() {
777479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(null);
778479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        newParentView.setLayoutTransition(null);
779479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
780479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
781479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            }
782e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
783e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
78419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
785c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
786c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7872b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
7881ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
789e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
790e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
791c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7925a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
79301811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
794e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
79501811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        }
79601811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
79701811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        return result;
798c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
799c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
800e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
801e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
802e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * an optional new {@link LayoutParams} instance
803e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
8042b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
8052b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param newParent the new parent
806479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet     * @param movedView the view to move
807e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the new location in the new parent
808e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
809e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
81019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
81119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
812e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
813e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
814479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
815479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
8169eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        try {
8172b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            // check if there is a transition on the previousParent.
818479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
819479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousTransition != null) {
8207550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
8217550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
8227550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
8237550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
8247550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // to handle).
8257550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
8267550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
8277550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // adding the child or the child will appear in its new location before the
8287550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // other children have made room for it.
8292b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8302b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
831479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
832479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    private int mChangeDisappearingCount = 0;
8332b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
83446d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
8352b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
8362b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
837479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
838479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount++;
839479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
8402b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
841e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
84246d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
8432b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
8442b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
845479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
846479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount--;
847479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
848479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
849479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
850479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                mChangeDisappearingCount == 0) {
8512b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            // add it to the parentView in the correct location
8522b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            if (params != null) {
853479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index, params);
8542b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            } else {
855479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index);
8562b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            }
8572b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                        }
8582b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
8592b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                });
8602b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8612b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // remove the view from the current parent.
862479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
8632b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8642b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
8652b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
866e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            } else {
8672b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // standard code with no animation. pretty simple.
868479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
869e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8702b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add it to the parentView in the correct location
8712b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                if (params != null) {
872479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index, params);
8732b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                } else {
874479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index);
8752b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                }
8762b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8772b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
8782b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            }
8799eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        } catch (UnsupportedOperationException e) {
8809eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
88119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
882c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
883e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
884e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
885e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
886e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a child from its current parent.
887e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
888e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
889e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
890e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
891e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
892e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
893bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#removeChild(Object, IAnimationListener)
894e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
89519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
896e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        checkLock();
897c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
8989eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        invalidateRenderingSize();
8999eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
900e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
901e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
902e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
903e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
904e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
905e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
90619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
907e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
908e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return removeView(parent, childView);
909e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
910e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
911e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
912e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
913e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(null);
914e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
915e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
916e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
917e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
91819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
919e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
920e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
92119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = removeView(parent, childView);
9221ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
923e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
924e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
925e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
9265a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        return render(false /*freshRender*/);
9272eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
9282eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
9292eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
930e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a given view from its current parent.
931e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
932e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to remove from its parent
933e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
93419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
93519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
936e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
937e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
93819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
939e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
940e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.removeView(view);
94119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
942e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
943e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
94419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
945e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
946e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
947e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
948c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
9491ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * Post process on a view hierarchy that was just inflated.
9501ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * <p/>
9511ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
952c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
953c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
954c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root view to process.
95537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback callback to the project.
95610bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta     * @param skip the view and it's children are not processed.
957c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
9581ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
95937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip)
960c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
96110bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        if (view == skip) {
96210bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            return;
96310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        }
964c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof TabHost) {
96537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            setupTabHost((TabHost) view, layoutlibCallback);
96631fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
96731fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
96831fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            badge.setImageToDefault();
9692fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet        } else if (view instanceof AdapterView<?>) {
9702fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get the view ID.
9712fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            int id = view.getId();
9722fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9732fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            BridgeContext context = getContext();
9742fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9752fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get a ResourceReference from the integer ID.
9762fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            ResourceReference listRef = context.resolveId(id);
9772fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9782fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            if (listRef != null) {
9792fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                SessionParams params = getParams();
9802fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                AdapterBinding binding = params.getAdapterBindings().get(listRef);
9812fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9822fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                // if there was no adapter binding, trying to get it from the call back.
9832fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding == null) {
98437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                    binding = layoutlibCallback.getAdapterBinding(
98537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                            listRef, context.getViewKey(view), view);
9862fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
9872fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9882fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding != null) {
9892fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9902fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    if (view instanceof AbsListView) {
9912fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) &&
9922fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                view instanceof ListView) {
9932fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ListView list = (ListView) view;
9942fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9952fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            boolean skipCallbackParser = false;
9962fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9972fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            int count = binding.getHeaderCount();
99810bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
9992fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
10002fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getHeaderAt(i),
100137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
10022fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
10032fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addHeaderView(pair.getFirst());
10042fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
10052fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10062fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
10072fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
10082fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10092fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            count = binding.getFooterCount();
101010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
10112fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
10122fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getFooterAt(i),
101337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
10142fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
10152fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addFooterView(pair.getFirst());
10162fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
10172fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10182fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
10192fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
10202fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
10212fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10222fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if (view instanceof ExpandableListView) {
10232fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((ExpandableListView) view).setAdapter(
102437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeExpandableAdapter(listRef, binding, layoutlibCallback));
10252fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        } else {
10262fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((AbsListView) view).setAdapter(
102737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeAdapter(listRef, binding, layoutlibCallback));
10282fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
10292fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    } else if (view instanceof AbsSpinner) {
10302fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        ((AbsSpinner) view).setAdapter(
103137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                new FakeAdapter(listRef, binding, layoutlibCallback));
10322fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    }
10332fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
10342fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            }
1035c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } else if (view instanceof ViewGroup) {
1036ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.postInflateProcess(view);
103710bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            ViewGroup group = (ViewGroup) view;
1038c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            final int count = group.getChildCount();
103910bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            for (int c = 0; c < count; c++) {
1040c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                View child = group.getChildAt(c);
104137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                postInflateProcess(child, layoutlibCallback, skip);
1042c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1043c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1044c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1045c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1046c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
10474dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * If the root layout is a CoordinatorLayout with an AppBar:
10484dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * Set the title of the AppBar to the title of the activity context.
10494dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
10504dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
10514dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
10524dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (coordinatorLayout == null) {
10534dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10544dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10554dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
10564dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (appBar == null) {
10574dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10584dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10594dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup collapsingToolbar =
10604dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
10614dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (collapsingToolbar == null) {
10624dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10634dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10644dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!hasToolbar(collapsingToolbar)) {
10654dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10664dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10674dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        RenderResources res = context.getRenderResources();
10684dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        String title = params.getAppLabel();
10694dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ResourceValue titleValue = res.findResValue(title, false);
10704dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (titleValue != null && titleValue.getValue() != null) {
10714dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            title = titleValue.getValue();
10724dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10734dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        DesignLibUtil.setTitle(collapsingToolbar, title);
10744dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10754dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10764dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private View findChildView(View view, String className) {
10774dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
10784dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return null;
10794dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10804dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
10814dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10824dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), className)) {
10834dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return group.getChildAt(i);
10844dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10854dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10864dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return null;
10874dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10884dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10894dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private boolean hasToolbar(View collapsingToolbar) {
10904dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(collapsingToolbar instanceof ViewGroup)) {
10914dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return false;
10924dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10934dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) collapsingToolbar;
10944dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10954dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
10964dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return true;
10974dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10984dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10994dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return false;
11004dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
11014dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
11024dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
1103d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * Set the scroll position on all the components with the "scrollX" and "scrollY" attribute. If
1104d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * the component supports nested scrolling attempt that first, then use the unconsumed scroll
1105d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * part to scroll the content in the component.
11064dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
11072605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    private static void handleScrolling(BridgeContext context, View view) {
1108d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        int scrollPosX = context.getScrollXPos(view);
1109d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        int scrollPosY = context.getScrollYPos(view);
1110d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        if (scrollPosX != 0 || scrollPosY != 0) {
11114dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (view.isNestedScrollingEnabled()) {
11124dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                int[] consumed = new int[2];
1113d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                int axis = scrollPosX != 0 ? View.SCROLL_AXIS_HORIZONTAL : 0;
1114d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                axis |= scrollPosY != 0 ? View.SCROLL_AXIS_VERTICAL : 0;
1115d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                if (view.startNestedScroll(axis)) {
1116d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view.dispatchNestedPreScroll(scrollPosX, scrollPosY, consumed, null);
1117d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view.dispatchNestedScroll(consumed[0], consumed[1], scrollPosX, scrollPosY,
1118d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                            null);
11194dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                    view.stopNestedScroll();
1120d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    scrollPosX -= consumed[0];
1121d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    scrollPosY -= consumed[1];
11224dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                }
11234dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
1124d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            if (scrollPosX != 0 || scrollPosY != 0) {
11252605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                view.scrollTo(scrollPosX, scrollPosY);
11264dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
11274dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
11284dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
11294dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
11304dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
11314dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
11324dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
11334dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
11344dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            View child = group.getChildAt(i);
11352605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            handleScrolling(context, child);
11364dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
11374dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
11384dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
11394dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
1140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Sets up a {@link TabHost} object.
1141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param tabHost the TabHost to setup.
114237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback The project callback object to access the project R class.
1143c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @throws PostInflateException
1144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
114537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback)
1146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1147c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
1148c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
1149c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1150c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1151c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1152c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
1153c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1154c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11551ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof TabWidget)) {
1156c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1157c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
1158c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
1159c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1160c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1161c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
1162c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1163c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
11641ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
11651ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1166c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1167c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
1168c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1169c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11701ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof FrameLayout)) {
11711ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1172c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1173c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
1174c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
1175c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1176c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1177c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
1178c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11791ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        // now process the content of the frameLayout and dynamically create tabs for it.
1180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        final int count = content.getChildCount();
1181c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1182c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
1183c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // and FrameLayout.
1184c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        tabHost.setup();
1185c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1186796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        if (count == 0) {
1187796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // Create a dummy child to get a single tab
118849ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta            TabSpec spec = tabHost.newTabSpec("tag")
118949ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                    .setIndicator("Tab Label", tabHost.getResources()
119049ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                            .getDrawable(android.R.drawable.ic_menu_info_details, null))
1191796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
119246d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                        @Override
1193796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        public View createTabContent(String tag) {
1194b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                            return new LinearLayout(getContext());
1195796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        }
1196796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    });
1197796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            tabHost.addTab(spec);
1198796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        } else {
11991ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // for each child of the frameLayout, add a new TabSpec
1200796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            for (int i = 0 ; i < count ; i++) {
1201796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                View child = content.getChildAt(i);
1202796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
120310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                @SuppressWarnings("ConstantConditions")  // child cannot be null.
1204796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                int id = child.getId();
12051ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                @SuppressWarnings("deprecation")
120637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                Pair<ResourceType, String> resource = layoutlibCallback.resolveResourceId(id);
1207796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String name;
1208796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                if (resource != null) {
1209b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                    name = resource.getSecond();
1210796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                } else {
1211796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1212796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                }
1213796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
1214c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1215c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1216c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1217c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
12184ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12194ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
12204ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views.
12214ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12224ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param view the root View
12234ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds.
12244ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
12254ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
12264ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame.
12274ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12284ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
12294ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
12304ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
12314ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
12324ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
1233bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12344ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
12354ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            ViewGroup group = ((ViewGroup) view);
12364ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
12374ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    setExtendedInfo, isContentFrame));
12384ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
12394ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
12404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1241bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12424ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12434ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
12441b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with
12454ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * the children of the {@code mContentRoot}.
12464ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12474ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param viewGroup the root View
12484ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset from the top for the content view frame.
12494ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
12504ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
12514ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame. {@code false} if the {@code ViewInfo} to be created is
12524ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       part of the system decor.
12534ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
12544ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
12554ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean setExtendedInfo, boolean isContentFrame) {
12564ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == null) {
12574ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return null;
1258bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
1259bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12604ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (!isContentFrame) {
12614ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            offset += viewGroup.getTop();
12624ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1263bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12644ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        int childCount = viewGroup.getChildCount();
12654ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == mContentRoot) {
12664ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
12674ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
12684ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
12694ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
127005b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                        setExtendedInfo);
12714ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithoutOffset.add(childViewInfo[0]);
12724ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithOffset.add(childViewInfo[1]);
1273bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            }
12744ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            mViewInfoList = childrenWithOffset;
12754ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return childrenWithoutOffset;
12764ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
12774ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
12784ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
12794ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
12804ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                        isContentFrame));
12814ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            }
12824ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return children;
1283bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
12844ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1285bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12864ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12874ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
12884ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
12894ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * one with the {@code offset} and other without the {@code offset}. The offset is needed to
12904ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * get the right bounds if the {@code ViewInfo} hierarchy is accessed from
12914ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
12924ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * offset is not needed.
12934ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12944ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
12954ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *         index 1 is with the offset.
12964ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
1297d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @NonNull
12984ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
12994ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo[] result = new ViewInfo[2];
13004ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view == null) {
13014ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return result;
13024ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
13034ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
13044ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[0] = createViewInfo(view, 0, setExtendedInfo, true);
13054ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[1] = createViewInfo(view, offset, setExtendedInfo, true);
13064ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
13074ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
13084ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[0].setChildren(children);
13094ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[1].setChildren(children);
13104ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
13114ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
1312bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    }
1313c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1314c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
13154ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
13164ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
13174ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * set.
13184ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds. Used only if view is part of the content frame.
1319c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
13204ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
13214ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
1322c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view == null) {
1323c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            return null;
1324c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1325c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1326d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        ViewParent parent = view.getParent();
13274ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result;
13284ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (isContentFrame) {
1329d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            // Account for parent scroll values when calculating the bounding box
1330d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            int scrollX = parent != null ? ((View)parent).getScrollX() : 0;
1331d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            int scrollY = parent != null ? ((View)parent).getScrollY() : 0;
1332d15459197f71f8cc940e2b057b399117df282f2cDiego Perez
1333bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // The view is part of the layout added by the user. Hence,
1334bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // the ViewCookie may be obtained only through the Context.
13354ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result = new ViewInfo(view.getClass().getName(),
1336bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    getContext().getViewKey(view),
1337d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    -scrollX + view.getLeft(), -scrollY + view.getTop() + offset,
1338d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    -scrollX + view.getRight(), -scrollY + view.getBottom() + offset,
1339d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view, view.getLayoutParams());
13404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
1341bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We are part of the system decor.
1342bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
13435ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    getViewKey(view),
13444ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getLeft(), view.getTop(), view.getRight(),
13454ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getBottom(), view, view.getLayoutParams());
1346bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            result = r;
1347bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We currently mark three kinds of views:
1348bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 1. Menus in the Action Bar
1349bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 2. Menus in the Overflow popup.
1350bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 3. The overflow popup button.
1351bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            if (view instanceof ListMenuItemView) {
1352bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 2.
1353bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // All menus in the popup are of type ListMenuItemView.
1354bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                r.setViewType(ViewType.ACTION_BAR_OVERFLOW_MENU);
1355bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            } else {
1356bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 3.
1357bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                ViewGroup.LayoutParams lp = view.getLayoutParams();
1358bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                if (lp instanceof ActionMenuView.LayoutParams &&
1359bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        ((ActionMenuView.LayoutParams) lp).isOverflowButton) {
1360bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    r.setViewType(ViewType.ACTION_BAR_OVERFLOW);
1361bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                } else {
1362bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // Mark 1.
1363bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // A view is a menu in the Action Bar is it is not the overflow button and of
1364bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // its parent is of type ActionMenuView. We can also check if the view is
1365bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // instanceof ActionMenuItemView but that will fail for menus using
1366bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // actionProviderClass.
1367bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    while (parent != mViewRoot && parent instanceof ViewGroup) {
1368bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        if (parent instanceof ActionMenuView) {
1369bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            r.setViewType(ViewType.ACTION_BAR_MENU);
1370bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            break;
1371bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        }
1372bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        parent = parent.getParent();
1373bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    }
1374bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                }
1375bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            }
13764ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1377c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
137805b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        if (setExtendedInfo) {
137905b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            MarginLayoutParams marginParams = null;
138005b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            LayoutParams params = view.getLayoutParams();
138105b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            if (params instanceof MarginLayoutParams) {
138205b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                marginParams = (MarginLayoutParams) params;
138305b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            }
138405b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            result.setExtendedInfo(view.getBaseline(),
138505b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.leftMargin : 0,
138605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.topMargin : 0,
138705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.rightMargin : 0,
138805b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.bottomMargin : 0);
138905b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        }
139005b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet
1391c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return result;
1392c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1393c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1394bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta    /* (non-Javadoc)
13955ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * The cookie for menu items are stored in menu item and not in the map from View stored in
13965ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * BridgeContext.
13975ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     */
1398d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @Nullable
13995ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    private Object getViewKey(View view) {
14005ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        BridgeContext context = getContext();
14015ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (!(view instanceof MenuView.ItemView)) {
14025ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return context.getViewKey(view);
14035ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
14045ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        MenuItemImpl menuItem;
14055ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (view instanceof ActionMenuItemView) {
14065ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ActionMenuItemView) view).getItemData();
14075ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof ListMenuItemView) {
14085ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ListMenuItemView) view).getItemData();
14095ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof IconMenuItemView) {
14105ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((IconMenuItemView) view).getItemData();
14115ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else {
14125ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = null;
14135ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
14145ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (menuItem instanceof BridgeMenuItemImpl) {
14155ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return ((BridgeMenuItemImpl) menuItem).getViewCookie();
14165ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
14175ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
14185ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        return null;
14195ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    }
14205ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
1421c13aa0c035cd226d27323bc0e533632ba32f6a84Diego Perez    public void invalidateRenderingSize() {
14224ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
14234ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
14244ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
1425c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    public BufferedImage getImage() {
1426c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return mImage;
1427c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1428c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
142916584225125acba18b74920b902c798dfead0328Xavier Ducrohet    public boolean isAlphaChannelImage() {
143016584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return mIsAlphaChannelImage;
143116584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
143216584225125acba18b74920b902c798dfead0328Xavier Ducrohet
14337d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    public List<ViewInfo> getViewInfos() {
14347d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return mViewInfoList;
1435c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1436cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet
14374ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    public List<ViewInfo> getSystemViewInfos() {
14384ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return mSystemViewInfoList;
14394ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
14404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
1441eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta    public Map<Object, PropertiesMap> getDefaultProperties() {
1442eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta        return getContext().getDefaultProperties();
1443eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta    }
1444eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta
144519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public void setScene(RenderSession session) {
144619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mScene = session;
1447c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1448c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
144919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public RenderSession getSession() {
1450c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        return mScene;
1451c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1452f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez
1453f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez    public void dispose() {
14545d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        boolean createdLooper = false;
14555d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        if (Looper.myLooper() == null) {
14565d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // Detaching the root view from the window will try to stop any running animations.
14575d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // The stop method checks that it can run in the looper so, if there is no current
14585d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // looper, we create a temporary one to complete the shutdown.
14595d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            Bridge.prepareThread();
14605d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            createdLooper = true;
14615d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        }
1462f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        AttachInfo_Accessor.detachFromWindow(mViewRoot);
1463f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mCanvas != null) {
1464f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mCanvas.release();
1465f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mCanvas = null;
1466f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1467f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mViewInfoList != null) {
1468f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mViewInfoList.clear();
1469f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1470f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mSystemViewInfoList != null) {
1471f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mSystemViewInfoList.clear();
1472f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1473f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mImage = null;
1474f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mViewRoot = null;
1475f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mContentRoot = null;
14765d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez
14775d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        if (createdLooper) {
14785d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            Bridge.cleanupThread();
147961ccc9198ab09363edbf500d7669dbcfafc5fa28Deepanshu Gupta            Choreographer_Delegate.dispose();
14805d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        }
1481f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez    }
1482c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet}
1483