RenderSessionImpl.java revision b1484862e2367d87d3ccbd0fd0a6d2598ed5918a
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;
49b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohetimport com.android.util.Pair;
50c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
517f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.animation.AnimationThread;
52e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.Animator;
532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohetimport android.animation.AnimatorInflater;
54e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohetimport android.animation.LayoutTransition;
552b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener;
56476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull;
57476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable;
58c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.app.Fragment_Delegate;
59c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap;
60c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Bitmap_Delegate;
61c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.graphics.Canvas;
6210bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Guptaimport android.preference.Preference_Delegate;
637f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.AttachInfo_Accessor;
647f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.BridgeInflater;
656dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.IWindowManager;
66891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohetimport android.view.IWindowManagerImpl;
676dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.Surface;
68c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View;
69c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.view.View.MeasureSpec;
7046d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.view.ViewGroup;
7101811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohetimport android.view.ViewGroup.LayoutParams;
7205b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohetimport android.view.ViewGroup.MarginLayoutParams;
73bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.view.ViewParent;
746dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohetimport android.view.WindowManagerGlobal_Delegate;
752fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsListView;
762fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AbsSpinner;
77bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Guptaimport android.widget.ActionMenuView;
782fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.AdapterView;
792fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ExpandableListView;
80c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.FrameLayout;
81796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.LinearLayout;
822fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohetimport android.widget.ListView;
8331fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohetimport android.widget.QuickContactBadge;
84c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport android.widget.TabHost;
85796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbyeimport android.widget.TabHost.TabSpec;
8646d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohetimport android.widget.TabWidget;
87c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
885a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohetimport java.awt.AlphaComposite;
89c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Color;
90c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.Graphics2D;
91c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.awt.image.BufferedImage;
92c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.ArrayList;
93c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.List;
94c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport java.util.Map;
95c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
9637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
9737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
9837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
9937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
10037dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
10137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
10261f23e9bf7d784e7a52168196758c4f6c6853e77Deepanshu Guptaimport static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
10337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta
104c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet/**
10519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * Class implementing the render session.
1061ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta * <p/>
10719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming
10819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
109c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet * be done on the layout.
110c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet */
111b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> {
112c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
113c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // scene state
11419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private RenderSession mScene;
115c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeXmlBlockParser mBlockParser;
116c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BridgeInflater mInflater;
117bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private ViewGroup mViewRoot;
118bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private FrameLayout mContentRoot;
1199eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private Canvas mCanvas;
1209eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenWidth = -1;
1219eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet    private int mMeasuredScreenHeight = -1;
122bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    private boolean mIsAlphaChannelImage;
12316584225125acba18b74920b902c798dfead0328Xavier Ducrohet
124c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    // information being returned through the API
125c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private BufferedImage mImage;
1267d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    private List<ViewInfo> mViewInfoList;
1274ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> mSystemViewInfoList;
128b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta    private Layout.Builder mLayoutBuilder;
129c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
130c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    private static final class PostInflateException extends Exception {
131c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        private static final long serialVersionUID = 1L;
132c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
133c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        public PostInflateException(String message) {
134c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            super(message);
135c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
136c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
137c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Creates a layout scene with all the information coming from the layout bridge API.
140c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
1411b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)},
1421b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * which act as a
14319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * call to {@link RenderSessionImpl#acquire(long)}
144c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     *
1451b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see Bridge#createSession(SessionParams)
146c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
1471126422ee1f532d8582a4e3b56dbfe505c15e775Xavier Ducrohet    public RenderSessionImpl(SessionParams params) {
148b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        super(new SessionParams(params));
1492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
1502eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
1512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
1522eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
1532eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * inflater, and parser.
1542eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1552eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
1562eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @return whether the scene was prepared
1582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1592eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #acquire(long)
1602eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @see #release()
1612eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
162b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    @Override
16319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result init(long timeout) {
164b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Result result = super.init(timeout);
1651ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
1662eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            return result;
1672eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
168c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
169b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
170b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
171c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
17216584225125acba18b74920b902c798dfead0328Xavier Ducrohet        // use default of true in case it's not found to use alpha by default
173b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mIsAlphaChannelImage = Layout.Builder.getBooleanThemeValue(params.getResources(),
174b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                        "windowIsFloating", true, true);
1752eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
176b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mLayoutBuilder = new Layout.Builder(params, context);
177c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1786dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        // FIXME: find those out, and possibly add them to the render params
1796dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        boolean hasNavigationBar = true;
1801ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        //noinspection ConstantConditions
1816dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
182b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                context.getMetrics(), Surface.ROTATION_0, hasNavigationBar);
1836dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet        WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
1846dfd0b39a63559999a769f93d5cdb48abe675344Xavier Ducrohet
185c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // build the inflater and parser.
18637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta        mInflater = new BridgeInflater(context, params.getLayoutlibCallback());
187b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        context.setBridgeInflater(mInflater);
1882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
189b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false);
1902eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
191168677c9e2f8438ec5687e3c6b0e41b986c5b230Xavier Ducrohet        return SUCCESS.createResult();
192c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
193c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
194c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
195c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Inflates the layout.
196c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
1972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
1982eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
1992eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
2002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #init(long)} was not called.
201c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
20219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result inflate() {
2032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
2042eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
205c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
206b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mViewRoot = new Layout(mLayoutBuilder);
207b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mLayoutBuilder = null;  // Done with the builder.
208b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta            mContentRoot = ((Layout) mViewRoot).getContentRoot();
209b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            SessionParams params = getParams();
210b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            BridgeContext context = getContext();
211c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
212c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // Sets the project callback (custom view loader) to the fragment delegate so that
213c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // it can instantiate the custom Fragment.
21437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback());
215c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
2161f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
21710bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            boolean isPreference = "PreferenceScreen".equals(rootTag);
21810bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            View view;
21910bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            if (isPreference) {
22010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = Preference_Delegate.inflatePreference(getContext(), mBlockParser,
221b1484862e2367d87d3ccbd0fd0a6d2598ed5918aDeepanshu Gupta                        mContentRoot);
22210bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            } else {
22310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                view = mInflater.inflate(mBlockParser, mContentRoot);
22410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            }
225c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
2262fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // done with the parser, pop it.
2272fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            context.popParser();
2282fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
22937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            Fragment_Delegate.setLayoutlibCallback(null);
230c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
231c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // set the AttachInfo on the root view.
2327f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet            AttachInfo_Accessor.setAttachInfo(mViewRoot);
233c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
23433758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet            // post-inflate process. For now this supports TabHost/TabWidget
23537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
236ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.onDoneInflation();
23733758ef8c98efb669c65eb9404b99ee5df09c6b5Xavier Ducrohet
2384dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            setActiveToolbar(view, context, params);
2394dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
24019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
241c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (PostInflateException e) {
24219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(e.getMessage(), e);
243c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
244c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
245c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
246c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
247c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
248c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
249c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
25019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_INFLATION.createResult(t.getMessage(), t);
251c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
252c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
253c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
254c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
255c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Renders the scene.
256c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * <p>
2572eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
2582eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
2595a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     * @param freshRender whether the render is a new one and should erase the existing bitmap (in
2605a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      the case where bitmaps are reused). This is typically needed when not playing
2615a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *      animations.)
2625a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet     *
2632eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
2642eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
2659eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet     *
2661b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * @see SessionParams#getRenderingMode()
267bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#render(long)
268c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
2695a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet    public Result render(boolean freshRender) {
2702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
2712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
272b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        SessionParams params = getParams();
273b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
274c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        try {
275c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            if (mViewRoot == null) {
27619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_NOT_INFLATED.createResult();
277c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
278c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
279b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            RenderingMode renderingMode = params.getRenderingMode();
280891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet            HardwareConfig hardwareConfig = params.getHardwareConfig();
281fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet
2829eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // only do the screen measure when needed.
2839eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            boolean newRenderSize = false;
2849eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            if (mMeasuredScreenWidth == -1) {
2859eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                newRenderSize = true;
286891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
287891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
2889eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
2899eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                if (renderingMode != RenderingMode.NORMAL) {
290c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
291c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
292c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            : MeasureSpec.EXACTLY;
293c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    int heightMeasureSpecMode = renderingMode.isVertExpand() ?
294c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
295c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            : MeasureSpec.EXACTLY;
296c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
297c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // We used to compare the measured size of the content to the screen size but
298c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // this does not work anymore due to the 2 following issues:
299c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // - If the content is in a decor (system bar, title/action bar), the root view
300c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    //   will not resize even with the UNSPECIFIED because of the embedded layout.
301c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // - If there is no decor, but a dialog frame, then the dialog padding prevents
302c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    //   comparing the size of the content to the screen frame (as it would not
303c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    //   take into account the dialog padding).
304c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
305c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // The solution is to first get the content size in a normal rendering, inside
306c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // the decor or the dialog padding.
307c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // Then measure only the content with UNSPECIFIED to see the size difference
308c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // and apply this to the screen size.
309c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
310c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // first measure the full layout, with EXACTLY to get the size of the
311c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // content as it is inside the decor/dialog
3121ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                    @SuppressWarnings("deprecation")
313c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    Pair<Integer, Integer> exactMeasure = measureView(
314c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mViewRoot, mContentRoot.getChildAt(0),
315c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenWidth, MeasureSpec.EXACTLY,
316c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenHeight, MeasureSpec.EXACTLY);
317c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
318c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // now measure the content only using UNSPECIFIED (where applicable, based on
319c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // the rendering mode). This will give us the size the content needs.
3201ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                    @SuppressWarnings("deprecation")
321c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    Pair<Integer, Integer> result = measureView(
322c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mContentRoot, mContentRoot.getChildAt(0),
323c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenWidth, widthMeasureSpecMode,
324c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenHeight, heightMeasureSpecMode);
325c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
326c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    // now look at the difference and add what is needed.
3279eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isHorizExpand()) {
328c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int measuredWidth = exactMeasure.getFirst();
329c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int neededWidth = result.getFirst();
330c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        if (neededWidth > measuredWidth) {
331c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenWidth += neededWidth - measuredWidth;
3329eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
333fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
334c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3359eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    if (renderingMode.isVertExpand()) {
336c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int measuredHeight = exactMeasure.getSecond();
337c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        int neededHeight = result.getSecond();
338c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                        if (neededHeight > measuredHeight) {
339c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                            mMeasuredScreenHeight += neededHeight - measuredHeight;
3409eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                        }
341fb25cae1916da1caf206ede879f07a4f8b61cfecXavier Ducrohet                    }
342c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                }
343c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
344c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
345c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            // measure again with the size we need
346c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // This must always be done before the call to layout
347c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            measureView(mViewRoot, null /*measuredView*/,
348c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
349c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
350c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
351c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // now do the layout.
35216584225125acba18b74920b902c798dfead0328Xavier Ducrohet            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
353c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
3544dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            handleScrolling(mViewRoot);
3554dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
35610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            if (params.isLayoutOnly()) {
35710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // delete the canvas and image to reset them on the next full rendering
35810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mImage = null;
35910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mCanvas = null;
36010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet            } else {
3617f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet                AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot);
36210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
36310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // draw the views
36410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                // create the BufferedImage into which the layout will be rendered.
36510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                boolean newImage = false;
3662c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez
3672c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // When disableBitmapCaching is true, we do not reuse mImage and
3682c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // we create a new one in every render.
3692c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // This is useful when mImage is just a wrapper of Graphics2D so
3702c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                // it doesn't get cached.
3712c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
3721f158819bc7cf58f97e47fabfaf23b2fb838f2ebAndrew Shulaev                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
3732c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                if (newRenderSize || mCanvas == null || disableBitmapCaching) {
37410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.getImageFactory() != null) {
37510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = params.getImageFactory().getImage(
37610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
37710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight);
37810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    } else {
37910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        mImage = new BufferedImage(
38010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenWidth,
38110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                mMeasuredScreenHeight,
38210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                                BufferedImage.TYPE_INT_ARGB);
38310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
38410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
38510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
38610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    if (params.isBgColorOverridden()) {
38710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        // since we override the content, it's the same as if it was a new image.
38810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        newImage = true;
38910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        Graphics2D gc = mImage.createGraphics();
39010df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setColor(new Color(params.getOverrideBgColor(), true));
39110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.setComposite(AlphaComposite.Src);
39210df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
39310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                        gc.dispose();
39410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    }
39510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
39610df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // create an Android bitmap around the BufferedImage
39710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
398891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                            true /*isMutable*/, hardwareConfig.getDensity());
39910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet
4002c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    if (mCanvas == null) {
4012c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        // create a Canvas around the Android bitmap
4022c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas = new Canvas(bitmap);
4032c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    } else {
4042c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                        mCanvas.setBitmap(bitmap);
4052c5e85b303077d2120b428bd4c7e6ecb6970935bDiego Perez                    }
406891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
4079eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                }
408c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
4091ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                if (freshRender && !newImage) {
4109eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet                    Graphics2D gc = mImage.createGraphics();
4115a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                    gc.setComposite(AlphaComposite.Src);
412c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
41310df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.setColor(new Color(0x00000000, true));
41410df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.fillRect(0, 0,
41510df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                            mMeasuredScreenWidth, mMeasuredScreenHeight);
41616584225125acba18b74920b902c798dfead0328Xavier Ducrohet
41710df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    // done
41810df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                    gc.dispose();
41910df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                }
42016584225125acba18b74920b902c798dfead0328Xavier Ducrohet
42110df650f0d4bdf086dae9ac29fafd8a1ded06c23Xavier Ducrohet                mViewRoot.draw(mCanvas);
4225a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet            }
4235a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet
4245ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
4255ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    false);
426c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
427c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // success!
42819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
429c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } catch (Throwable e) {
430c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            // get the real cause of the exception.
431c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            Throwable t = e;
432c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            while (t.getCause() != null) {
433c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                t = t.getCause();
434c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
435c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
43619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_UNKNOWN.createResult(t.getMessage(), t);
437c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
438c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
439c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
440c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
441c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
442c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
443c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
444c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
445c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
446c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     *
447c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param viewToMeasure the view on which to execute measure().
448c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param measuredView if non null, the view to query for its measured width/height.
449c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param width the width to use in the MeasureSpec.
450c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param widthMode the MeasureSpec mode to use for the width.
451c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param height the height to use in the MeasureSpec.
452c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @param heightMode the MeasureSpec mode to use for the height.
453c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     * @return the measured width/height if measuredView is non-null, null otherwise.
454c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet     */
4551ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
456c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
457c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            int width, int widthMode, int height, int heightMode) {
458c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
459c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
460c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        viewToMeasure.measure(w_spec, h_spec);
461c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
462c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        if (measuredView != null) {
463c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet            return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight());
464c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        }
465c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
466c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet        return null;
467c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    }
468c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet
469c5aeac7f157e3cb9e29ab8c126f74e26493501f5Xavier Ducrohet    /**
4702eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * Animate an object
4712eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * <p>
4722eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
4732eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *
4742eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
4752eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
476e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
477bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
4782eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet     */
47919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result animate(Object targetObject, String animationName,
4802eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            boolean isFrameworkAnimation, IAnimationListener listener) {
4812eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        checkLock();
4822eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
483b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
484b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
4852eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        // find the animation file.
4861ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        ResourceValue animationResource;
4872eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        int animationId = 0;
4882eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (isFrameworkAnimation) {
489b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getFrameworkResource(
49035ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
4912eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
492b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
4932eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
4942eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        } else {
495b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            animationResource = context.getRenderResources().getProjectResource(
49635ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                    ResourceType.ANIMATOR, animationName);
4972eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            if (animationResource != null) {
49837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                animationId = context.getLayoutlibCallback().getResourceId(
49935ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet                        ResourceType.ANIMATOR, animationName);
5002eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5012eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5022eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
5032eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        if (animationResource != null) {
5042eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            try {
505b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                Animator anim = AnimatorInflater.loadAnimator(context, animationId);
5062eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                if (anim != null) {
5072eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                    anim.setTarget(targetObject);
5082eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
509e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new PlayAnimationThread(anim, this, animationName, listener).start();
5102eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
51119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                    return SUCCESS.createResult();
5122eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet                }
5132eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            } catch (Exception e) {
514c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                // get the real cause of the exception.
515c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                Throwable t = e;
516c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                while (t.getCause() != null) {
517c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                    t = t.getCause();
518c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet                }
519c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
52019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                return ERROR_UNKNOWN.createResult(t.getMessage(), t);
5212eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet            }
5222eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet        }
5232eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
52419a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        return ERROR_ANIM_NOT_FOUND.createResult();
525c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
526c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
527e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
528e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Insert a new child into an existing parent.
529e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
530e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
531e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
532e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
533e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
534e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
535bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
536e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
53719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
538e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final int index, IAnimationListener listener) {
539c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
540c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
541b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        BridgeContext context = getContext();
542b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
543c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // create a block parser for the XML
54402d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
54502d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet                childXml, context, false /* platformResourceFlag */);
546c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
547c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // inflate the child without adding it to the root since we want to control where it'll
548c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // get added. We do pass the parentView however to ensure that the layoutParams will
549c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        // be created correctly.
550e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
55102d2b5a4031c80bfe1012ce2f4f7b3695762abd9Xavier Ducrohet        blockParser.ensurePopped();
552c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
553e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
554e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
555e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
556e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "insertChild", listener) {
557e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
558e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
55919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
560e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(new LayoutTransition());
561e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return addView(parentView, child, index);
562e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
563e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
564e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
565e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
566e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parentView.setLayoutTransition(null);
567e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
568e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
569e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
570e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
57119a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(child);
5729eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        }
5739eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
574e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        // add it to the parentView in the correct location
57519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = addView(parentView, child, index);
5761ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
577e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
578e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
579c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
5805a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
581c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        if (result.isSuccess()) {
582e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(child);
583c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        }
584c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet
585c8aec064f9f304c88f61c8c1aa3d60521b92177aXavier Ducrohet        return result;
586c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
587c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
588e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
589e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Adds a given view to a given parent at a given index.
590e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
591e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param parent the parent to receive the view
592e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to add to the parent
593e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the index where to do the add.
594e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
59519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
59619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
597e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
598e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
59919a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result addView(ViewGroup parent, View view, int index) {
600e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
601e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.addView(view, index);
60219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
603e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
604e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
60519a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
606e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
607e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
608e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
609e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
610e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a view to a new parent at a given location
611e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
612e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
613e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
614e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
615e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
616e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
617bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
618e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
6192b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet    public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
620479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            Map<String, String> layoutParamsMap, final IAnimationListener listener) {
621c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        checkLock();
622c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
623e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        invalidateRenderingSize();
624e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
62501811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        LayoutParams layoutParams = null;
626e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (layoutParamsMap != null) {
627e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // need to create a new LayoutParams object for the new parent.
6282b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            layoutParams = newParentView.generateLayoutParams(
629e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    new BridgeLayoutParamsMapAttributes(layoutParamsMap));
630e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
6319eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
6322b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        // get the current parent of the view that needs to be moved.
6332b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        final ViewGroup previousParent = (ViewGroup) childView.getParent();
6342b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
635e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
636e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            final LayoutParams params = layoutParams;
63701811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
638479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // there is no support for animating views across layouts, so in case the new and old
639479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            // parent views are different we fake the animation through a no animation thread.
640479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousParent != newParentView) {
641479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new Thread("not animated moveChild") {
642479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
643479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void run() {
644479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        Result result = moveView(previousParent, newParentView, childView, index,
645479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                params);
6461ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
647479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
648479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
649479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
650479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // ready to do the work, acquire the scene.
651479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        result = acquire(250);
6521ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                        if (!result.isSuccess()) {
653479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            listener.done(result);
654479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            return;
655479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
656479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
657479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        try {
6585a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet                            result = render(false /*freshRender*/);
659479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            if (result.isSuccess()) {
660479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                listener.onNewFrame(RenderSessionImpl.this.getSession());
661479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            }
662479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        } finally {
663479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            release();
664479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
665479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
666479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        listener.done(result);
6672b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
668479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
669479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            } else {
670479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                new AnimationThread(this, "moveChild", listener) {
6712b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
672479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
673479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public Result preAnimation() {
674479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // set up the transition for the parent.
675479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        LayoutTransition transition = new LayoutTransition();
676479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(transition);
6777550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet
678479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // tweak the animation durations and start delays (to match the duration of
679479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // animation playing just before).
680479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // Note: Cannot user Animation.setDuration() directly. Have to set it
681479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // on the LayoutTransition.
682479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.DISAPPEARING, 100);
683479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_DISAPPEARING plays after DISAPPEARING
684479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
68501811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
686479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
687479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
688479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
689479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        // CHANGE_APPEARING plays after CHANGE_APPEARING
690479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setStartDelay(LayoutTransition.APPEARING, 100);
691479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
692479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        transition.setDuration(LayoutTransition.APPEARING, 100);
693479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
694479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        return moveView(previousParent, newParentView, childView, index, params);
695479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
696479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
697479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    @Override
698479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    public void postAnimation() {
699479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        previousParent.setLayoutTransition(null);
700479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        newParentView.setLayoutTransition(null);
701479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    }
702479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                }.start();
703479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            }
704e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
705e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
70619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult(layoutParams);
707c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
708c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7092b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet        Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
7101ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
711e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
712e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
713c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
7145a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        result = render(false /*freshRender*/);
71501811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        if (layoutParams != null && result.isSuccess()) {
716e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            result = result.getCopyWithData(layoutParams);
71701811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        }
71801811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet
71901811aa86279af1b341a4fff344d66c0ebdd63daXavier Ducrohet        return result;
720c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
721c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
722e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
723e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Moves a View from its current parent to a new given parent at a new given location, with
724e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * an optional new {@link LayoutParams} instance
725e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
7262b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param previousParent the previous parent, still owning the child at the time of the call.
7272b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet     * @param newParent the new parent
728479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet     * @param movedView the view to move
729e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param index the new location in the new parent
730e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param params an option (can be null) {@link LayoutParams} instance.
731e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
73219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
73319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
734e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
735e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
736479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet    private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
737479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            final View movedView, final int index, final LayoutParams params) {
7389eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        try {
7392b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            // check if there is a transition on the previousParent.
740479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            LayoutTransition previousTransition = previousParent.getLayoutTransition();
741479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet            if (previousTransition != null) {
7427550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // in this case there is an animation. This means we have to wait for the child's
7437550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent reference to be null'ed out so that we can add it to the new parent.
7447550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // It is technically removed right before the DISAPPEARING animation is done (if
7457550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // the animation of this type is not null, otherwise it's after which is impossible
7467550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // to handle).
7477550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // Because there is no move animation, if the new parent is the same as the old
7487550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
7497550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // adding the child or the child will appear in its new location before the
7507550ec1d8e526c4ae8c0bb08b06e1b6e799eacecXavier Ducrohet                // other children have made room for it.
7512b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7522b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add a listener to the transition to be notified of the actual removal.
753479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousTransition.addTransitionListener(new TransitionListener() {
754479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    private int mChangeDisappearingCount = 0;
7552b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
75646d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
7572b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void startTransition(LayoutTransition transition, ViewGroup container,
7582b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
759479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
760479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount++;
761479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
7622b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
763e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
76446d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                    @Override
7652b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    public void endTransition(LayoutTransition transition, ViewGroup container,
7662b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            View view, int transitionType) {
767479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
768479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                            mChangeDisappearingCount--;
769479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        }
770479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet
771479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                        if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
772479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                mChangeDisappearingCount == 0) {
7732b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            // add it to the parentView in the correct location
7742b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            if (params != null) {
775479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index, params);
7762b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            } else {
777479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                                newParent.addView(movedView, index);
7782b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                            }
7792b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                        }
7802b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                    }
7812b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                });
7822b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7832b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // remove the view from the current parent.
784479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
7852b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7862b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // and return since adding the view to the new parent is done in the listener.
7872b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
788e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            } else {
7892b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // standard code with no animation. pretty simple.
790479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                previousParent.removeView(movedView);
791e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
7922b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                // add it to the parentView in the correct location
7932b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                if (params != null) {
794479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index, params);
7952b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                } else {
796479101a9b4142d21d42351684bc9bc65ec3471beXavier Ducrohet                    newParent.addView(movedView, index);
7972b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                }
7982b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet
7992b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet                return SUCCESS.createResult();
8002b9c38ab62abc8d5b2f956e961087f259caf25ffXavier Ducrohet            }
8019eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        } catch (UnsupportedOperationException e) {
8029eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
80319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
804c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        }
805e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
806e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
807e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    /**
808e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a child from its current parent.
809e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * <p>
810e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * {@link #acquire(long)} must have been called before this.
811e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
812e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
813e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
814e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
815bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet     * @see RenderSession#removeChild(Object, IAnimationListener)
816e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
81719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Result removeChild(final View childView, IAnimationListener listener) {
818e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        checkLock();
819c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
8209eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet        invalidateRenderingSize();
8219eb6d412af6859b6c0bb969c76bbfc48eec8fd4bXavier Ducrohet
822e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        final ViewGroup parent = (ViewGroup) childView.getParent();
823e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
824e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        if (listener != null) {
825e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            new AnimationThread(this, "moveChild", listener) {
826e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
827e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
82819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet                public Result preAnimation() {
829e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(new LayoutTransition());
830e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    return removeView(parent, childView);
831e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
832e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
833e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                @Override
834e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                public void postAnimation() {
835e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                    parent.setLayoutTransition(null);
836e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet                }
837e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            }.start();
838e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
839e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // always return success since the real status will come through the listener.
84019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
841e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
842e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
84319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        Result result = removeView(parent, childView);
8441ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!result.isSuccess()) {
845e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            return result;
846e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
847e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
8485a82d8c58bf91c357c37a82b9f5e5c26f676d847Xavier Ducrohet        return render(false /*freshRender*/);
8492eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    }
8502eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet
8512eea6fab1cbb0a5c8f913491c2d622c904759893Xavier Ducrohet    /**
852e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * Removes a given view from its current parent.
853e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
854e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     * @param view the view to remove from its parent
855e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *
85619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     * @return a Result with {@link Status#SUCCESS} or
85719a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet     *     {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
858e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     *     adding views.
859e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet     */
86019a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    private Result removeView(ViewGroup parent, View view) {
861e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        try {
862e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            parent.removeView(view);
86319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return SUCCESS.createResult();
864e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        } catch (UnsupportedOperationException e) {
865e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet            // looks like this is a view class that doesn't support children manipulation!
86619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet            return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
867e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet        }
868e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet    }
869e1179ea065392485a6e3bf1e28a1242179cd48b0Xavier Ducrohet
870c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
8711ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * Post process on a view hierarchy that was just inflated.
8721ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * <p/>
8731ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta     * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
874c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
875c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * based on the content of the {@link FrameLayout}.
876c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param view the root view to process.
87737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback callback to the project.
87810bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta     * @param skip the view and it's children are not processed.
879c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
8801ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta    @SuppressWarnings("deprecation")  // For the use of Pair
88137dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip)
882c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
88310bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        if (view == skip) {
88410bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            return;
88510bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta        }
886c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view instanceof TabHost) {
88737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta            setupTabHost((TabHost) view, layoutlibCallback);
88831fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet        } else if (view instanceof QuickContactBadge) {
88931fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            QuickContactBadge badge = (QuickContactBadge) view;
89031fd1cf7697ef777b41c7a6a20e37ff5d573d732Xavier Ducrohet            badge.setImageToDefault();
8912fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet        } else if (view instanceof AdapterView<?>) {
8922fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get the view ID.
8932fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            int id = view.getId();
8942fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
8952fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            BridgeContext context = getContext();
8962fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
8972fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            // get a ResourceReference from the integer ID.
8982fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            ResourceReference listRef = context.resolveId(id);
8992fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9002fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            if (listRef != null) {
9012fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                SessionParams params = getParams();
9022fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                AdapterBinding binding = params.getAdapterBindings().get(listRef);
9032fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9042fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                // if there was no adapter binding, trying to get it from the call back.
9052fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding == null) {
90637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                    binding = layoutlibCallback.getAdapterBinding(
90737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                            listRef, context.getViewKey(view), view);
9082fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
9092fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9102fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                if (binding != null) {
9112fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9122fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    if (view instanceof AbsListView) {
9132fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) &&
9142fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                view instanceof ListView) {
9152fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ListView list = (ListView) view;
9162fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9172fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            boolean skipCallbackParser = false;
9182fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9192fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            int count = binding.getHeaderCount();
92010bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
9212fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
9222fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getHeaderAt(i),
92337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
9242fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
9252fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addHeaderView(pair.getFirst());
9262fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
9272fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9282fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
9292fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
9302fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9312fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            count = binding.getFooterCount();
93210bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                            for (int i = 0; i < count; i++) {
9332fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                Pair<View, Boolean> pair = context.inflateView(
9342fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                        binding.getFooterAt(i),
93537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                        list, false, skipCallbackParser);
9362fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                if (pair.getFirst() != null) {
9372fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                    list.addFooterView(pair.getFirst());
9382fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                }
9392fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9402fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                                skipCallbackParser |= pair.getSecond();
9412fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            }
9422fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
9432fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet
9442fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        if (view instanceof ExpandableListView) {
9452fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((ExpandableListView) view).setAdapter(
94637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeExpandableAdapter(listRef, binding, layoutlibCallback));
9472fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        } else {
9482fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                            ((AbsListView) view).setAdapter(
94937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                    new FakeAdapter(listRef, binding, layoutlibCallback));
9502fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        }
9512fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    } else if (view instanceof AbsSpinner) {
9522fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                        ((AbsSpinner) view).setAdapter(
95337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                                new FakeAdapter(listRef, binding, layoutlibCallback));
9542fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                    }
9552fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet                }
9562fae858db55fc6984ef923a6226b9408c37c72cbXavier Ducrohet            }
957c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        } else if (view instanceof ViewGroup) {
958ccbc11770397888cf7780925bb4c7cf1d2f2f80eDeepanshu Gupta            mInflater.postInflateProcess(view);
95910bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            ViewGroup group = (ViewGroup) view;
960c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            final int count = group.getChildCount();
96110bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta            for (int c = 0; c < count; c++) {
962c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                View child = group.getChildAt(c);
96337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                postInflateProcess(child, layoutlibCallback, skip);
964c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
965c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
966c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
967c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
968c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
9694dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * If the root layout is a CoordinatorLayout with an AppBar:
9704dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * Set the title of the AppBar to the title of the activity context.
9714dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
9724dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
9734dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
9744dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (coordinatorLayout == null) {
9754dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
9764dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
9774dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
9784dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (appBar == null) {
9794dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
9804dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
9814dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup collapsingToolbar =
9824dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
9834dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (collapsingToolbar == null) {
9844dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
9854dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
9864dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!hasToolbar(collapsingToolbar)) {
9874dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
9884dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
9894dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        RenderResources res = context.getRenderResources();
9904dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        String title = params.getAppLabel();
9914dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ResourceValue titleValue = res.findResValue(title, false);
9924dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (titleValue != null && titleValue.getValue() != null) {
9934dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            title = titleValue.getValue();
9944dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
9954dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        DesignLibUtil.setTitle(collapsingToolbar, title);
9964dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
9974dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
9984dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private View findChildView(View view, String className) {
9994dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
10004dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return null;
10014dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10024dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
10034dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10044dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), className)) {
10054dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return group.getChildAt(i);
10064dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10074dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10084dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return null;
10094dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10104dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10114dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private boolean hasToolbar(View collapsingToolbar) {
10124dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(collapsingToolbar instanceof ViewGroup)) {
10134dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return false;
10144dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10154dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) collapsingToolbar;
10164dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10174dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
10184dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                return true;
10194dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10204dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10214dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        return false;
10224dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10234dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10244dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
10254dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * Set the vertical scroll position on all the components with the "scrollY" attribute. If the
10264dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * component supports nested scrolling attempt that first, then use the unconsumed scroll part
10274dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     * to scroll the content in the component.
10284dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen     */
10294dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    private void handleScrolling(View view) {
10304dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        BridgeContext context = getContext();
10314dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        int scrollPos = context.getScrollYPos(view);
10324dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (scrollPos != 0) {
10334dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (view.isNestedScrollingEnabled()) {
10344dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                int[] consumed = new int[2];
10354dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                if (view.startNestedScroll(DesignLibUtil.SCROLL_AXIS_VERTICAL)) {
10364dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                    view.dispatchNestedPreScroll(0, scrollPos, consumed, null);
10374dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                    view.dispatchNestedScroll(consumed[0], consumed[1], 0, scrollPos, null);
10384dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                    view.stopNestedScroll();
10394dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                    scrollPos -= consumed[1];
10404dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                }
10414dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10424dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            if (scrollPos != 0) {
10434dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                view.scrollBy(0, scrollPos);
10444dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            } else {
10454dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen                view.scrollBy(0, scrollPos);
10464dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            }
10474dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        } else {
10484dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            view.scrollBy(0, scrollPos);
10494dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10504dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10514dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        if (!(view instanceof ViewGroup)) {
10524dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            return;
10534dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10544dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        ViewGroup group = (ViewGroup) view;
10554dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        for (int i = 0; i < group.getChildCount(); i++) {
10564dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            View child = group.getChildAt(i);
10574dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen            handleScrolling(child);
10584dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen        }
10594dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    }
10604dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen
10614dfe4d43ce5634f059a3ba669e3cac4551c3a3eeJens Ole Lauridsen    /**
1062c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * Sets up a {@link TabHost} object.
1063c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @param tabHost the TabHost to setup.
106437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta     * @param layoutlibCallback The project callback object to access the project R class.
1065c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     * @throws PostInflateException
1066c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
106737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta    private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback)
1068c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throws PostInflateException {
1069c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // look for the TabWidget, and the FrameLayout. They have their own specific names
1070c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        View v = tabHost.findViewById(android.R.id.tabs);
1071c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1072c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
1073c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1074c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
1075c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1076c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
10771ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof TabWidget)) {
1078c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1079c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
1080c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
1081c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1082c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1083c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        v = tabHost.findViewById(android.R.id.tabcontent);
1084c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1085c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (v == null) {
10861ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
10871ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1088c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(
1089c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
1090c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1091c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
10921ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        if (!(v instanceof FrameLayout)) {
10931ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            //noinspection SpellCheckingInspection
1094c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            throw new PostInflateException(String.format(
1095c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
1096c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
1097c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1098c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1099c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        FrameLayout content = (FrameLayout)v;
1100c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11011ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta        // now process the content of the frameLayout and dynamically create tabs for it.
1102c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        final int count = content.getChildCount();
1103c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1104c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // this must be called before addTab() so that the TabHost searches its TabWidget
1105c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        // and FrameLayout.
1106c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        tabHost.setup();
1107c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1108796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        if (count == 0) {
1109796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            // Create a dummy child to get a single tab
111049ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta            TabSpec spec = tabHost.newTabSpec("tag")
111149ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                    .setIndicator("Tab Label", tabHost.getResources()
111249ce36e1754243eedc124b4f7e68af1b458c821cDeepanshu Gupta                            .getDrawable(android.R.drawable.ic_menu_info_details, null))
1113796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    .setContent(new TabHost.TabContentFactory() {
111446d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet                        @Override
1115796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        public View createTabContent(String tag) {
1116b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                            return new LinearLayout(getContext());
1117796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                        }
1118796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    });
1119796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            tabHost.addTab(spec);
1120796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye        } else {
11211ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta            // for each child of the frameLayout, add a new TabSpec
1122796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye            for (int i = 0 ; i < count ; i++) {
1123796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                View child = content.getChildAt(i);
1124796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String tabSpec = String.format("tab_spec%d", i+1);
112510bb1371dca38b5b59f083ee963f7987da6511f2Deepanshu Gupta                @SuppressWarnings("ConstantConditions")  // child cannot be null.
1126796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                int id = child.getId();
11271ea1b21acd5517d5405bd3338ba24d5a03a8d792Deepanshu Gupta                @SuppressWarnings("deprecation")
112837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                Pair<ResourceType, String> resource = layoutlibCallback.resolveResourceId(id);
1129796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                String name;
1130796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                if (resource != null) {
1131b353495192ba1acce94b8ab8aeeffe3c9a3bcfacXavier Ducrohet                    name = resource.getSecond();
1132796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                } else {
1133796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
1134796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                }
1135796992a942f3508a15ee62d34d6c7ec5de045d83Tor Norbye                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
1136c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            }
1137c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1138c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1139c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
11404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
11414ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
11424ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views.
11434ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
11444ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param view the root View
11454ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds.
11464ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
11474ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
11484ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame.
11494ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
11504ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
11514ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
11524ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
11534ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
11544ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
1155bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
11564ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
11574ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            ViewGroup group = ((ViewGroup) view);
11584ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
11594ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    setExtendedInfo, isContentFrame));
11604ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
11614ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
11624ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1163bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
11644ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
11654ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
11661b87390c9426c4bc9119829e9375d712dfde11c3Deepanshu Gupta     * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with
11674ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * the children of the {@code mContentRoot}.
11684ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
11694ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param viewGroup the root View
11704ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset from the top for the content view frame.
11714ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
11724ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
11734ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       content frame. {@code false} if the {@code ViewInfo} to be created is
11744ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *                       part of the system decor.
11754ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
11764ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
11774ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean setExtendedInfo, boolean isContentFrame) {
11784ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == null) {
11794ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return null;
1180bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
1181bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
11824ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (!isContentFrame) {
11834ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            offset += viewGroup.getTop();
11844ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1185bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
11864ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        int childCount = viewGroup.getChildCount();
11874ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (viewGroup == mContentRoot) {
11884ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
11894ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
11904ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
11914ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
119205b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                        setExtendedInfo);
11934ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithoutOffset.add(childViewInfo[0]);
11944ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                childrenWithOffset.add(childViewInfo[1]);
1195bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet            }
11964ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            mViewInfoList = childrenWithOffset;
11974ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return childrenWithoutOffset;
11984ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
11994ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
12004ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            for (int i = 0; i < childCount; i++) {
12014ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
12024ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                        isContentFrame));
12034ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            }
12044ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return children;
1205bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet        }
12064ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
1207bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet
12084ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    /**
12094ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
12104ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
12114ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * one with the {@code offset} and other without the {@code offset}. The offset is needed to
12124ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * get the right bounds if the {@code ViewInfo} hierarchy is accessed from
12134ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
12144ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * offset is not needed.
12154ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *
12164ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
12174ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     *         index 1 is with the offset.
12184ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     */
1219d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @NonNull
12204ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
12214ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo[] result = new ViewInfo[2];
12224ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view == null) {
12234ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            return result;
12244ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
12254ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
12264ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[0] = createViewInfo(view, 0, setExtendedInfo, true);
12274ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        result[1] = createViewInfo(view, offset, setExtendedInfo, true);
12284ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (view instanceof ViewGroup) {
12294ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
12304ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[0].setChildren(children);
12314ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result[1].setChildren(children);
12324ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
12334ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return result;
1234bbbb8326020368958a3f1d248878329e9d6b10c0Xavier Ducrohet    }
1235c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1236c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    /**
12374ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
12384ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
12394ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * set.
12404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta     * @param offset an offset for the view bounds. Used only if view is part of the content frame.
1241c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet     */
12424ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
12434ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            boolean isContentFrame) {
1244c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        if (view == null) {
1245c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet            return null;
1246c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        }
1247c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
12484ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        ViewInfo result;
12494ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        if (isContentFrame) {
1250bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // The view is part of the layout added by the user. Hence,
1251bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // the ViewCookie may be obtained only through the Context.
12524ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta            result = new ViewInfo(view.getClass().getName(),
1253bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    getContext().getViewKey(view),
12544ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getLeft(), view.getTop() + offset, view.getRight(),
12554ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getBottom() + offset, view, view.getLayoutParams());
12564ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        } else {
1257bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We are part of the system decor.
1258bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
12595ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta                    getViewKey(view),
12604ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getLeft(), view.getTop(), view.getRight(),
12614ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta                    view.getBottom(), view, view.getLayoutParams());
1262bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            result = r;
1263bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // We currently mark three kinds of views:
1264bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 1. Menus in the Action Bar
1265bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 2. Menus in the Overflow popup.
1266bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            // 3. The overflow popup button.
1267bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            if (view instanceof ListMenuItemView) {
1268bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 2.
1269bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // All menus in the popup are of type ListMenuItemView.
1270bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                r.setViewType(ViewType.ACTION_BAR_OVERFLOW_MENU);
1271bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            } else {
1272bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                // Mark 3.
1273bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                ViewGroup.LayoutParams lp = view.getLayoutParams();
1274bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                if (lp instanceof ActionMenuView.LayoutParams &&
1275bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        ((ActionMenuView.LayoutParams) lp).isOverflowButton) {
1276bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    r.setViewType(ViewType.ACTION_BAR_OVERFLOW);
1277bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                } else {
1278bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // Mark 1.
1279bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // A view is a menu in the Action Bar is it is not the overflow button and of
1280bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // its parent is of type ActionMenuView. We can also check if the view is
1281bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // instanceof ActionMenuItemView but that will fail for menus using
1282bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    // actionProviderClass.
1283bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    ViewParent parent = view.getParent();
1284bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    while (parent != mViewRoot && parent instanceof ViewGroup) {
1285bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        if (parent instanceof ActionMenuView) {
1286bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            r.setViewType(ViewType.ACTION_BAR_MENU);
1287bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                            break;
1288bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        }
1289bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                        parent = parent.getParent();
1290bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                    }
1291bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta                }
1292bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta            }
12934ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        }
1294c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
129505b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        if (setExtendedInfo) {
129605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            MarginLayoutParams marginParams = null;
129705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            LayoutParams params = view.getLayoutParams();
129805b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            if (params instanceof MarginLayoutParams) {
129905b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                marginParams = (MarginLayoutParams) params;
130005b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            }
130105b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet            result.setExtendedInfo(view.getBaseline(),
130205b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.leftMargin : 0,
130305b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.topMargin : 0,
130405b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.rightMargin : 0,
130505b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet                    marginParams != null ? marginParams.bottomMargin : 0);
130605b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet        }
130705b7b69c6c5d418e18db644feed1ec2ca83291ccXavier Ducrohet
1308c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return result;
1309c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1310c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
1311bac0d9ae796920360ee2f2babd8f2c03d4c3c2b8Deepanshu Gupta    /* (non-Javadoc)
13125ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * The cookie for menu items are stored in menu item and not in the map from View stored in
13135ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     * BridgeContext.
13145ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta     */
1315d345f44a87de1088fcd19e021238852bbffbbaecDeepanshu Gupta    @Nullable
13165ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    private Object getViewKey(View view) {
13175ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        BridgeContext context = getContext();
13185ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (!(view instanceof MenuView.ItemView)) {
13195ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return context.getViewKey(view);
13205ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
13215ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        MenuItemImpl menuItem;
13225ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (view instanceof ActionMenuItemView) {
13235ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ActionMenuItemView) view).getItemData();
13245ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof ListMenuItemView) {
13255ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((ListMenuItemView) view).getItemData();
13265ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else if (view instanceof IconMenuItemView) {
13275ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = ((IconMenuItemView) view).getItemData();
13285ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        } else {
13295ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            menuItem = null;
13305ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
13315ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        if (menuItem instanceof BridgeMenuItemImpl) {
13325ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta            return ((BridgeMenuItemImpl) menuItem).getViewCookie();
13335ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        }
13345ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
13355ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta        return null;
13365ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta    }
13375ba2f230faa355eb9bc1e90f6c48eeeb437f390cDeepanshu Gupta
1338c13aa0c035cd226d27323bc0e533632ba32f6a84Diego Perez    public void invalidateRenderingSize() {
13394ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
13404ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
13414ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
1342c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    public BufferedImage getImage() {
1343c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet        return mImage;
1344c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1345c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet
134616584225125acba18b74920b902c798dfead0328Xavier Ducrohet    public boolean isAlphaChannelImage() {
134716584225125acba18b74920b902c798dfead0328Xavier Ducrohet        return mIsAlphaChannelImage;
134816584225125acba18b74920b902c798dfead0328Xavier Ducrohet    }
134916584225125acba18b74920b902c798dfead0328Xavier Ducrohet
13507d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet    public List<ViewInfo> getViewInfos() {
13517d7016e72431ad7ee595d857a19231c69efeb6deXavier Ducrohet        return mViewInfoList;
1352c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet    }
1353cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet
13544ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    public List<ViewInfo> getSystemViewInfos() {
13554ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta        return mSystemViewInfoList;
13564ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta    }
13574ccc4bd54f85d86818f61d728c6361d2003ddd8eDeepanshu Gupta
135819a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public Map<String, String> getDefaultProperties(Object viewObject) {
1359b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return getContext().getDefaultPropMap(viewObject);
1360cf52390eee4c9ae792ef63af1528b2e71b33a04fXavier Ducrohet    }
1361c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
136219a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public void setScene(RenderSession session) {
136319a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet        mScene = session;
1364c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1365c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet
136619a021038f2f4683dddef651543d7298f5bd7218Xavier Ducrohet    public RenderSession getSession() {
1367c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet        return mScene;
1368c14e7dd8ba15f517a5402ad802377b1d60784416Xavier Ducrohet    }
1369c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohet}
1370