RenderSessionImpl.java revision 61ccc9198ab09363edbf500d7669dbcfafc5fa28
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;
51c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
527f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.animation.AnimationThread;
53e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.Animator;
542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.animation.AnimatorInflater;
55e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.LayoutTransition;
562b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
57476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull;
58476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable;
59c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.app.Fragment_Delegate;
60c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap;
61c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
62c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Canvas;
635d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perezimport android.os.Looper;
6410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Guptaimport android.preference.Preference_Delegate;
657f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.AttachInfo_Accessor;
667f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.BridgeInflater;
6729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perezimport android.view.Choreographer_Delegate;
686dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.IWindowManager;
69891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohetimport android.view.IWindowManagerImpl;
706dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.Surface;
71c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View;
72c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.MeasureSpec;
7346d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.view.ViewGroup;
7401811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport android.view.ViewGroup.LayoutParams;
7505b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohetimport android.view.ViewGroup.MarginLayoutParams;
76bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.view.ViewParent;
776dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.WindowManagerGlobal_Delegate;
782fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsListView;
792fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsSpinner;
80bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.widget.ActionMenuView;
812fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AdapterView;
822fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ExpandableListView;
83c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.FrameLayout;
84796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.LinearLayout;
852fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ListView;
8631fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohetimport android.widget.QuickContactBadge;
87c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabHost;
88796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.TabHost.TabSpec;
8946d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.widget.TabWidget;
90c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
915a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohetimport java.awt.AlphaComposite;
92c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Color;
93c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Graphics2D;
94c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.image.BufferedImage;
95c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.ArrayList;
96c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.List;
97c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.Map;
98c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
9937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
10037dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
10137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
10237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
10337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
10437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
10561f23e9bf7d784e7a52168196758c4f6c6853e77Deepanshu Guptaimport static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
10637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta
107c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/**
10819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * Class implementing the render session.
1091ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta * <p/>
11019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
11119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
112c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * be done on the layout.
113c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
114b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> {
115c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
116c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // scene state
11719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private RenderSession mScene;
118c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
119c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeInflater mInflater;
120bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private ViewGroup mViewRoot;
121bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private FrameLayout mContentRoot;
1229eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private Canvas mCanvas;
1239eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1249eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenHeight = -1;
125bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private boolean mIsAlphaChannelImage;
12629ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /** If >= 0, a frame will be executed */
12729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    private long mElapsedFrameTimeNanos = -1;
12829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /** True if one frame has been already executed to start the animations */
12929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    private boolean mFirstFrameExecuted = false;
13016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
131c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // information being returned through the API
132c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BufferedImage mImage;
1337d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    private List<ViewInfo> mViewInfoList;
1344ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> mSystemViewInfoList;
135b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta    private Layout.Builder mLayoutBuilder;
136c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
137c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final class PostInflateException extends Exception {
138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        private static final long serialVersionUID = 1L;
139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        public PostInflateException(String message) {
141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            super(message);
142c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
143c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
145c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
147c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
1481b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)},
1491b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * which act as a
15019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
151c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     *
1521b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see Bridge#createSession(SessionParams)
153c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1541126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohet    public RenderSessionImpl(SessionParams params) {
155b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        super(new SessionParams(params));
1562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
1572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
1592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
1602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * inflater, and parser.
1612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1622eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
1632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return whether the scene was prepared
1652eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #acquire(long)
1672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #release()
1682eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
169b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    @Override
17019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result init(long timeout) {
171b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Result result = super.init(timeout);
1721ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
1732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            return result;
1742eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
175c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
176b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
177b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
178c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
17916584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // use default of true in case it's not found to use alpha by default
180fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(),
181fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta                "windowIsFloating", true, true);
1822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
183b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mLayoutBuilder = new Layout.Builder(params, context);
184c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1856dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        // FIXME: find those out, and possibly add them to the render params
1866dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        boolean hasNavigationBar = true;
1871ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        //noinspection ConstantConditions
1886dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
189b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                context.getMetrics(), Surface.ROTATION_0, hasNavigationBar);
1906dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
1916dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet
192c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // build the inflater and parser.
19337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta        mInflater = new BridgeInflater(context, params.getLayoutlibCallback());
194b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        context.setBridgeInflater(mInflater);
1952eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
196b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false);
1972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
198168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet        return SUCCESS.createResult();
199c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
200c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
201c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
202c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Inflates the layout.
203c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
2042eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
2052eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2062eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
2072eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
208c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
20919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result inflate() {
2102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
2112eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
212c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
213b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mViewRoot = new Layout(mLayoutBuilder);
214b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mLayoutBuilder = null;  // Done with the builder.
215b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mContentRoot = ((Layout) mViewRoot).getContentRoot();
216b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            SessionParams params = getParams();
217b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            BridgeContext context = getContext();
218c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
219c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
220c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // it can instantiate the custom Fragment.
22137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback());
222c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
2231f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
22410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            boolean isPreference = "PreferenceScreen".equals(rootTag);
22510bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            View view;
22610bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            if (isPreference) {
22710bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = Preference_Delegate.inflatePreference(getContext(), mBlockParser,
228b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                        mContentRoot);
22910bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            } else {
23010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = mInflater.inflate(mBlockParser, mContentRoot);
23110bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            }
232c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
2332fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // done with the parser, pop it.
2342fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            context.popParser();
2352fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
23637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(null);
237c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
238c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // set the AttachInfo on the root view.
2397f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet            AttachInfo_Accessor.setAttachInfo(mViewRoot);
240c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
24133758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
24237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
243ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.onDoneInflation();
24433758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet
2454dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            setActiveToolbar(view, context, params);
2464dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
24719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
248c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (PostInflateException e) {
24919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
250c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
251c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
252c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
253c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
254c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
255c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
256c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
25719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
258c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
259c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
260c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
261c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
26229ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     * Sets the time for which the next frame will be selected. The time is the elapsed time from
26329ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     * the current system nanos time. You
26429ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez     */
26529ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    public void setElapsedFrameTimeNanos(long nanos) {
26629ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez        mElapsedFrameTimeNanos = nanos;
26729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    }
26829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez
26929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez    /**
270c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Renders the scene.
271c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
2722eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
2732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2745a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
2755a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
2765a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      animations.)
2775a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *
2782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
2792eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
2809eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet     *
2811b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see SessionParams#getRenderingMode()
282bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#render(long)
283c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
2845a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet    public Result render(boolean freshRender) {
2852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
2862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
287b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
288b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
289c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
290c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mViewRoot == null) {
29119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
292c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
293c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
294b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            RenderingMode renderingMode = params.getRenderingMode();
295891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet            HardwareConfig hardwareConfig = params.getHardwareConfig();
296fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet
2979eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // only do the screen measure when needed.
2989eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            boolean newRenderSize = false;
2999eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
3009eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                newRenderSize = true;
301891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
302891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
3039eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
3049eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
305c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
306c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
307c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            : MeasureSpec.EXACTLY;
308c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    int heightMeasureSpecMode = renderingMode.isVertExpand() ?
309c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
310c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            : MeasureSpec.EXACTLY;
311c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
312c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // We used to compare the measured size of the content to the screen size but
313c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // this does not work anymore due to the 2 following issues:
314c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // - If the content is in a decor (system bar, title/action bar), the root view
315c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    //   will not resize even with the UNSPECIFIED because of the embedded layout.
316c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // - If there is no decor, but a dialog frame, then the dialog padding prevents
317c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    //   comparing the size of the content to the screen frame (as it would not
318c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    //   take into account the dialog padding).
319c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
320c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // The solution is to first get the content size in a normal rendering, inside
321c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // the decor or the dialog padding.
322c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // Then measure only the content with UNSPECIFIED to see the size difference
323c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // and apply this to the screen size.
324c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
325c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // first measure the full layout, with EXACTLY to get the size of the
326c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // content as it is inside the decor/dialog
3271ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                    @SuppressWarnings("deprecation")
328c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    Pair<Integer, Integer> exactMeasure = measureView(
329c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mViewRoot, mContentRoot.getChildAt(0),
330c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenWidth, MeasureSpec.EXACTLY,
331c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenHeight, MeasureSpec.EXACTLY);
332c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
333c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // now measure the content only using UNSPECIFIED (where applicable, based on
334c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // the rendering mode). This will give us the size the content needs.
3351ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                    @SuppressWarnings("deprecation")
336c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    Pair<Integer, Integer> result = measureView(
337c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mContentRoot, mContentRoot.getChildAt(0),
338c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenWidth, widthMeasureSpecMode,
339c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenHeight, heightMeasureSpecMode);
340c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
341c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // now look at the difference and add what is needed.
3429eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
343c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int measuredWidth = exactMeasure.getFirst();
344c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int neededWidth = result.getFirst();
345c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        if (neededWidth > measuredWidth) {
346c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenWidth += neededWidth - measuredWidth;
3479eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
3484362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                        if (mMeasuredScreenWidth < measuredWidth) {
3494362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                            // If the screen width is less than the exact measured width,
3504362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                            // expand to match.
3514362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                            mMeasuredScreenWidth = measuredWidth;
3524362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                        }
353fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
354c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3559eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isVertExpand()) {
356c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int measuredHeight = exactMeasure.getSecond();
357c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int neededHeight = result.getSecond();
358c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        if (neededHeight > measuredHeight) {
359c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenHeight += neededHeight - measuredHeight;
3609eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
3614362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                        if (mMeasuredScreenHeight < measuredHeight) {
3624362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                            // If the screen height is less than the exact measured height,
3634362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                            // expand to match.
3644362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                            mMeasuredScreenHeight = measuredHeight;
3654362443cd9a5df6c5cc012881a0aaf96c927b923Diego Perez                        }
366fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
367c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
368c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
369c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
370c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            // measure again with the size we need
371c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // This must always be done before the call to layout
372c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            measureView(mViewRoot, null /*measuredView*/,
373c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
374c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
375c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
376c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // now do the layout.
37716584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
378c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3794dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            handleScrolling(mViewRoot);
3804dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
38110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            if (params.isLayoutOnly()) {
38210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // delete the canvas and image to reset them on the next full rendering
38310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mImage = null;
38410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mCanvas = null;
38510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            } else {
3867f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet                AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot);
38710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
38810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // draw the views
38910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // create the BufferedImage into which the layout will be rendered.
39010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                boolean newImage = false;
3912c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez
3922c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // When disableBitmapCaching is true, we do not reuse mImage and
3932c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // we create a new one in every render.
3942c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // This is useful when mImage is just a wrapper of Graphics2D so
3952c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // it doesn't get cached.
3962c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
3971f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
3982c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                if (newRenderSize || mCanvas == null || disableBitmapCaching) {
39910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.getImageFactory() != null) {
40010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = params.getImageFactory().getImage(
40110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
40210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight);
40310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    } else {
40410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = new BufferedImage(
40510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
40610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight,
40710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                BufferedImage.TYPE_INT_ARGB);
40810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
40910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
41010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
41110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.isBgColorOverridden()) {
41210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        // since we override the content, it's the same as if it was a new image.
41310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
41410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        Graphics2D gc = mImage.createGraphics();
41510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setColor(new Color(params.getOverrideBgColor(), true));
41610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setComposite(AlphaComposite.Src);
41710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
41810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.dispose();
41910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
42010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
42110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // create an Android bitmap around the BufferedImage
42210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
423891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                            true /*isMutable*/, hardwareConfig.getDensity());
42410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
4252c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    if (mCanvas == null) {
4262c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        // create a Canvas around the Android bitmap
4272c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas = new Canvas(bitmap);
4282c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    } else {
4292c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas.setBitmap(bitmap);
4302c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    }
431891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
4329eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
433c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4341ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                if (freshRender && !newImage) {
4359eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
4365a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
437c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
43810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.setColor(new Color(0x00000000, true));
4394ea74d2960688db6aa13452765dd5f2d07a40189Deepanshu Gupta                    gc.fillRect(0, 0,
4404ea74d2960688db6aa13452765dd5f2d07a40189Deepanshu Gupta                            mMeasuredScreenWidth, mMeasuredScreenHeight);
44116584225125acba18b74920b902c798dfead0328Xavier Ducrohet
44210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // done
44310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.dispose();
44410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                }
44516584225125acba18b74920b902c798dfead0328Xavier Ducrohet
44629ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                if (mElapsedFrameTimeNanos >= 0) {
44729ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    long initialTime = System_Delegate.nanoTime();
44829ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    if (!mFirstFrameExecuted) {
44929ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        // The first frame will initialize the animations
45029ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        Choreographer_Delegate.doFrame(initialTime);
45129ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                        mFirstFrameExecuted = true;
45229ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    }
45329ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    // Second frame will move the animations
45429ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                    Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
45529ed07524ce0fc2e5950f5340d306247145d0efaDiego Perez                }
45610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mViewRoot.draw(mCanvas);
4575a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            }
4585a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet
4595ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
4605ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    false);
461c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
462c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // success!
46319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
464c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
465c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
466c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
467c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
468c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
469c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
470c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
47119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
472c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
473c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
474c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
475c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
476c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
477c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
478c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
479c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
480c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
481c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
482c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param viewToMeasure the view on which to execute measure().
483c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param measuredView if non null, the view to query for its measured width/height.
484c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param width the width to use in the MeasureSpec.
485c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param widthMode the MeasureSpec mode to use for the width.
486c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param height the height to use in the MeasureSpec.
487c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param heightMode the MeasureSpec mode to use for the height.
488c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @return the measured width/height if measuredView is non-null, null otherwise.
489c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     */
4901ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
491c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
492c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            int width, int widthMode, int height, int heightMode) {
493c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
494c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
495c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        viewToMeasure.measure(w_spec, h_spec);
496c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
497c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        if (measuredView != null) {
498c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight());
499c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        }
500c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
501c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        return null;
502c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    }
503c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
504c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    /**
5052eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Animate an object
5062eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * <p>
5072eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
5082eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
5092eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
5102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
511e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
512bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
5132eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
51419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
5152eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
5162eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
5172eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
518b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
519b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
5202eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // find the animation file.
5211ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        ResourceValue animationResource;
5222eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        int animationId = 0;
5232eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (isFrameworkAnimation) {
524b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getFrameworkResource(
52535ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
5262eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
527b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
5282eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5292eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } else {
530b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getProjectResource(
53135ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
5322eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
53337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                animationId = context.getLayoutlibCallback().getResourceId(
53435ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
5352eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5362eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5372eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
5382eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (animationResource != null) {
5392eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            try {
540b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(context, animationId);
5412eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (anim != null) {
5422eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    anim.setTarget(targetObject);
5432eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
544e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
5452eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
54619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    return SUCCESS.createResult();
5472eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
5482eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            } catch (Exception e) {
549c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                // get the real cause of the exception.
550c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                Throwable t = e;
551c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                while (t.getCause() != null) {
552c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                    t = t.getCause();
553c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                }
554c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
55519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
55919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
560c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
561c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
562e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
563e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Insert a new child into an existing parent.
564e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
565e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
566e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
567e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
568e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
569e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
570bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
571e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
57219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
573e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final int index, IAnimationListener listener) {
574c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
575c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
576b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
577b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
578c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // create a block parser for the XML
57902d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
58002d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet                childXml, context, false /* platformResourceFlag */);
581c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
582c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
583c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
584c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // be created correctly.
585e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
58602d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        blockParser.ensurePopped();
587c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
588e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
589e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
590e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
591e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
592e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
593e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
59419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
595e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
596e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return addView(parentView, child, index);
597e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
598e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
599e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
600e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
601e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(null);
602e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
603e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
604e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
605e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
60619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(child);
6079eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        }
6089eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
609e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        // add it to the parentView in the correct location
61019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = addView(parentView, child, index);
6111ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
612e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
613e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
614c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
6155a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
616c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        if (result.isSuccess()) {
617e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(child);
618c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        }
619c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet
620c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        return result;
621c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
622c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
623e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
624e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Adds a given view to a given parent at a given index.
625e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
626e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param parent the parent to receive the view
627e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to add to the parent
628e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the index where to do the add.
629e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
63019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
63119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
632e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
633e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
63419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
635e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
636e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.addView(view, index);
63719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
638e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
639e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
64019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
641e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
642e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
643e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
644e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
645e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a view to a new parent at a given location
646e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
647e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
648e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
649e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
650e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
651e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
652bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
653e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
6542b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
655479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
656c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
657c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
658e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
659e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
66001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        LayoutParams layoutParams = null;
661e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (layoutParamsMap != null) {
662e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
6632b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
664e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
665e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
6669eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
6672b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        // get the current parent of the view that needs to be moved.
6682b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
6692b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
670e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
671e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final LayoutParams params = layoutParams;
67201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
673479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
674479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
675479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousParent != newParentView) {
676479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new Thread("not animated moveChild") {
677479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
678479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void run() {
679479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
680479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                params);
6811ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
682479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
683479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
684479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
685479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // ready to do the work, acquire the scene.
686479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        result = acquire(250);
6871ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
688479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
689479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            return;
690479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
691479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
692479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        try {
6935a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                            result = render(false /*freshRender*/);
694479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            if (result.isSuccess()) {
695479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
696479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            }
697479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        } finally {
698479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            release();
699479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
700479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
701479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        listener.done(result);
7022b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
703479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
704479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            } else {
705479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
7062b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
707479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
708479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public Result preAnimation() {
709479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // set up the transition for the parent.
710479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
711479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(transition);
7127550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet
713479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
714479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // animation playing just before).
715479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
716479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // on the LayoutTransition.
717479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
718479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
719479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
72001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
721479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
722479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
723479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
724479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
725479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
726479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
727479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
728479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
729479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
730479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
731479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
732479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
733479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void postAnimation() {
734479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(null);
735479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        newParentView.setLayoutTransition(null);
736479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
737479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
738479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            }
739e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
740e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
74119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
742c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
743c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7442b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
7451ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
746e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
747e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
748c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7495a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
75001811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
751e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
75201811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        }
75301811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
75401811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        return result;
755c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
756c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
757e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
758e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
759e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * an optional new {@link LayoutParams} instance
760e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
7612b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
7622b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param newParent the new parent
763479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet     * @param movedView the view to move
764e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the new location in the new parent
765e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
766e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
76719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
76819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
769e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
770e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
771479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
772479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
7739eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        try {
7742b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            // check if there is a transition on the previousParent.
775479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
776479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousTransition != null) {
7777550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
7787550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
7797550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
7807550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
7817550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // to handle).
7827550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
7837550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
7847550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // adding the child or the child will appear in its new location before the
7857550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // other children have made room for it.
7862b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7872b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
788479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
789479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    private int mChangeDisappearingCount = 0;
7902b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
79146d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
7922b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
7932b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
794479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
795479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount++;
796479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
7972b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
798e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
79946d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
8002b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
8012b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
802479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
803479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount--;
804479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
805479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
806479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
807479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                mChangeDisappearingCount == 0) {
8082b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            // add it to the parentView in the correct location
8092b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            if (params != null) {
810479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index, params);
8112b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            } else {
812479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index);
8132b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            }
8142b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                        }
8152b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
8162b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                });
8172b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8182b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // remove the view from the current parent.
819479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
8202b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8212b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
8222b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
823e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            } else {
8242b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // standard code with no animation. pretty simple.
825479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
826e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8272b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add it to the parentView in the correct location
8282b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                if (params != null) {
829479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index, params);
8302b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                } else {
831479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index);
8322b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                }
8332b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
8342b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
8352b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            }
8369eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        } catch (UnsupportedOperationException e) {
8379eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
83819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
839c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
840e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
841e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
842e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
843e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a child from its current parent.
844e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
845e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
846e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
847e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
848e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
849e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
850bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#removeChild(Object, IAnimationListener)
851e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
85219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
853e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        checkLock();
854c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
8559eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        invalidateRenderingSize();
8569eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
857e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
858e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
859e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
860e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
861e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
862e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
86319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
864e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
865e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return removeView(parent, childView);
866e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
867e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
868e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
869e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
870e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(null);
871e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
872e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
873e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
874e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
87519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
876e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
877e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
87819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = removeView(parent, childView);
8791ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
880e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
881e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
882e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8835a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        return render(false /*freshRender*/);
8842eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
8852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
8862eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
887e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a given view from its current parent.
888e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
889e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to remove from its parent
890e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
89119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
89219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
893e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
894e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
89519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
896e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
897e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.removeView(view);
89819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
899e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
900e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
90119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
902e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
903e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
904e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
905c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
9061ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * Post process on a view hierarchy that was just inflated.
9071ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * <p/>
9081ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
909c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
910c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
911c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root view to process.
91237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback callback to the project.
91310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta     * @param skip the view and it's children are not processed.
914c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
9151ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
91637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip)
917c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
91810bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        if (view == skip) {
91910bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            return;
92010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        }
921c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof TabHost) {
92237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            setupTabHost((TabHost) view, layoutlibCallback);
92331fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
92431fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
92531fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            badge.setImageToDefault();
9262fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet        } else if (view instanceof AdapterView<?>) {
9272fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get the view ID.
9282fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            int id = view.getId();
9292fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9302fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            BridgeContext context = getContext();
9312fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9322fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get a ResourceReference from the integer ID.
9332fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            ResourceReference listRef = context.resolveId(id);
9342fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9352fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            if (listRef != null) {
9362fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                SessionParams params = getParams();
9372fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                AdapterBinding binding = params.getAdapterBindings().get(listRef);
9382fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9392fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                // if there was no adapter binding, trying to get it from the call back.
9402fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding == null) {
94137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                    binding = layoutlibCallback.getAdapterBinding(
94237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                            listRef, context.getViewKey(view), view);
9432fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
9442fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9452fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding != null) {
9462fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9472fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    if (view instanceof AbsListView) {
9482fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) &&
9492fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                view instanceof ListView) {
9502fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ListView list = (ListView) view;
9512fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9522fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            boolean skipCallbackParser = false;
9532fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9542fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            int count = binding.getHeaderCount();
95510bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
9562fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
9572fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getHeaderAt(i),
95837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
9592fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
9602fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addHeaderView(pair.getFirst());
9612fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
9622fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9632fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
9642fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
9652fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9662fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            count = binding.getFooterCount();
96710bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
9682fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
9692fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getFooterAt(i),
97037dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
9712fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
9722fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addFooterView(pair.getFirst());
9732fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
9742fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9752fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
9762fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
9772fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
9782fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9792fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if (view instanceof ExpandableListView) {
9802fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((ExpandableListView) view).setAdapter(
98137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeExpandableAdapter(listRef, binding, layoutlibCallback));
9822fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        } else {
9832fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((AbsListView) view).setAdapter(
98437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeAdapter(listRef, binding, layoutlibCallback));
9852fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
9862fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    } else if (view instanceof AbsSpinner) {
9872fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        ((AbsSpinner) view).setAdapter(
98837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                new FakeAdapter(listRef, binding, layoutlibCallback));
9892fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    }
9902fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
9912fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            }
992c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } else if (view instanceof ViewGroup) {
993ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.postInflateProcess(view);
99410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            ViewGroup group = (ViewGroup) view;
995c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            final int count = group.getChildCount();
99610bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            for (int c = 0; c < count; c++) {
997c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                View child = group.getChildAt(c);
99837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                postInflateProcess(child, layoutlibCallback, skip);
999c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1000c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1001c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1002c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1003c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
10044dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * If the root layout is a CoordinatorLayout with an AppBar:
10054dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * Set the title of the AppBar to the title of the activity context.
10064dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
10074dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
10084dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
10094dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (coordinatorLayout == null) {
10104dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10114dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10124dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
10134dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (appBar == null) {
10144dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10154dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10164dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup collapsingToolbar =
10174dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
10184dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (collapsingToolbar == null) {
10194dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10204dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10214dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!hasToolbar(collapsingToolbar)) {
10224dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10234dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10244dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        RenderResources res = context.getRenderResources();
10254dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        String title = params.getAppLabel();
10264dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ResourceValue titleValue = res.findResValue(title, false);
10274dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (titleValue != null && titleValue.getValue() != null) {
10284dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            title = titleValue.getValue();
10294dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10304dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        DesignLibUtil.setTitle(collapsingToolbar, title);
10314dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10324dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10334dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private View findChildView(View view, String className) {
10344dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
10354dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return null;
10364dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10374dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
10384dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10394dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), className)) {
10404dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return group.getChildAt(i);
10414dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10424dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10434dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return null;
10444dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10454dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10464dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private boolean hasToolbar(View collapsingToolbar) {
10474dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(collapsingToolbar instanceof ViewGroup)) {
10484dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return false;
10494dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10504dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) collapsingToolbar;
10514dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10524dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
10534dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return true;
10544dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10554dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10564dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return false;
10574dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10584dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10594dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
1060d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * Set the scroll position on all the components with the "scrollX" and "scrollY" attribute. If
1061d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * the component supports nested scrolling attempt that first, then use the unconsumed scroll
1062d15459197f71f8cc940e2b057b399117df282f2cDiego Perez     * part to scroll the content in the component.
10634dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
10644dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private void handleScrolling(View view) {
10654dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        BridgeContext context = getContext();
1066d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        int scrollPosX = context.getScrollXPos(view);
1067d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        int scrollPosY = context.getScrollYPos(view);
1068d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        if (scrollPosX != 0 || scrollPosY != 0) {
10694dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (view.isNestedScrollingEnabled()) {
10704dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                int[] consumed = new int[2];
1071d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                int axis = scrollPosX != 0 ? View.SCROLL_AXIS_HORIZONTAL : 0;
1072d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                axis |= scrollPosY != 0 ? View.SCROLL_AXIS_VERTICAL : 0;
1073d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                if (view.startNestedScroll(axis)) {
1074d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view.dispatchNestedPreScroll(scrollPosX, scrollPosY, consumed, null);
1075d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view.dispatchNestedScroll(consumed[0], consumed[1], scrollPosX, scrollPosY,
1076d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                            null);
10774dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                    view.stopNestedScroll();
1078d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    scrollPosX -= consumed[0];
1079d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    scrollPosY -= consumed[1];
10804dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                }
10814dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
1082d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            if (scrollPosX != 0 || scrollPosY != 0) {
1083d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                view.scrollBy(scrollPosX, scrollPosY);
10844dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10854dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10864dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10874dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
10884dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10894dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10904dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
10914dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10924dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            View child = group.getChildAt(i);
10934dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            handleScrolling(child);
10944dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10954dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10964dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10974dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
1098c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Sets up a {@link TabHost} object.
1099c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param tabHost the TabHost to setup.
110037dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback The project callback object to access the project R class.
1101c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @throws PostInflateException
1102c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
110337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback)
1104c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1105c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
1106c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
1107c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1108c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1109c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1110c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
1111c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1112c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11131ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof TabWidget)) {
1114c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1115c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
1116c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
1117c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1118c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1119c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
1120c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1121c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
11221ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
11231ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1124c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1125c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
1126c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1127c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11281ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof FrameLayout)) {
11291ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1130c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1131c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
1132c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
1133c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1134c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1135c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
1136c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11371ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        // now process the content of the frameLayout and dynamically create tabs for it.
1138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        final int count = content.getChildCount();
1139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
1141c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // and FrameLayout.
1142c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        tabHost.setup();
1143c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1144796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        if (count == 0) {
1145796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // Create a dummy child to get a single tab
114649ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta            TabSpec spec = tabHost.newTabSpec("tag")
114749ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                    .setIndicator("Tab Label", tabHost.getResources()
114849ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                            .getDrawable(android.R.drawable.ic_menu_info_details, null))
1149796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
115046d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                        @Override
1151796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        public View createTabContent(String tag) {
1152b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                            return new LinearLayout(getContext());
1153796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        }
1154796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    });
1155796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            tabHost.addTab(spec);
1156796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        } else {
11571ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // for each child of the frameLayout, add a new TabSpec
1158796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            for (int i = 0 ; i < count ; i++) {
1159796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                View child = content.getChildAt(i);
1160796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
116110bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                @SuppressWarnings("ConstantConditions")  // child cannot be null.
1162796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                int id = child.getId();
11631ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                @SuppressWarnings("deprecation")
116437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                Pair<ResourceType, String> resource = layoutlibCallback.resolveResourceId(id);
1165796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String name;
1166796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                if (resource != null) {
1167b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                    name = resource.getSecond();
1168796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                } else {
1169796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1170796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                }
1171796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
1172c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1173c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1174c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1175c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11764ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
11774ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
11784ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views.
11794ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
11804ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param view the root View
11814ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds.
11824ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
11834ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
11844ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame.
11854ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
11864ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
11874ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
11884ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
11894ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
11904ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
1191bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
11924ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
11934ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            ViewGroup group = ((ViewGroup) view);
11944ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
11954ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    setExtendedInfo, isContentFrame));
11964ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
11974ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
11984ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1199bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12004ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12014ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
12021b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with
12034ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * the children of the {@code mContentRoot}.
12044ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12054ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param viewGroup the root View
12064ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset from the top for the content view frame.
12074ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
12084ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
12094ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame. {@code false} if the {@code ViewInfo} to be created is
12104ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       part of the system decor.
12114ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
12124ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
12134ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean setExtendedInfo, boolean isContentFrame) {
12144ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == null) {
12154ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return null;
1216bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
1217bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12184ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (!isContentFrame) {
12194ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            offset += viewGroup.getTop();
12204ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1221bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12224ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        int childCount = viewGroup.getChildCount();
12234ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == mContentRoot) {
12244ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
12254ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
12264ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
12274ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
122805b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                        setExtendedInfo);
12294ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithoutOffset.add(childViewInfo[0]);
12304ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithOffset.add(childViewInfo[1]);
1231bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            }
12324ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            mViewInfoList = childrenWithOffset;
12334ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return childrenWithoutOffset;
12344ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
12354ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
12364ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
12374ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
12384ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                        isContentFrame));
12394ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            }
12404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return children;
1241bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
12424ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1243bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12444ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12454ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
12464ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
12474ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * one with the {@code offset} and other without the {@code offset}. The offset is needed to
12484ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * get the right bounds if the {@code ViewInfo} hierarchy is accessed from
12494ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
12504ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * offset is not needed.
12514ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12524ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
12534ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *         index 1 is with the offset.
12544ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
1255d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @NonNull
12564ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
12574ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo[] result = new ViewInfo[2];
12584ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view == null) {
12594ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return result;
12604ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
12614ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
12624ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[0] = createViewInfo(view, 0, setExtendedInfo, true);
12634ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[1] = createViewInfo(view, offset, setExtendedInfo, true);
12644ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
12654ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
12664ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[0].setChildren(children);
12674ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[1].setChildren(children);
12684ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
12694ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
1270bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    }
1271c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1272c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
12734ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
12744ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
12754ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * set.
12764ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds. Used only if view is part of the content frame.
1277c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
12784ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
12794ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
1280c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view == null) {
1281c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            return null;
1282c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1283c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1284d15459197f71f8cc940e2b057b399117df282f2cDiego Perez        ViewParent parent = view.getParent();
12854ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result;
12864ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (isContentFrame) {
1287d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            // Account for parent scroll values when calculating the bounding box
1288d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            int scrollX = parent != null ? ((View)parent).getScrollX() : 0;
1289d15459197f71f8cc940e2b057b399117df282f2cDiego Perez            int scrollY = parent != null ? ((View)parent).getScrollY() : 0;
1290d15459197f71f8cc940e2b057b399117df282f2cDiego Perez
1291bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // The view is part of the layout added by the user. Hence,
1292bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // the ViewCookie may be obtained only through the Context.
12934ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result = new ViewInfo(view.getClass().getName(),
1294bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    getContext().getViewKey(view),
1295d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    -scrollX + view.getLeft(), -scrollY + view.getTop() + offset,
1296d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    -scrollX + view.getRight(), -scrollY + view.getBottom() + offset,
1297d15459197f71f8cc940e2b057b399117df282f2cDiego Perez                    view, view.getLayoutParams());
12984ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
1299bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We are part of the system decor.
1300bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
13015ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    getViewKey(view),
13024ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getLeft(), view.getTop(), view.getRight(),
13034ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getBottom(), view, view.getLayoutParams());
1304bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            result = r;
1305bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We currently mark three kinds of views:
1306bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 1. Menus in the Action Bar
1307bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 2. Menus in the Overflow popup.
1308bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 3. The overflow popup button.
1309bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            if (view instanceof ListMenuItemView) {
1310bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 2.
1311bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // All menus in the popup are of type ListMenuItemView.
1312bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                r.setViewType(ViewType.ACTION_BAR_OVERFLOW_MENU);
1313bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            } else {
1314bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 3.
1315bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                ViewGroup.LayoutParams lp = view.getLayoutParams();
1316bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                if (lp instanceof ActionMenuView.LayoutParams &&
1317bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        ((ActionMenuView.LayoutParams) lp).isOverflowButton) {
1318bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    r.setViewType(ViewType.ACTION_BAR_OVERFLOW);
1319bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                } else {
1320bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // Mark 1.
1321bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // A view is a menu in the Action Bar is it is not the overflow button and of
1322bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // its parent is of type ActionMenuView. We can also check if the view is
1323bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // instanceof ActionMenuItemView but that will fail for menus using
1324bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // actionProviderClass.
1325bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    while (parent != mViewRoot && parent instanceof ViewGroup) {
1326bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        if (parent instanceof ActionMenuView) {
1327bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            r.setViewType(ViewType.ACTION_BAR_MENU);
1328bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            break;
1329bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        }
1330bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        parent = parent.getParent();
1331bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    }
1332bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                }
1333bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            }
13344ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1335c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
133605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        if (setExtendedInfo) {
133705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            MarginLayoutParams marginParams = null;
133805b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            LayoutParams params = view.getLayoutParams();
133905b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            if (params instanceof MarginLayoutParams) {
134005b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                marginParams = (MarginLayoutParams) params;
134105b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            }
134205b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            result.setExtendedInfo(view.getBaseline(),
134305b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.leftMargin : 0,
134405b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.topMargin : 0,
134505b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.rightMargin : 0,
134605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.bottomMargin : 0);
134705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        }
134805b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet
1349c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return result;
1350c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1351c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1352bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta    /* (non-Javadoc)
13535ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * The cookie for menu items are stored in menu item and not in the map from View stored in
13545ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * BridgeContext.
13555ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     */
1356d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @Nullable
13575ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    private Object getViewKey(View view) {
13585ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        BridgeContext context = getContext();
13595ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (!(view instanceof MenuView.ItemView)) {
13605ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return context.getViewKey(view);
13615ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
13625ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        MenuItemImpl menuItem;
13635ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (view instanceof ActionMenuItemView) {
13645ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ActionMenuItemView) view).getItemData();
13655ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof ListMenuItemView) {
13665ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ListMenuItemView) view).getItemData();
13675ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof IconMenuItemView) {
13685ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((IconMenuItemView) view).getItemData();
13695ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else {
13705ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = null;
13715ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
13725ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (menuItem instanceof BridgeMenuItemImpl) {
13735ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return ((BridgeMenuItemImpl) menuItem).getViewCookie();
13745ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
13755ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
13765ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        return null;
13775ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    }
13785ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
1379c13aa0c035cd226d27323bc0e533632ba32f6a84Diego Perez    public void invalidateRenderingSize() {
13804ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
13814ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
13824ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
1383c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    public BufferedImage getImage() {
1384c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return mImage;
1385c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1386c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
138716584225125acba18b74920b902c798dfead0328Xavier Ducrohet    public boolean isAlphaChannelImage() {
138816584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return mIsAlphaChannelImage;
138916584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
139016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
13917d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    public List<ViewInfo> getViewInfos() {
13927d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return mViewInfoList;
1393c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1394cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet
13954ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    public List<ViewInfo> getSystemViewInfos() {
13964ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return mSystemViewInfoList;
13974ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
13984ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
139919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
1400b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return getContext().getDefaultPropMap(viewObject);
1401cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet    }
1402c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
140319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public void setScene(RenderSession session) {
140419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mScene = session;
1405c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1406c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
140719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public RenderSession getSession() {
1408c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        return mScene;
1409c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1410f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez
1411f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez    public void dispose() {
14125d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        boolean createdLooper = false;
14135d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        if (Looper.myLooper() == null) {
14145d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // Detaching the root view from the window will try to stop any running animations.
14155d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // The stop method checks that it can run in the looper so, if there is no current
14165d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            // looper, we create a temporary one to complete the shutdown.
14175d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            Bridge.prepareThread();
14185d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            createdLooper = true;
14195d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        }
1420f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        AttachInfo_Accessor.detachFromWindow(mViewRoot);
1421f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mCanvas != null) {
1422f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mCanvas.release();
1423f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mCanvas = null;
1424f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1425f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mViewInfoList != null) {
1426f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mViewInfoList.clear();
1427f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1428f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        if (mSystemViewInfoList != null) {
1429f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez            mSystemViewInfoList.clear();
1430f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        }
1431f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mImage = null;
1432f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mViewRoot = null;
1433f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez        mContentRoot = null;
14345d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez
14355d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        if (createdLooper) {
14365d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez            Bridge.cleanupThread();
143761ccc9198ab09363edbf500d7669dbcfafc5fa28Deepanshu Gupta            Choreographer_Delegate.dispose();
14385d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez        }
1439f5650cf3a3a1a8d6ced9fc7b0f399689c9adc1b8Diego Perez    }
1440c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet}
1441