RenderSessionImpl.java revision 39e540caffca2584aa6c4cb74ce42dceb24a93f7
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;
454dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsenimport com.android.layoutlib.bridge.android.support.DesignLibUtil;
462fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeAdapter;
472fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
4835ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohetimport com.android.resources.ResourceType;
4929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perezimport com.android.tools.layoutlib.java.System_Delegate;
50b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohetimport com.android.util.Pair;
51eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Guptaimport com.android.util.PropertiesMap;
52c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
537f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.animation.AnimationThread;
54e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.Animator;
552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.animation.AnimatorInflater;
56e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.LayoutTransition;
572b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
58476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull;
59476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable;
60c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.app.Fragment_Delegate;
61c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap;
62c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
63c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Canvas;
645d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perezimport android.os.Looper;
6510bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Guptaimport android.preference.Preference_Delegate;
667f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.AttachInfo_Accessor;
677f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.BridgeInflater;
6829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perezimport android.view.Choreographer_Delegate;
696dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.IWindowManager;
70891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohetimport android.view.IWindowManagerImpl;
716dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.Surface;
72c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View;
73c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.MeasureSpec;
7446d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.view.ViewGroup;
7501811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport android.view.ViewGroup.LayoutParams;
7605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohetimport android.view.ViewGroup.MarginLayoutParams;
77bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.view.ViewParent;
786dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.WindowManagerGlobal_Delegate;
792fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsListView;
802fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsSpinner;
81bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.widget.ActionMenuView;
822fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AdapterView;
832fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ExpandableListView;
84c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.FrameLayout;
85796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.LinearLayout;
862fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ListView;
8731fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohetimport android.widget.QuickContactBadge;
88c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabHost;
89796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.TabHost.TabSpec;
9046d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.widget.TabWidget;
91c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
925a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohetimport java.awt.AlphaComposite;
93c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Color;
94c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Graphics2D;
95c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.image.BufferedImage;
96c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.ArrayList;
97c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.List;
98c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.Map;
99c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
10037dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
10137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
10237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
10337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
10437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
10537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
10661f23e9bf7d784e7a52168196758c4f6c6853e77Deepanshu Guptaimport static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
10737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta
108c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/**
10919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * Class implementing the render session.
1101ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta * <p/>
11119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
11219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
113c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * be done on the layout.
114c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
115b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> {
116c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
117c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // scene state
11819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private RenderSession mScene;
119c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
120c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeInflater mInflater;
121bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private ViewGroup mViewRoot;
122bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private FrameLayout mContentRoot;
1239eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private Canvas mCanvas;
1249eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1259eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenHeight = -1;
126bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private boolean mIsAlphaChannelImage;
12729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /** If >= 0, a frame will be executed */
12829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    private long mElapsedFrameTimeNanos = -1;
12929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /** True if one frame has been already executed to start the animations */
13029ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    private boolean mFirstFrameExecuted = false;
13116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
132c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // information being returned through the API
133c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BufferedImage mImage;
1347d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    private List<ViewInfo> mViewInfoList;
1354ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> mSystemViewInfoList;
136b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta    private Layout.Builder mLayoutBuilder;
13739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    private boolean mNewRenderSize;
138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final class PostInflateException extends Exception {
140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        private static final long serialVersionUID = 1L;
141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
142c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        public PostInflateException(String message) {
143c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            super(message);
144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
145c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
147c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
148c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
149c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
1501b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)},
1511b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * which act as a
15219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
153c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     *
1541b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see Bridge#createSession(SessionParams)
155c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1561126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohet    public RenderSessionImpl(SessionParams params) {
157b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        super(new SessionParams(params));
1582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
1592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
1612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
1622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * inflater, and parser.
1632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
1652eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return whether the scene was prepared
1672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #acquire(long)
1692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #release()
1702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
171b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    @Override
17219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result init(long timeout) {
173b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Result result = super.init(timeout);
1741ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
1752eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            return result;
1762eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
177c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
178b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
179b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
18116584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // use default of true in case it's not found to use alpha by default
182fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(),
183fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta                "windowIsFloating", true, true);
1842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
185b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mLayoutBuilder = new Layout.Builder(params, context);
186c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1876dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        // FIXME: find those out, and possibly add them to the render params
1886dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        boolean hasNavigationBar = true;
1891ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        //noinspection ConstantConditions
1906dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
191b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                context.getMetrics(), Surface.ROTATION_0, hasNavigationBar);
1926dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
1936dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet
194c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // build the inflater and parser.
19537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta        mInflater = new BridgeInflater(context, params.getLayoutlibCallback());
196b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        context.setBridgeInflater(mInflater);
1972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
198b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false);
1992eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
200168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet        return SUCCESS.createResult();
201c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
202c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
203c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
20439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez     * Measures the the current layout if needed (see {@link #invalidateRenderingSize}).
20539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez     */
20639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    private void measure(@NonNull SessionParams params) {
20739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        // only do the screen measure when needed.
20839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        if (mMeasuredScreenWidth != -1) {
20939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            return;
21039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        }
21139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
21239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        RenderingMode renderingMode = params.getRenderingMode();
21339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        HardwareConfig hardwareConfig = params.getHardwareConfig();
21439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
21539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        mNewRenderSize = true;
21639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
21739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
21839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
21939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        if (renderingMode != RenderingMode.NORMAL) {
22039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
22139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
22239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    : MeasureSpec.EXACTLY;
22339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            int heightMeasureSpecMode = renderingMode.isVertExpand() ?
22439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
22539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    : MeasureSpec.EXACTLY;
22639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
22739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // We used to compare the measured size of the content to the screen size but
22839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // this does not work anymore due to the 2 following issues:
22939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // - If the content is in a decor (system bar, title/action bar), the root view
23039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            //   will not resize even with the UNSPECIFIED because of the embedded layout.
23139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // - If there is no decor, but a dialog frame, then the dialog padding prevents
23239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            //   comparing the size of the content to the screen frame (as it would not
23339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            //   take into account the dialog padding).
23439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
23539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // The solution is to first get the content size in a normal rendering, inside
23639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // the decor or the dialog padding.
23739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // Then measure only the content with UNSPECIFIED to see the size difference
23839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // and apply this to the screen size.
23939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
24039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // first measure the full layout, with EXACTLY to get the size of the
24139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // content as it is inside the decor/dialog
24239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            @SuppressWarnings("deprecation")
24339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            Pair<Integer, Integer> exactMeasure = measureView(
24439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mViewRoot, mContentRoot.getChildAt(0),
24539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
24639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
24739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
24839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // now measure the content only using UNSPECIFIED (where applicable, based on
24939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // the rendering mode). This will give us the size the content needs.
25039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            @SuppressWarnings("deprecation")
25139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            Pair<Integer, Integer> result = measureView(
25239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mContentRoot, mContentRoot.getChildAt(0),
25339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth, widthMeasureSpecMode,
25439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight, heightMeasureSpecMode);
25539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
25639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            // now look at the difference and add what is needed.
25739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            if (renderingMode.isHorizExpand()) {
25839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int measuredWidth = exactMeasure.getFirst();
25939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int neededWidth = result.getFirst();
26039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (neededWidth > measuredWidth) {
26139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth += neededWidth - measuredWidth;
26239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
26339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (mMeasuredScreenWidth < measuredWidth) {
26439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // If the screen width is less than the exact measured width,
26539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // expand to match.
26639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth = measuredWidth;
26739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
26839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            }
26939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
27039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            if (renderingMode.isVertExpand()) {
27139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int measuredHeight = exactMeasure.getSecond();
27239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                int neededHeight = result.getSecond();
27339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (neededHeight > measuredHeight) {
27439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight += neededHeight - measuredHeight;
27539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
27639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (mMeasuredScreenHeight < measuredHeight) {
27739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // If the screen height is less than the exact measured height,
27839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    // expand to match.
27939e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight = measuredHeight;
28039e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                }
28139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            }
28239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez        }
28339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    }
28439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
28539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez    /**
286c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Inflates the layout.
287c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
2882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
2892eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2902eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
2912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
292c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
29319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result inflate() {
2942eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
2952eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
296c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
297b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mViewRoot = new Layout(mLayoutBuilder);
298b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mLayoutBuilder = null;  // Done with the builder.
299b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mContentRoot = ((Layout) mViewRoot).getContentRoot();
300b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            SessionParams params = getParams();
301b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            BridgeContext context = getContext();
302c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
303c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
304c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // it can instantiate the custom Fragment.
30537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback());
306c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3071f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
30810bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            boolean isPreference = "PreferenceScreen".equals(rootTag);
30910bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            View view;
31010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            if (isPreference) {
31110bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = Preference_Delegate.inflatePreference(getContext(), mBlockParser,
312b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                        mContentRoot);
31310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            } else {
31410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = mInflater.inflate(mBlockParser, mContentRoot);
31510bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            }
316c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3172fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // done with the parser, pop it.
3182fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            context.popParser();
3192fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
32037dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(null);
321c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
322c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // set the AttachInfo on the root view.
3237f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet            AttachInfo_Accessor.setAttachInfo(mViewRoot);
324c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
32533758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
32637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
327ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.onDoneInflation();
32833758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet
3294dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            setActiveToolbar(view, context, params);
3304dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
33139e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            measure(params);
33239e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            measureView(mViewRoot, null /*measuredView*/,
33339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
33439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
33539e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
33639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
33739e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    false);
33839e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez
33919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
340c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (PostInflateException e) {
34119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
342c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
343c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
344c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
345c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
346c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
347c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
348c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
34919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
350c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
351c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
352c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
353c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
35429ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     * Sets the time for which the next frame will be selected. The time is the elapsed time from
35529ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     * the current system nanos time. You
35629ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     */
35729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    public void setElapsedFrameTimeNanos(long nanos) {
35829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez        mElapsedFrameTimeNanos = nanos;
35929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    }
36029ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez
36129ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /**
3622605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * Renders the given view hierarchy to the passed canvas and returns the result of the render
3632605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * operation.
3642605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * @param canvas an optional canvas to render the views to. If null, only the measure and
3652605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     * layout steps will be executed.
3662605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez     */
3672605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    private static Result render(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot,
3682605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            @Nullable Canvas canvas, int width, int height) {
3692605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        // measure again with the size we need
3702605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        // This must always be done before the call to layout
3712605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        measureView(viewRoot, null /*measuredView*/,
3722605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                width, MeasureSpec.EXACTLY,
3732605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                height, MeasureSpec.EXACTLY);
3742605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3752605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        // now do the layout.
3762605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        viewRoot.layout(0, 0, width, height);
3772605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        handleScrolling(context, viewRoot);
3782605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3792605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        if (canvas == null) {
3802605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            return SUCCESS.createResult();
3812605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        }
3822605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3832605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        AttachInfo_Accessor.dispatchOnPreDraw(viewRoot);
3842605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        viewRoot.draw(canvas);
3852605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3862605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez        return SUCCESS.createResult();
3872605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    }
3882605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
3892605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    /**
390c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Renders the scene.
391c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
3922eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
3932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
3945a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
3955a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
3965a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      animations.)
3975a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *
3982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
3992eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
4009eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet     *
4011b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see SessionParams#getRenderingMode()
402bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#render(long)
403c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
4045a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet    public Result render(boolean freshRender) {
4052eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
4062eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
407b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
408b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
409c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
410c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mViewRoot == null) {
41119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
412c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
413c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
41439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            measure(params);
415c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
41639e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez            HardwareConfig hardwareConfig = params.getHardwareConfig();
4172605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            Result renderResult = SUCCESS.createResult();
41810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            if (params.isLayoutOnly()) {
41910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // delete the canvas and image to reset them on the next full rendering
42010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mImage = null;
42110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mCanvas = null;
42210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            } else {
42310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // draw the views
42410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // create the BufferedImage into which the layout will be rendered.
42510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                boolean newImage = false;
4262c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez
4272c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // When disableBitmapCaching is true, we do not reuse mImage and
4282c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // we create a new one in every render.
4292c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // This is useful when mImage is just a wrapper of Graphics2D so
4302c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // it doesn't get cached.
4312c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
4321f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
43339e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                if (mNewRenderSize || mCanvas == null || disableBitmapCaching) {
43439e540caffca2584aa6c4cb74ce42dceb24a93f7Diego Perez                    mNewRenderSize = false;
43510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.getImageFactory() != null) {
43610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = params.getImageFactory().getImage(
43710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
43810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight);
43910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    } else {
44010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = new BufferedImage(
44110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
44210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight,
44310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                BufferedImage.TYPE_INT_ARGB);
44410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
44510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
44610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
44710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.isBgColorOverridden()) {
44810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        // since we override the content, it's the same as if it was a new image.
44910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
45010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        Graphics2D gc = mImage.createGraphics();
45110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setColor(new Color(params.getOverrideBgColor(), true));
45210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setComposite(AlphaComposite.Src);
45310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
45410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.dispose();
45510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
45610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
45710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // create an Android bitmap around the BufferedImage
45810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
459891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                            true /*isMutable*/, hardwareConfig.getDensity());
46010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
4612c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    if (mCanvas == null) {
4622c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        // create a Canvas around the Android bitmap
4632c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas = new Canvas(bitmap);
4642c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    } else {
4652c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas.setBitmap(bitmap);
4662c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    }
467891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
4689eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
469c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4701ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                if (freshRender && !newImage) {
4719eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
4725a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
473c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
47410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.setColor(new Color(0x00000000, true));
4754ea74d2960688db6aa13452765dd5f2d07a40189Deepanshu Gupta                    gc.fillRect(0, 0,
4764ea74d2960688db6aa13452765dd5f2d07a40189Deepanshu Gupta                            mMeasuredScreenWidth, mMeasuredScreenHeight);
47716584225125acba18b74920b902c798dfead0328Xavier Ducrohet
47810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // done
47910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.dispose();
48010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                }
48116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
48229ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                if (mElapsedFrameTimeNanos >= 0) {
48329ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    long initialTime = System_Delegate.nanoTime();
48429ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    if (!mFirstFrameExecuted) {
4852605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                        // We need to run an initial draw call to initialize the animations
4862605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                        render(getContext(), mViewRoot, mCanvas, 0, 0);
4872605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez
48829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        // The first frame will initialize the animations
48929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        Choreographer_Delegate.doFrame(initialTime);
49029ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        mFirstFrameExecuted = true;
49129ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    }
49229ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    // Second frame will move the animations
49329ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
49429ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                }
4952605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                renderResult = render(getContext(), mViewRoot, mCanvas, mMeasuredScreenWidth,
4962605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                        mMeasuredScreenHeight);
4975a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            }
4985a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet
4995ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
5005ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    false);
501c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
502c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // success!
5032605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            return renderResult;
504c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
505c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
506c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
507c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
508c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
509c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
510c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
51119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
512c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
513c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
514c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
515c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
516c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
517c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
518c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
519c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
520c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
521c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
522c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param viewToMeasure the view on which to execute measure().
523c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param measuredView if non null, the view to query for its measured width/height.
524c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param width the width to use in the MeasureSpec.
525c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param widthMode the MeasureSpec mode to use for the width.
526c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param height the height to use in the MeasureSpec.
527c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param heightMode the MeasureSpec mode to use for the height.
528c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @return the measured width/height if measuredView is non-null, null otherwise.
529c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     */
5301ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
5312605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
532c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            int width, int widthMode, int height, int heightMode) {
533c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
534c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
535c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        viewToMeasure.measure(w_spec, h_spec);
536c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
537c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        if (measuredView != null) {
538c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight());
539c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        }
540c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
541c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        return null;
542c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    }
543c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
544c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    /**
5452eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Animate an object
5462eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * <p>
5472eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
5482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
5492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
5502eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
551e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
552bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
5532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
55419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
5552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
5562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
5572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
558b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
559b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
5602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // find the animation file.
5611ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        ResourceValue animationResource;
5622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        int animationId = 0;
5632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (isFrameworkAnimation) {
564b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getFrameworkResource(
56535ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
5662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
567b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
5682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5692eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } else {
570b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getProjectResource(
57135ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
5722eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
57337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                animationId = context.getLayoutlibCallback().getResourceId(
57435ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
5752eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5762eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5772eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
5782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (animationResource != null) {
5792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            try {
580b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(context, animationId);
5812eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (anim != null) {
5822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    anim.setTarget(targetObject);
5832eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
584e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
5852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
58619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    return SUCCESS.createResult();
5872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
5882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            } catch (Exception e) {
589c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                // get the real cause of the exception.
590c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                Throwable t = e;
591c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                while (t.getCause() != null) {
592c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                    t = t.getCause();
593c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                }
594c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
59519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5962eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
59919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
600c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
601c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
602e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
603e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Insert a new child into an existing parent.
604e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
605e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
606e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
607e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
608e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
609e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
610bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
611e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
61219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
613e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final int index, IAnimationListener listener) {
614c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
615c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
616b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
617b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
618c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // create a block parser for the XML
61902d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
62002d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet                childXml, context, false /* platformResourceFlag */);
621c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
622c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
623c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
624c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // be created correctly.
625e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
62602d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        blockParser.ensurePopped();
627c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
628e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
629e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
630e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
631e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
632e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
633e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
63419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
635e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
636e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return addView(parentView, child, index);
637e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
638e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
639e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
640e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
641e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(null);
642e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
643e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
644e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
645e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
64619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(child);
6479eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        }
6489eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
649e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        // add it to the parentView in the correct location
65019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = addView(parentView, child, index);
6511ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
652e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
653e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
654c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
6555a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
656c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        if (result.isSuccess()) {
657e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(child);
658c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        }
659c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet
660c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        return result;
661c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
662c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
663e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
664e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Adds a given view to a given parent at a given index.
665e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
666e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param parent the parent to receive the view
667e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to add to the parent
668e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the index where to do the add.
669e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
67019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
67119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
672e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
673e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
67419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
675e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
676e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.addView(view, index);
67719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
678e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
679e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
68019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
681e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
682e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
683e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
684e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
685e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a view to a new parent at a given location
686e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
687e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
688e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
689e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
690e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
691e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
692bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
693e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
6942b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
695479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
696c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
697c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
698e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
699e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
70001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        LayoutParams layoutParams = null;
701e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (layoutParamsMap != null) {
702e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
7032b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
704e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
705e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
7069eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
7072b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        // get the current parent of the view that needs to be moved.
7082b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
7092b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
710e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
711e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final LayoutParams params = layoutParams;
71201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
713479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
714479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
715479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousParent != newParentView) {
716479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new Thread("not animated moveChild") {
717479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
718479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void run() {
719479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
720479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                params);
7211ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
722479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
723479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
724479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
725479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // ready to do the work, acquire the scene.
726479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        result = acquire(250);
7271ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
728479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
729479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            return;
730479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
731479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
732479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        try {
7335a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                            result = render(false /*freshRender*/);
734479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            if (result.isSuccess()) {
735479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
736479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            }
737479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        } finally {
738479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            release();
739479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
740479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
741479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        listener.done(result);
7422b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
743479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
744479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            } else {
745479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
7462b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
747479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
748479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public Result preAnimation() {
749479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // set up the transition for the parent.
750479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
751479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(transition);
7527550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet
753479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
754479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // animation playing just before).
755479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
756479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // on the LayoutTransition.
757479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
758479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
759479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
76001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
761479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
762479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
763479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
764479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
765479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
766479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
767479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
768479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
769479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
770479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
771479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
772479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
773479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void postAnimation() {
774479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(null);
775479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        newParentView.setLayoutTransition(null);
776479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
777479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
778479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            }
779e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
780e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
78119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
782c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
783c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7842b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
7851ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
786e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
787e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
788c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7895a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
79001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
791e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
79201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        }
79301811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
79401811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        return result;
795c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
796c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
797e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
798e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
799e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * an optional new {@link LayoutParams} instance
800e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
8012b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
8022b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param newParent the new parent
803479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet     * @param movedView the view to move
804e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the new location in the new parent
805e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
806e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
80719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
80819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
809e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
810e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
811479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
812479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
8139eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        try {
8142b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            // check if there is a transition on the previousParent.
815479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
816479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousTransition != null) {
8177550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
8187550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
8197550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
8207550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
8217550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // to handle).
8227550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
8237550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
8247550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // adding the child or the child will appear in its new location before the
8257550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // other children have made room for it.
8262b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8272b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
828479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
829479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    private int mChangeDisappearingCount = 0;
8302b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
83146d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
8322b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
8332b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
834479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
835479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount++;
836479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
8372b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
838e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
83946d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
8402b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
8412b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
842479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
843479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount--;
844479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
845479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
846479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
847479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                mChangeDisappearingCount == 0) {
8482b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            // add it to the parentView in the correct location
8492b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            if (params != null) {
850479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index, params);
8512b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            } else {
852479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index);
8532b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            }
8542b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                        }
8552b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
8562b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                });
8572b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8582b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // remove the view from the current parent.
859479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
8602b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8612b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
8622b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
863e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            } else {
8642b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // standard code with no animation. pretty simple.
865479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
866e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8672b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add it to the parentView in the correct location
8682b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                if (params != null) {
869479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index, params);
8702b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                } else {
871479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index);
8722b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                }
8732b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8742b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
8752b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            }
8769eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        } catch (UnsupportedOperationException e) {
8779eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
87819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
879c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
880e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
881e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
882e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
883e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a child from its current parent.
884e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
885e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
886e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
887e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
888e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
889e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
890bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#removeChild(Object, IAnimationListener)
891e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
89219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
893e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        checkLock();
894c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
8959eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        invalidateRenderingSize();
8969eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
897e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
898e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
899e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
900e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
901e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
902e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
90319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
904e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
905e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return removeView(parent, childView);
906e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
907e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
908e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
909e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
910e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(null);
911e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
912e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
913e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
914e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
91519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
916e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
917e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
91819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = removeView(parent, childView);
9191ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
920e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
921e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
922e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
9235a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        return render(false /*freshRender*/);
9242eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
9252eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
9262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
927e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a given view from its current parent.
928e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
929e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to remove from its parent
930e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
93119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
93219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
933e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
934e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
93519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
936e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
937e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.removeView(view);
93819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
939e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
940e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
94119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
942e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
943e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
944e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
945c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
9461ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * Post process on a view hierarchy that was just inflated.
9471ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * <p/>
9481ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
949c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
950c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
951c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root view to process.
95237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback callback to the project.
95310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta     * @param skip the view and it's children are not processed.
954c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
9551ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
95637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip)
957c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
95810bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        if (view == skip) {
95910bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            return;
96010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        }
961c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof TabHost) {
96237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            setupTabHost((TabHost) view, layoutlibCallback);
96331fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
96431fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
96531fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            badge.setImageToDefault();
9662fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet        } else if (view instanceof AdapterView<?>) {
9672fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get the view ID.
9682fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            int id = view.getId();
9692fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9702fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            BridgeContext context = getContext();
9712fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9722fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get a ResourceReference from the integer ID.
9732fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            ResourceReference listRef = context.resolveId(id);
9742fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9752fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            if (listRef != null) {
9762fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                SessionParams params = getParams();
9772fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                AdapterBinding binding = params.getAdapterBindings().get(listRef);
9782fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9792fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                // if there was no adapter binding, trying to get it from the call back.
9802fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding == null) {
98137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                    binding = layoutlibCallback.getAdapterBinding(
98237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                            listRef, context.getViewKey(view), view);
9832fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
9842fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9852fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding != null) {
9862fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9872fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    if (view instanceof AbsListView) {
9882fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) &&
9892fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                view instanceof ListView) {
9902fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ListView list = (ListView) view;
9912fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9922fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            boolean skipCallbackParser = false;
9932fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9942fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            int count = binding.getHeaderCount();
99510bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
9962fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
9972fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getHeaderAt(i),
99837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
9992fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
10002fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addHeaderView(pair.getFirst());
10012fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
10022fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10032fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
10042fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
10052fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10062fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            count = binding.getFooterCount();
100710bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
10082fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
10092fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getFooterAt(i),
101037dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
10112fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
10122fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addFooterView(pair.getFirst());
10132fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
10142fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10152fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
10162fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
10172fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
10182fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
10192fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if (view instanceof ExpandableListView) {
10202fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((ExpandableListView) view).setAdapter(
102137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeExpandableAdapter(listRef, binding, layoutlibCallback));
10222fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        } else {
10232fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((AbsListView) view).setAdapter(
102437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeAdapter(listRef, binding, layoutlibCallback));
10252fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
10262fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    } else if (view instanceof AbsSpinner) {
10272fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        ((AbsSpinner) view).setAdapter(
102837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                new FakeAdapter(listRef, binding, layoutlibCallback));
10292fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    }
10302fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
10312fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            }
1032c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } else if (view instanceof ViewGroup) {
1033ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.postInflateProcess(view);
103410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            ViewGroup group = (ViewGroup) view;
1035c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            final int count = group.getChildCount();
103610bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            for (int c = 0; c < count; c++) {
1037c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                View child = group.getChildAt(c);
103837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                postInflateProcess(child, layoutlibCallback, skip);
1039c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1040c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1041c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1042c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1043c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
10444dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * If the root layout is a CoordinatorLayout with an AppBar:
10454dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * Set the title of the AppBar to the title of the activity context.
10464dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
10474dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
10484dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
10494dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (coordinatorLayout == null) {
10504dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10514dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10524dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
10534dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (appBar == null) {
10544dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10554dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10564dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup collapsingToolbar =
10574dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
10584dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (collapsingToolbar == null) {
10594dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10604dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10614dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!hasToolbar(collapsingToolbar)) {
10624dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10634dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10644dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        RenderResources res = context.getRenderResources();
10654dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        String title = params.getAppLabel();
10664dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ResourceValue titleValue = res.findResValue(title, false);
10674dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (titleValue != null && titleValue.getValue() != null) {
10684dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            title = titleValue.getValue();
10694dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10704dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        DesignLibUtil.setTitle(collapsingToolbar, title);
10714dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10724dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10734dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private View findChildView(View view, String className) {
10744dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
10754dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return null;
10764dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10774dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
10784dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10794dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), className)) {
10804dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return group.getChildAt(i);
10814dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10824dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10834dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return null;
10844dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10854dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10864dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private boolean hasToolbar(View collapsingToolbar) {
10874dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(collapsingToolbar instanceof ViewGroup)) {
10884dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return false;
10894dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10904dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) collapsingToolbar;
10914dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10924dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
10934dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return true;
10944dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10954dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10964dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return false;
10974dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10984dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10994dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
1100d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * Set the scroll position on all the components with the "scrollX" and "scrollY" attribute. If
1101d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * the component supports nested scrolling attempt that first, then use the unconsumed scroll
1102d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * part to scroll the content in the component.
11034dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
11042605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez    private static void handleScrolling(BridgeContext context, View view) {
1105d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        int scrollPosX = context.getScrollXPos(view);
1106d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        int scrollPosY = context.getScrollYPos(view);
1107d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        if (scrollPosX != 0 || scrollPosY != 0) {
11084dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (view.isNestedScrollingEnabled()) {
11094dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                int[] consumed = new int[2];
1110d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                int axis = scrollPosX != 0 ? View.SCROLL_AXIS_HORIZONTAL : 0;
1111d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                axis |= scrollPosY != 0 ? View.SCROLL_AXIS_VERTICAL : 0;
1112d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                if (view.startNestedScroll(axis)) {
1113d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view.dispatchNestedPreScroll(scrollPosX, scrollPosY, consumed, null);
1114d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view.dispatchNestedScroll(consumed[0], consumed[1], scrollPosX, scrollPosY,
1115d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                            null);
11164dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                    view.stopNestedScroll();
1117d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    scrollPosX -= consumed[0];
1118d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    scrollPosY -= consumed[1];
11194dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                }
11204dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
1121d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            if (scrollPosX != 0 || scrollPosY != 0) {
11222605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez                view.scrollTo(scrollPosX, scrollPosY);
11234dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
11244dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
11254dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
11264dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
11274dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
11284dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
11294dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
11304dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
11314dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            View child = group.getChildAt(i);
11322605f91f705fbf51800c6fde8ee8cd5f199447b4Diego Perez            handleScrolling(context, child);
11334dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
11344dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
11354dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
11364dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
1137c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Sets up a {@link TabHost} object.
1138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param tabHost the TabHost to setup.
113937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback The project callback object to access the project R class.
1140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @throws PostInflateException
1141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
114237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback)
1143c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
1145c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
1146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1147c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1148c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1149c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
1150c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1151c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11521ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof TabWidget)) {
1153c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1154c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
1155c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
1156c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1157c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1158c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
1159c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1160c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
11611ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
11621ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1163c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1164c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
1165c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1166c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11671ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof FrameLayout)) {
11681ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1169c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1170c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
1171c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
1172c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1173c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1174c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
1175c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11761ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        // now process the content of the frameLayout and dynamically create tabs for it.
1177c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        final int count = content.getChildCount();
1178c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1179c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
1180c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // and FrameLayout.
1181c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        tabHost.setup();
1182c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1183796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        if (count == 0) {
1184796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // Create a dummy child to get a single tab
118549ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta            TabSpec spec = tabHost.newTabSpec("tag")
118649ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                    .setIndicator("Tab Label", tabHost.getResources()
118749ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                            .getDrawable(android.R.drawable.ic_menu_info_details, null))
1188796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
118946d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                        @Override
1190796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        public View createTabContent(String tag) {
1191b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                            return new LinearLayout(getContext());
1192796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        }
1193796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    });
1194796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            tabHost.addTab(spec);
1195796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        } else {
11961ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // for each child of the frameLayout, add a new TabSpec
1197796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            for (int i = 0 ; i < count ; i++) {
1198796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                View child = content.getChildAt(i);
1199796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
120010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                @SuppressWarnings("ConstantConditions")  // child cannot be null.
1201796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                int id = child.getId();
12021ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                @SuppressWarnings("deprecation")
120337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                Pair<ResourceType, String> resource = layoutlibCallback.resolveResourceId(id);
1204796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String name;
1205796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                if (resource != null) {
1206b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                    name = resource.getSecond();
1207796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                } else {
1208796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1209796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                }
1210796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
1211c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1212c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1213c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1214c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
12154ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12164ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
12174ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views.
12184ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12194ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param view the root View
12204ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds.
12214ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
12224ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
12234ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame.
12244ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12254ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
12264ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
12274ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
12284ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
12294ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
1230bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12314ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
12324ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            ViewGroup group = ((ViewGroup) view);
12334ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
12344ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    setExtendedInfo, isContentFrame));
12354ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
12364ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
12374ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1238bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12394ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
12411b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with
12424ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * the children of the {@code mContentRoot}.
12434ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12444ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param viewGroup the root View
12454ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset from the top for the content view frame.
12464ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
12474ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
12484ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame. {@code false} if the {@code ViewInfo} to be created is
12494ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       part of the system decor.
12504ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
12514ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
12524ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean setExtendedInfo, boolean isContentFrame) {
12534ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == null) {
12544ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return null;
1255bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
1256bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12574ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (!isContentFrame) {
12584ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            offset += viewGroup.getTop();
12594ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1260bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12614ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        int childCount = viewGroup.getChildCount();
12624ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == mContentRoot) {
12634ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
12644ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
12654ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
12664ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
126705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                        setExtendedInfo);
12684ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithoutOffset.add(childViewInfo[0]);
12694ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithOffset.add(childViewInfo[1]);
1270bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            }
12714ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            mViewInfoList = childrenWithOffset;
12724ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return childrenWithoutOffset;
12734ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
12744ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
12754ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
12764ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
12774ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                        isContentFrame));
12784ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            }
12794ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return children;
1280bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
12814ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1282bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12834ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12844ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
12854ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
12864ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * one with the {@code offset} and other without the {@code offset}. The offset is needed to
12874ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * get the right bounds if the {@code ViewInfo} hierarchy is accessed from
12884ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
12894ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * offset is not needed.
12904ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12914ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
12924ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *         index 1 is with the offset.
12934ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
1294d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @NonNull
12954ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
12964ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo[] result = new ViewInfo[2];
12974ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view == null) {
12984ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return result;
12994ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
13004ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
13014ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[0] = createViewInfo(view, 0, setExtendedInfo, true);
13024ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[1] = createViewInfo(view, offset, setExtendedInfo, true);
13034ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
13044ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
13054ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[0].setChildren(children);
13064ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[1].setChildren(children);
13074ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
13084ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
1309bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    }
1310c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1311c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
13124ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
13134ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
13144ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * set.
13154ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds. Used only if view is part of the content frame.
1316c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
13174ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
13184ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
1319c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view == null) {
1320c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            return null;
1321c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1322c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1323d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        ViewParent parent = view.getParent();
13244ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result;
13254ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (isContentFrame) {
1326d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            // Account for parent scroll values when calculating the bounding box
1327d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            int scrollX = parent != null ? ((View)parent).getScrollX() : 0;
1328d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            int scrollY = parent != null ? ((View)parent).getScrollY() : 0;
1329d15459197f71f8cc940e2b057b399117df282f2cDiego Perez
1330bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // The view is part of the layout added by the user. Hence,
1331bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // the ViewCookie may be obtained only through the Context.
13324ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result = new ViewInfo(view.getClass().getName(),
1333bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    getContext().getViewKey(view),
1334d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    -scrollX + view.getLeft(), -scrollY + view.getTop() + offset,
1335d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    -scrollX + view.getRight(), -scrollY + view.getBottom() + offset,
1336d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view, view.getLayoutParams());
13374ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
1338bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We are part of the system decor.
1339bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
13405ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    getViewKey(view),
13414ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getLeft(), view.getTop(), view.getRight(),
13424ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getBottom(), view, view.getLayoutParams());
1343bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            result = r;
1344bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We currently mark three kinds of views:
1345bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 1. Menus in the Action Bar
1346bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 2. Menus in the Overflow popup.
1347bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 3. The overflow popup button.
1348bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            if (view instanceof ListMenuItemView) {
1349bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 2.
1350bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // All menus in the popup are of type ListMenuItemView.
1351bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                r.setViewType(ViewType.ACTION_BAR_OVERFLOW_MENU);
1352bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            } else {
1353bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 3.
1354bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                ViewGroup.LayoutParams lp = view.getLayoutParams();
1355bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                if (lp instanceof ActionMenuView.LayoutParams &&
1356bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        ((ActionMenuView.LayoutParams) lp).isOverflowButton) {
1357bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    r.setViewType(ViewType.ACTION_BAR_OVERFLOW);
1358bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                } else {
1359bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // Mark 1.
1360bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // A view is a menu in the Action Bar is it is not the overflow button and of
1361bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // its parent is of type ActionMenuView. We can also check if the view is
1362bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // instanceof ActionMenuItemView but that will fail for menus using
1363bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // actionProviderClass.
1364bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    while (parent != mViewRoot && parent instanceof ViewGroup) {
1365bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        if (parent instanceof ActionMenuView) {
1366bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            r.setViewType(ViewType.ACTION_BAR_MENU);
1367bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            break;
1368bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        }
1369bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        parent = parent.getParent();
1370bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    }
1371bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                }
1372bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            }
13734ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1374c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
137505b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        if (setExtendedInfo) {
137605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            MarginLayoutParams marginParams = null;
137705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            LayoutParams params = view.getLayoutParams();
137805b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            if (params instanceof MarginLayoutParams) {
137905b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                marginParams = (MarginLayoutParams) params;
138005b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            }
138105b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            result.setExtendedInfo(view.getBaseline(),
138205b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.leftMargin : 0,
138305b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.topMargin : 0,
138405b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.rightMargin : 0,
138505b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.bottomMargin : 0);
138605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        }
138705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet
1388c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return result;
1389c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1390c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1391bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta    /* (non-Javadoc)
13925ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * The cookie for menu items are stored in menu item and not in the map from View stored in
13935ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * BridgeContext.
13945ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     */
1395d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @Nullable
13965ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    private Object getViewKey(View view) {
13975ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        BridgeContext context = getContext();
13985ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (!(view instanceof MenuView.ItemView)) {
13995ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return context.getViewKey(view);
14005ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
14015ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        MenuItemImpl menuItem;
14025ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (view instanceof ActionMenuItemView) {
14035ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ActionMenuItemView) view).getItemData();
14045ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof ListMenuItemView) {
14055ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ListMenuItemView) view).getItemData();
14065ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof IconMenuItemView) {
14075ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((IconMenuItemView) view).getItemData();
14085ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else {
14095ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = null;
14105ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
14115ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (menuItem instanceof BridgeMenuItemImpl) {
14125ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return ((BridgeMenuItemImpl) menuItem).getViewCookie();
14135ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
14145ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
14155ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        return null;
14165ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    }
14175ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
1418c13aa0c035cd226d27323bc0e533632ba32f6a84Diego Perez    public void invalidateRenderingSize() {
14194ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
14204ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
14214ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
1422c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    public BufferedImage getImage() {
1423c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return mImage;
1424c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1425c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
142616584225125acba18b74920b902c798dfead0328Xavier Ducrohet    public boolean isAlphaChannelImage() {
142716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return mIsAlphaChannelImage;
142816584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
142916584225125acba18b74920b902c798dfead0328Xavier Ducrohet
14307d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    public List<ViewInfo> getViewInfos() {
14317d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return mViewInfoList;
1432c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1433cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet
14344ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    public List<ViewInfo> getSystemViewInfos() {
14354ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return mSystemViewInfoList;
14364ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
14374ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
1438eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta    public Map<Object, PropertiesMap> getDefaultProperties() {
1439eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta        return getContext().getDefaultProperties();
1440eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta    }
1441eaf1853b98d7bf2c3d693ad702050968ef0a404cDeepanshu Gupta
144219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public void setScene(RenderSession session) {
144319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mScene = session;
1444c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1445c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
144619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public RenderSession getSession() {
1447c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        return mScene;
1448c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1449f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez
1450f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez    public void dispose() {
14515d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        boolean createdLooper = false;
14525d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        if (Looper.myLooper() == null) {
14535d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // Detaching the root view from the window will try to stop any running animations.
14545d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // The stop method checks that it can run in the looper so, if there is no current
14555d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // looper, we create a temporary one to complete the shutdown.
14565d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            Bridge.prepareThread();
14575d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            createdLooper = true;
14585d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        }
1459f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        AttachInfo_Accessor.detachFromWindow(mViewRoot);
1460f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mCanvas != null) {
1461f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mCanvas.release();
1462f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mCanvas = null;
1463f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1464f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mViewInfoList != null) {
1465f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mViewInfoList.clear();
1466f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1467f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mSystemViewInfoList != null) {
1468f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mSystemViewInfoList.clear();
1469f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1470f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mImage = null;
1471f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mViewRoot = null;
1472f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mContentRoot = null;
14735d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez
14745d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        if (createdLooper) {
14755d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            Bridge.cleanupThread();
147661ccc9198ab09363edbf500d7669dbcfafc5fa28Deepanshu Gupta            Choreographer_Delegate.dispose();
14775d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        }
1478f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez    }
1479c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet}
1480