13bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/* 23bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Copyright (C) 2010 The Android Open Source Project 33bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 43bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License"); 53bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * you may not use this file except in compliance with the License. 63bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * You may obtain a copy of the License at 73bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 83bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * http://www.apache.org/licenses/LICENSE-2.0 93bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Unless required by applicable law or agreed to in writing, software 113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS, 123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * See the License for the specific language governing permissions and 143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * limitations under the License. 153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetpackage com.android.layoutlib.bridge.impl; 183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 197062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.ide.common.rendering.api.AdapterBinding; 2064f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohetimport com.android.ide.common.rendering.api.HardwareConfig; 215cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perezimport com.android.ide.common.rendering.api.LayoutLog; 22b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutlibCallback; 230d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources; 24ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession; 257062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceReference; 26ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue; 27ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result; 28d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams; 29b32414fe256a6fe1d65e7a1443cd6ea77db8bd95Xavier Ducrohetimport com.android.ide.common.rendering.api.SessionParams.RenderingMode; 30d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo; 3170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport com.android.ide.common.rendering.api.ViewType; 3241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.ActionMenuItemView; 3341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.BridgeMenuItemImpl; 3441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.IconMenuItemView; 3541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.ListMenuItemView; 3641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.MenuItemImpl; 3741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Guptaimport com.android.internal.view.menu.MenuView; 38ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge; 393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext; 403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser; 41a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaevimport com.android.layoutlib.bridge.android.RenderParamsFlags; 42259504c6368e44adfffd4f56f7a838b2d5e73ff9Diego Perezimport com.android.layoutlib.bridge.android.graphics.NopCanvas; 43c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsenimport com.android.layoutlib.bridge.android.support.DesignLibUtil; 44f59abd4701479e496d955cb8521a813e535aefa3Jerome Gaillardimport com.android.layoutlib.bridge.android.support.FragmentTabHostUtil; 45b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perezimport com.android.layoutlib.bridge.android.support.SupportPreferencesUtil; 467062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeAdapter; 477062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter; 48f59abd4701479e496d955cb8521a813e535aefa3Jerome Gaillardimport com.android.layoutlib.bridge.util.ReflectionUtils; 491b5ef2d19e1d7cb491c1c79f867e38ec0bde2770Xavier Ducrohetimport com.android.resources.ResourceType; 50344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Guptaimport com.android.tools.layoutlib.java.System_Delegate; 51947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohetimport com.android.util.Pair; 5218be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Guptaimport com.android.util.PropertiesMap; 533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 54442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.NonNull; 55442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.Nullable; 563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate; 573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap; 583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate; 593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas; 60e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perezimport android.os.Looper; 618a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Guptaimport android.preference.Preference_Delegate; 62994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.view.AttachInfo_Accessor; 63994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohetimport android.view.BridgeInflater; 64344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Guptaimport android.view.Choreographer_Delegate; 653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View; 663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec; 67d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport android.view.ViewGroup; 68ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport android.view.ViewGroup.LayoutParams; 696208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohetimport android.view.ViewGroup.MarginLayoutParams; 7070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport android.view.ViewParent; 717062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AbsListView; 727062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AbsSpinner; 7370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Guptaimport android.widget.ActionMenuView; 747062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.AdapterView; 757062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.ExpandableListView; 763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout; 77f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.LinearLayout; 787062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohetimport android.widget.ListView; 7962c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohetimport android.widget.QuickContactBadge; 803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost; 81f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbyeimport android.widget.TabHost.TabSpec; 82d98e133b3911b8db3430ce9d85efd5a6adcf70bfXavier Ducrohetimport android.widget.TabWidget; 833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 844c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohetimport java.awt.AlphaComposite; 853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color; 863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D; 873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage; 883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList; 893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List; 903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map; 913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 92b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION; 93b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED; 94b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN; 95b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS; 96baf88de1f5c435a788f6c38720354b2dbaa19e60Deepanshu Guptaimport static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf; 97b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta 983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/** 99ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * Class implementing the render session. 100952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta * <p/> 101ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming 102ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then 1033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout. 1043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 1050fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohetpublic class RenderSessionImpl extends RenderAction<SessionParams> { 1063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 107259504c6368e44adfffd4f56f7a838b2d5e73ff9Diego Perez private static final Canvas NOP_CANVAS = new NopCanvas(); 108259504c6368e44adfffd4f56f7a838b2d5e73ff9Diego Perez 1093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene state 110ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet private RenderSession mScene; 1113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeXmlBlockParser mBlockParser; 1123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeInflater mInflater; 113799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet private ViewGroup mViewRoot; 114799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet private FrameLayout mContentRoot; 1151392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet private Canvas mCanvas; 1161392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet private int mMeasuredScreenWidth = -1; 1171392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet private int mMeasuredScreenHeight = -1; 118799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet private boolean mIsAlphaChannelImage; 119344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta /** If >= 0, a frame will be executed */ 120344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta private long mElapsedFrameTimeNanos = -1; 121344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta /** True if one frame has been already executed to start the animations */ 122344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta private boolean mFirstFrameExecuted = false; 123a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet 1243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // information being returned through the API 1253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BufferedImage mImage; 126e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet private List<ViewInfo> mViewInfoList; 12785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta private List<ViewInfo> mSystemViewInfoList; 1288b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta private Layout.Builder mLayoutBuilder; 1296e1b7e3e383e12d36356841130647b846e4c8467Diego Perez private boolean mNewRenderSize; 1303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final class PostInflateException extends Exception { 1323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final long serialVersionUID = 1L; 1333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 134bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez private PostInflateException(String message) { 1353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet super(message); 1363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 1403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Creates a layout scene with all the information coming from the layout bridge API. 1413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 1428d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)}, 1438d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta * which act as a 144ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * call to {@link RenderSessionImpl#acquire(long)} 1453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 1468d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta * @see Bridge#createSession(SessionParams) 1473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 148b32414fe256a6fe1d65e7a1443cd6ea77db8bd95Xavier Ducrohet public RenderSessionImpl(SessionParams params) { 1490fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet super(new SessionParams(params)); 150ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 151ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 152ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 153ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Initializes and acquires the scene, creating various Android objects such as context, 154ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * inflater, and parser. 155ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 156ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @param timeout the time to wait if another rendering is happening. 157ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 158ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @return whether the scene was prepared 159ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 160ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #acquire(long) 161ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #release() 162ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 1630fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet @Override 164ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result init(long timeout) { 1650fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet Result result = super.init(timeout); 166952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta if (!result.isSuccess()) { 167ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return result; 168ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 1693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1700fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet SessionParams params = getParams(); 1710fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet BridgeContext context = getContext(); 1723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 173a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet // use default of true in case it's not found to use alpha by default 174300f4893351a9974fa3380c513b29d4a7883cd74Deepanshu Gupta mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(), 175300f4893351a9974fa3380c513b29d4a7883cd74Deepanshu Gupta "windowIsFloating", true, true); 176ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 1778b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta mLayoutBuilder = new Layout.Builder(params, context); 1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // build the inflater and parser. 180b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta mInflater = new BridgeInflater(context, params.getLayoutlibCallback()); 1810fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet context.setBridgeInflater(mInflater); 182ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 1838b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false); 184ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 1853054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet return SUCCESS.createResult(); 1863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 1896e1b7e3e383e12d36356841130647b846e4c8467Diego Perez * Measures the the current layout if needed (see {@link #invalidateRenderingSize}). 1906e1b7e3e383e12d36356841130647b846e4c8467Diego Perez */ 1917bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez private void measureLayout(@NonNull SessionParams params) { 1926e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // only do the screen measure when needed. 1936e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (mMeasuredScreenWidth != -1) { 1946e1b7e3e383e12d36356841130647b846e4c8467Diego Perez return; 1956e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 1966e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 1976e1b7e3e383e12d36356841130647b846e4c8467Diego Perez RenderingMode renderingMode = params.getRenderingMode(); 1986e1b7e3e383e12d36356841130647b846e4c8467Diego Perez HardwareConfig hardwareConfig = params.getHardwareConfig(); 1996e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 2006e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mNewRenderSize = true; 2016e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenWidth = hardwareConfig.getScreenWidth(); 2026e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenHeight = hardwareConfig.getScreenHeight(); 2036e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 2046e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (renderingMode != RenderingMode.NORMAL) { 2056e1b7e3e383e12d36356841130647b846e4c8467Diego Perez int widthMeasureSpecMode = renderingMode.isHorizExpand() ? 2066e1b7e3e383e12d36356841130647b846e4c8467Diego Perez MeasureSpec.UNSPECIFIED // this lets us know the actual needed size 2076e1b7e3e383e12d36356841130647b846e4c8467Diego Perez : MeasureSpec.EXACTLY; 2086e1b7e3e383e12d36356841130647b846e4c8467Diego Perez int heightMeasureSpecMode = renderingMode.isVertExpand() ? 2096e1b7e3e383e12d36356841130647b846e4c8467Diego Perez MeasureSpec.UNSPECIFIED // this lets us know the actual needed size 2106e1b7e3e383e12d36356841130647b846e4c8467Diego Perez : MeasureSpec.EXACTLY; 2116e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 2126e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // We used to compare the measured size of the content to the screen size but 2136e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // this does not work anymore due to the 2 following issues: 2146e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // - If the content is in a decor (system bar, title/action bar), the root view 2156e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // will not resize even with the UNSPECIFIED because of the embedded layout. 2166e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // - If there is no decor, but a dialog frame, then the dialog padding prevents 2176e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // comparing the size of the content to the screen frame (as it would not 2186e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // take into account the dialog padding). 2196e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 2206e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // The solution is to first get the content size in a normal rendering, inside 2216e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // the decor or the dialog padding. 2226e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // Then measure only the content with UNSPECIFIED to see the size difference 2236e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // and apply this to the screen size. 2246e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 225bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez View measuredView = mContentRoot.getChildAt(0); 226bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez 2276e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // first measure the full layout, with EXACTLY to get the size of the 2286e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // content as it is inside the decor/dialog 2296e1b7e3e383e12d36356841130647b846e4c8467Diego Perez @SuppressWarnings("deprecation") 2306e1b7e3e383e12d36356841130647b846e4c8467Diego Perez Pair<Integer, Integer> exactMeasure = measureView( 231bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez mViewRoot, measuredView, 2326e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenWidth, MeasureSpec.EXACTLY, 2336e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenHeight, MeasureSpec.EXACTLY); 2346e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 2356e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // now measure the content only using UNSPECIFIED (where applicable, based on 2366e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // the rendering mode). This will give us the size the content needs. 2376e1b7e3e383e12d36356841130647b846e4c8467Diego Perez @SuppressWarnings("deprecation") 2386e1b7e3e383e12d36356841130647b846e4c8467Diego Perez Pair<Integer, Integer> result = measureView( 2396e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mContentRoot, mContentRoot.getChildAt(0), 2406e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenWidth, widthMeasureSpecMode, 2416e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenHeight, heightMeasureSpecMode); 2426e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 243bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez // If measuredView is not null, exactMeasure nor result will be null. 244bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez assert exactMeasure != null; 245bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez assert result != null; 246bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez 2476e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // now look at the difference and add what is needed. 2486e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (renderingMode.isHorizExpand()) { 2496e1b7e3e383e12d36356841130647b846e4c8467Diego Perez int measuredWidth = exactMeasure.getFirst(); 2506e1b7e3e383e12d36356841130647b846e4c8467Diego Perez int neededWidth = result.getFirst(); 2516e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (neededWidth > measuredWidth) { 2526e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenWidth += neededWidth - measuredWidth; 2536e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2546e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (mMeasuredScreenWidth < measuredWidth) { 2556e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // If the screen width is less than the exact measured width, 2566e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // expand to match. 2576e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenWidth = measuredWidth; 2586e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2596e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2606e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 2616e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (renderingMode.isVertExpand()) { 2626e1b7e3e383e12d36356841130647b846e4c8467Diego Perez int measuredHeight = exactMeasure.getSecond(); 2636e1b7e3e383e12d36356841130647b846e4c8467Diego Perez int neededHeight = result.getSecond(); 2646e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (neededHeight > measuredHeight) { 2656e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenHeight += neededHeight - measuredHeight; 2666e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2676e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (mMeasuredScreenHeight < measuredHeight) { 2686e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // If the screen height is less than the exact measured height, 2696e1b7e3e383e12d36356841130647b846e4c8467Diego Perez // expand to match. 2706e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenHeight = measuredHeight; 2716e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2726e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2736e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2746e1b7e3e383e12d36356841130647b846e4c8467Diego Perez } 2756e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 2766e1b7e3e383e12d36356841130647b846e4c8467Diego Perez /** 2773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Inflates the layout. 2783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 279ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 280ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 281ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 282ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #init(long)} was not called. 2833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 284ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result inflate() { 285ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 286ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 2873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 2888b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta mViewRoot = new Layout(mLayoutBuilder); 2898b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta mLayoutBuilder = null; // Done with the builder. 2908b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta mContentRoot = ((Layout) mViewRoot).getContentRoot(); 2910fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet SessionParams params = getParams(); 2920fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet BridgeContext context = getContext(); 2933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2945cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez if (Bridge.isLocaleRtl(params.getLocale())) { 2955cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez if (!params.isRtlSupported()) { 2965cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez Bridge.getLog().warning(LayoutLog.TAG_RTL_NOT_ENABLED, 2975cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez "You are using a right-to-left " + 2985cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez "(RTL) locale but RTL is not enabled", null); 2995cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez } else if (params.getSimulatedPlatformVersion() < 17) { 3005cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez // This will render ok because we are using the latest layoutlib but at least 3015cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez // warn the user that this might fail in a real device. 3025cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez Bridge.getLog().warning(LayoutLog.TAG_RTL_NOT_SUPPORTED, "You are using a " + 3035cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez "right-to-left " + 3045cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez "(RTL) locale but RTL is not supported for API level < 17", null); 3055cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez } 3065cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez } 3075cee4833e93b8f9aa9f38815eaa342fab9cc8658Diego Perez 3083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Sets the project callback (custom view loader) to the fragment delegate so that 3093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // it can instantiate the custom Fragment. 310b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback()); 3113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 312a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaev String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG); 3138a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta boolean isPreference = "PreferenceScreen".equals(rootTag); 3148a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta View view; 3158a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta if (isPreference) { 316b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez // First try to use the support library inflater. If something fails, fallback 317b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez // to the system preference inflater. 318b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez view = SupportPreferencesUtil.inflatePreference(getContext(), mBlockParser, 3198b4b0ce31acc9f57c7df5b1c70183a6655c1edfbDeepanshu Gupta mContentRoot); 320b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez if (view == null) { 321b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez view = Preference_Delegate.inflatePreference(getContext(), mBlockParser, 322b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez mContentRoot); 323b321cbfeb00723a6d18746f0d5bbcfd6b6602f6eDiego Perez } 3248a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta } else { 3258a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta view = mInflater.inflate(mBlockParser, mContentRoot); 3268a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta } 3273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3287062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet // done with the parser, pop it. 3297062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet context.popParser(); 3307062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 331b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta Fragment_Delegate.setLayoutlibCallback(null); 3323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // set the AttachInfo on the root view. 334994236e95e9809ec8c1d06a218f606f1af2083afXavier Ducrohet AttachInfo_Accessor.setAttachInfo(mViewRoot); 3353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 336a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet // post-inflate process. For now this supports TabHost/TabWidget 337b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null); 3389028fa93da0f9c7dad2176de347cd6e705084c9fDeepanshu Gupta mInflater.onDoneInflation(); 339a2378f55b81e7d29f451d7f65527de49417a3f0cXavier Ducrohet 340c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen setActiveToolbar(view, context, params); 341c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen 3427bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez measureLayout(params); 3436e1b7e3e383e12d36356841130647b846e4c8467Diego Perez measureView(mViewRoot, null /*measuredView*/, 3446e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenWidth, MeasureSpec.EXACTLY, 3456e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mMeasuredScreenHeight, MeasureSpec.EXACTLY); 3466e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight); 347e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez mSystemViewInfoList = 348e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(), 3496e1b7e3e383e12d36356841130647b846e4c8467Diego Perez false); 3506e1b7e3e383e12d36356841130647b846e4c8467Diego Perez 35167f948f353b652d3373c7bdb0c2a8715e8b4e9f6Diego Perez Choreographer_Delegate.clearFrames(); 35267f948f353b652d3373c7bdb0c2a8715e8b4e9f6Diego Perez 353ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (PostInflateException e) { 355ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_INFLATION.createResult(e.getMessage(), e); 3563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 3573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 3583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 3593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 3603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 3613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 363ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_INFLATION.createResult(t.getMessage(), t); 3643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 368344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta * Sets the time for which the next frame will be selected. The time is the elapsed time from 369344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta * the current system nanos time. You 370344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta */ 371344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta public void setElapsedFrameTimeNanos(long nanos) { 372344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta mElapsedFrameTimeNanos = nanos; 373344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta } 374344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta 375344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta /** 376f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez * Runs a layout pass for the given view root 3770685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez */ 378f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez private static void doLayout(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot, 379f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez int width, int height) { 3800685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez // measure again with the size we need 3810685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez // This must always be done before the call to layout 3820685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez measureView(viewRoot, null /*measuredView*/, 3830685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez width, MeasureSpec.EXACTLY, 3840685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez height, MeasureSpec.EXACTLY); 3850685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez 3860685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez // now do the layout. 3870685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez viewRoot.layout(0, 0, width, height); 3880685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez handleScrolling(context, viewRoot); 389f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez } 3900685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez 391f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez /** 392f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez * Renders the given view hierarchy to the passed canvas and returns the result of the render 393f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez * operation. 394f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez * @param canvas an optional canvas to render the views to. If null, only the measure and 395f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez * layout steps will be executed. 396f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez */ 397bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez private static Result renderAndBuildResult(@NonNull ViewGroup viewRoot, @Nullable Canvas canvas) { 3980685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez if (canvas == null) { 3990685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez return SUCCESS.createResult(); 4000685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez } 4010685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez 4020685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez AttachInfo_Accessor.dispatchOnPreDraw(viewRoot); 4030685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez viewRoot.draw(canvas); 4040685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez 4050685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez return SUCCESS.createResult(); 4060685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez } 4070685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez 4080685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez /** 4093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Renders the scene. 4103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 411ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 412ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 4134c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet * @param freshRender whether the render is a new one and should erase the existing bitmap (in 4144c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet * the case where bitmaps are reused). This is typically needed when not playing 4154c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet * animations.) 4164c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet * 417ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 418ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 4191392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet * 4208d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta * @see SessionParams#getRenderingMode() 421799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet * @see RenderSession#render(long) 4223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 4234c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet public Result render(boolean freshRender) { 4247bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez return renderAndBuildResult(freshRender, false); 4257bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez } 4267bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez 4277bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez /** 4287bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * Measures the layout 4297bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * <p> 4307bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * {@link #acquire(long)} must have been called before this. 4317bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * 4327bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * @throws IllegalStateException if the current context is different than the one owned by 4337bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * the scene, or if {@link #acquire(long)} was not called. 4347bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * 4357bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * @see SessionParams#getRenderingMode() 4367bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * @see RenderSession#render(long) 4377bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez */ 4387bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez public Result measure() { 4397bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez return renderAndBuildResult(false, true); 4407bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez } 4417bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez 4427bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez /** 4437bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * Renders the scene. 4447bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * <p> 4457bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * {@link #acquire(long)} must have been called before this. 4467bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * 4477bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * @param freshRender whether the render is a new one and should erase the existing bitmap (in 4487bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * the case where bitmaps are reused). This is typically needed when not playing 4497bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * animations.) 4507bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * 4517bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * @throws IllegalStateException if the current context is different than the one owned by 4527bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * the scene, or if {@link #acquire(long)} was not called. 4537bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * 4547bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * @see SessionParams#getRenderingMode() 4557bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez * @see RenderSession#render(long) 4567bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez */ 4577bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez private Result renderAndBuildResult(boolean freshRender, boolean onlyMeasure) { 458ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 459ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 4600fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet SessionParams params = getParams(); 4610fde9af6be75b32a401eafc8904426424e00e70cXavier Ducrohet 4623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 4633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mViewRoot == null) { 464ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_NOT_INFLATED.createResult(); 4653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4677bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez measureLayout(params); 4683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4696e1b7e3e383e12d36356841130647b846e4c8467Diego Perez HardwareConfig hardwareConfig = params.getHardwareConfig(); 4700685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez Result renderResult = SUCCESS.createResult(); 4717bb8850ed2076ebf8442a5fdb68ec9a8f53623e0Diego Perez if (onlyMeasure) { 472f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet // delete the canvas and image to reset them on the next full rendering 473f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mImage = null; 474f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mCanvas = null; 475f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez doLayout(getContext(), mViewRoot, mMeasuredScreenWidth, mMeasuredScreenHeight); 476f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet } else { 477f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet // draw the views 478f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet // create the BufferedImage into which the layout will be rendered. 479f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet boolean newImage = false; 480e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez 481e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez // When disableBitmapCaching is true, we do not reuse mImage and 482e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez // we create a new one in every render. 483e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez // This is useful when mImage is just a wrapper of Graphics2D so 484e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez // it doesn't get cached. 485e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag( 486a4a2d3d5936bcdda1409796179725d354e5f4400Andrew Shulaev RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING)); 4876e1b7e3e383e12d36356841130647b846e4c8467Diego Perez if (mNewRenderSize || mCanvas == null || disableBitmapCaching) { 4886e1b7e3e383e12d36356841130647b846e4c8467Diego Perez mNewRenderSize = false; 489f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet if (params.getImageFactory() != null) { 490f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mImage = params.getImageFactory().getImage( 491f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mMeasuredScreenWidth, 492f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mMeasuredScreenHeight); 493f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet } else { 494f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mImage = new BufferedImage( 495f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mMeasuredScreenWidth, 496f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet mMeasuredScreenHeight, 497f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet BufferedImage.TYPE_INT_ARGB); 498f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet newImage = true; 499f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet } 500f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet 501f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet if (params.isBgColorOverridden()) { 502f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet // since we override the content, it's the same as if it was a new image. 503f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet newImage = true; 504f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet Graphics2D gc = mImage.createGraphics(); 505f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet gc.setColor(new Color(params.getOverrideBgColor(), true)); 506f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet gc.setComposite(AlphaComposite.Src); 507f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight); 508f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet gc.dispose(); 509f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet } 510f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet 511f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet // create an Android bitmap around the BufferedImage 512f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage, 51364f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet true /*isMutable*/, hardwareConfig.getDensity()); 514f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet 515e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez if (mCanvas == null) { 516e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez // create a Canvas around the Android bitmap 517e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez mCanvas = new Canvas(bitmap); 518e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez } else { 519e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez mCanvas.setBitmap(bitmap); 520e12b3f96291cf0e3dc60d9db9ac3d3859325f3d4Diego Perez } 52164f5dc0e6437e95695ed4048f047c3cbef447e0fXavier Ducrohet mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue()); 5221392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 5233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 524952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta if (freshRender && !newImage) { 5251392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet Graphics2D gc = mImage.createGraphics(); 5264c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet gc.setComposite(AlphaComposite.Src); 5273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 528f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet gc.setColor(new Color(0x00000000, true)); 529f4978e031c3ad565f02d5a4c65f87ae4477f3613Deepanshu Gupta gc.fillRect(0, 0, 530f4978e031c3ad565f02d5a4c65f87ae4477f3613Deepanshu Gupta mMeasuredScreenWidth, mMeasuredScreenHeight); 531a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet 532f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet // done 533f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet gc.dispose(); 534f27575799aab2e552c0491a07b34389e1422fc27Xavier Ducrohet } 535a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet 536f1a0a823499fc0a464e18b8eba992b32d14b8bb1Diego Perez doLayout(getContext(), mViewRoot, mMeasuredScreenWidth, mMeasuredScreenHeight); 537344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta if (mElapsedFrameTimeNanos >= 0) { 538344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta long initialTime = System_Delegate.nanoTime(); 539344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta if (!mFirstFrameExecuted) { 5400685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez // We need to run an initial draw call to initialize the animations 541bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez renderAndBuildResult(mViewRoot, NOP_CANVAS); 5420685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez 543344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta // The first frame will initialize the animations 544344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta Choreographer_Delegate.doFrame(initialTime); 545344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta mFirstFrameExecuted = true; 546344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta } 547344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta // Second frame will move the animations 548344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos); 549344cbc9b8ed3ae06a5b183d684df0399fef59879Deepanshu Gupta } 550bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez renderResult = renderAndBuildResult(mViewRoot, mCanvas); 5514c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet } 5524c6c050f68c67097b92eb38e9f01dae9885907caXavier Ducrohet 553e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez mSystemViewInfoList = 554e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(), 55541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta false); 5563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // success! 5580685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez return renderResult; 5593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 5603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 5613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 5623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 5633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 5643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 566ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_UNKNOWN.createResult(t.getMessage(), t); 5673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 5718ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * Executes {@link View#measure(int, int)} on a given view with the given parameters (used 5728ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}. 5738ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * 5748ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height) 5758ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}). 5768ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * 5778ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * @param viewToMeasure the view on which to execute measure(). 5788ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * @param measuredView if non null, the view to query for its measured width/height. 5798ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * @param width the width to use in the MeasureSpec. 5808ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * @param widthMode the MeasureSpec mode to use for the width. 5818ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * @param height the height to use in the MeasureSpec. 5828ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * @param heightMode the MeasureSpec mode to use for the height. 5838ae691c1148038995d1185716f629b82c582897fXavier Ducrohet * @return the measured width/height if measuredView is non-null, null otherwise. 5848ae691c1148038995d1185716f629b82c582897fXavier Ducrohet */ 585952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta @SuppressWarnings("deprecation") // For the use of Pair 5860685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView, 5878ae691c1148038995d1185716f629b82c582897fXavier Ducrohet int width, int widthMode, int height, int heightMode) { 5888ae691c1148038995d1185716f629b82c582897fXavier Ducrohet int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode); 5898ae691c1148038995d1185716f629b82c582897fXavier Ducrohet int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode); 5908ae691c1148038995d1185716f629b82c582897fXavier Ducrohet viewToMeasure.measure(w_spec, h_spec); 5918ae691c1148038995d1185716f629b82c582897fXavier Ducrohet 5928ae691c1148038995d1185716f629b82c582897fXavier Ducrohet if (measuredView != null) { 5938ae691c1148038995d1185716f629b82c582897fXavier Ducrohet return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight()); 5948ae691c1148038995d1185716f629b82c582897fXavier Ducrohet } 5958ae691c1148038995d1185716f629b82c582897fXavier Ducrohet 5968ae691c1148038995d1185716f629b82c582897fXavier Ducrohet return null; 5978ae691c1148038995d1185716f629b82c582897fXavier Ducrohet } 5988ae691c1148038995d1185716f629b82c582897fXavier Ducrohet 5998ae691c1148038995d1185716f629b82c582897fXavier Ducrohet /** 600952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta * Post process on a view hierarchy that was just inflated. 601952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta * <p/> 602952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the 6033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically 6043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * based on the content of the {@link FrameLayout}. 6053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param view the root view to process. 606b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta * @param layoutlibCallback callback to the project. 6078a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta * @param skip the view and it's children are not processed. 6083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 609952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta @SuppressWarnings("deprecation") // For the use of Pair 610b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip) 6113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 6128a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta if (view == skip) { 6138a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta return; 6148a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta } 6153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view instanceof TabHost) { 616b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta setupTabHost((TabHost) view, layoutlibCallback); 61762c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet } else if (view instanceof QuickContactBadge) { 61862c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet QuickContactBadge badge = (QuickContactBadge) view; 61962c9c3463a9b4a4bc899f5db353f2856876e6590Xavier Ducrohet badge.setImageToDefault(); 6207062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } else if (view instanceof AdapterView<?>) { 6217062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet // get the view ID. 6227062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet int id = view.getId(); 6237062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6247062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet BridgeContext context = getContext(); 6257062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6267062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet // get a ResourceReference from the integer ID. 6277062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet ResourceReference listRef = context.resolveId(id); 6287062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6297062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if (listRef != null) { 6307062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet SessionParams params = getParams(); 6317062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet AdapterBinding binding = params.getAdapterBindings().get(listRef); 6327062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6337062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet // if there was no adapter binding, trying to get it from the call back. 6347062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if (binding == null) { 635b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta binding = layoutlibCallback.getAdapterBinding( 636b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta listRef, context.getViewKey(view), view); 6377062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6387062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6397062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if (binding != null) { 6407062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6417062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if (view instanceof AbsListView) { 6427062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) && 6437062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet view instanceof ListView) { 6447062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet ListView list = (ListView) view; 6457062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6467062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet boolean skipCallbackParser = false; 6477062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6487062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet int count = binding.getHeaderCount(); 6498a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta for (int i = 0; i < count; i++) { 6507062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet Pair<View, Boolean> pair = context.inflateView( 6517062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet binding.getHeaderAt(i), 652b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta list, false, skipCallbackParser); 6537062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if (pair.getFirst() != null) { 6547062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet list.addHeaderView(pair.getFirst()); 6557062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6567062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6577062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet skipCallbackParser |= pair.getSecond(); 6587062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6597062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6607062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet count = binding.getFooterCount(); 6618a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta for (int i = 0; i < count; i++) { 6627062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet Pair<View, Boolean> pair = context.inflateView( 6637062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet binding.getFooterAt(i), 664b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta list, false, skipCallbackParser); 6657062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if (pair.getFirst() != null) { 6667062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet list.addFooterView(pair.getFirst()); 6677062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6687062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6697062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet skipCallbackParser |= pair.getSecond(); 6707062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6717062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6727062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet 6737062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet if (view instanceof ExpandableListView) { 6747062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet ((ExpandableListView) view).setAdapter( 675b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta new FakeExpandableAdapter(listRef, binding, layoutlibCallback)); 6767062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } else { 6777062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet ((AbsListView) view).setAdapter( 678b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta new FakeAdapter(listRef, binding, layoutlibCallback)); 6797062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6807062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } else if (view instanceof AbsSpinner) { 6817062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet ((AbsSpinner) view).setAdapter( 682b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta new FakeAdapter(listRef, binding, layoutlibCallback)); 6837062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6847062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6857062c1ad9adcb216ac49100ca1044e9d89e8f8c1Xavier Ducrohet } 6863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else if (view instanceof ViewGroup) { 6879028fa93da0f9c7dad2176de347cd6e705084c9fDeepanshu Gupta mInflater.postInflateProcess(view); 6888a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta ViewGroup group = (ViewGroup) view; 6893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = group.getChildCount(); 6908a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta for (int c = 0; c < count; c++) { 6913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View child = group.getChildAt(c); 692b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta postInflateProcess(child, layoutlibCallback, skip); 6933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 698c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen * If the root layout is a CoordinatorLayout with an AppBar: 699c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen * Set the title of the AppBar to the title of the activity context. 700c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen */ 701c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen private void setActiveToolbar(View view, BridgeContext context, SessionParams params) { 702c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT); 703c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (coordinatorLayout == null) { 704c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return; 705c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 706c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT); 707c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (appBar == null) { 708c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return; 709c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 710c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen ViewGroup collapsingToolbar = 711c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT); 712c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (collapsingToolbar == null) { 713c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return; 714c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 715c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (!hasToolbar(collapsingToolbar)) { 716c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return; 717c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 718c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen RenderResources res = context.getRenderResources(); 719c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen String title = params.getAppLabel(); 720c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen ResourceValue titleValue = res.findResValue(title, false); 721c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (titleValue != null && titleValue.getValue() != null) { 722c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen title = titleValue.getValue(); 723c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 724c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen DesignLibUtil.setTitle(collapsingToolbar, title); 725c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 726c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen 727c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen private View findChildView(View view, String className) { 728c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (!(view instanceof ViewGroup)) { 729c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return null; 730c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 731c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen ViewGroup group = (ViewGroup) view; 732c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen for (int i = 0; i < group.getChildCount(); i++) { 733c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (isInstanceOf(group.getChildAt(i), className)) { 734c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return group.getChildAt(i); 735c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 736c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 737c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return null; 738c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 739c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen 740c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen private boolean hasToolbar(View collapsingToolbar) { 741c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (!(collapsingToolbar instanceof ViewGroup)) { 742c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return false; 743c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 744c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen ViewGroup group = (ViewGroup) collapsingToolbar; 745c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen for (int i = 0; i < group.getChildCount(); i++) { 746c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) { 747c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return true; 748c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 749c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 750c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return false; 751c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 752c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen 753c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen /** 754777163c3facaed668b43061d726a572fd58f6f60Diego Perez * Set the scroll position on all the components with the "scrollX" and "scrollY" attribute. If 755777163c3facaed668b43061d726a572fd58f6f60Diego Perez * the component supports nested scrolling attempt that first, then use the unconsumed scroll 756777163c3facaed668b43061d726a572fd58f6f60Diego Perez * part to scroll the content in the component. 757c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen */ 7580685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez private static void handleScrolling(BridgeContext context, View view) { 759777163c3facaed668b43061d726a572fd58f6f60Diego Perez int scrollPosX = context.getScrollXPos(view); 760777163c3facaed668b43061d726a572fd58f6f60Diego Perez int scrollPosY = context.getScrollYPos(view); 761777163c3facaed668b43061d726a572fd58f6f60Diego Perez if (scrollPosX != 0 || scrollPosY != 0) { 762c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (view.isNestedScrollingEnabled()) { 763c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen int[] consumed = new int[2]; 764777163c3facaed668b43061d726a572fd58f6f60Diego Perez int axis = scrollPosX != 0 ? View.SCROLL_AXIS_HORIZONTAL : 0; 765777163c3facaed668b43061d726a572fd58f6f60Diego Perez axis |= scrollPosY != 0 ? View.SCROLL_AXIS_VERTICAL : 0; 766777163c3facaed668b43061d726a572fd58f6f60Diego Perez if (view.startNestedScroll(axis)) { 767777163c3facaed668b43061d726a572fd58f6f60Diego Perez view.dispatchNestedPreScroll(scrollPosX, scrollPosY, consumed, null); 768777163c3facaed668b43061d726a572fd58f6f60Diego Perez view.dispatchNestedScroll(consumed[0], consumed[1], scrollPosX, scrollPosY, 769777163c3facaed668b43061d726a572fd58f6f60Diego Perez null); 770c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen view.stopNestedScroll(); 771777163c3facaed668b43061d726a572fd58f6f60Diego Perez scrollPosX -= consumed[0]; 772777163c3facaed668b43061d726a572fd58f6f60Diego Perez scrollPosY -= consumed[1]; 773c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 774c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 775777163c3facaed668b43061d726a572fd58f6f60Diego Perez if (scrollPosX != 0 || scrollPosY != 0) { 7760685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez view.scrollTo(scrollPosX, scrollPosY); 777c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 778c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 779c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen 780c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen if (!(view instanceof ViewGroup)) { 781c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen return; 782c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 783c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen ViewGroup group = (ViewGroup) view; 784c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen for (int i = 0; i < group.getChildCount(); i++) { 785c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen View child = group.getChildAt(i); 7860685ab35ad78094ceb2d9fb0583e2cadd1968c90Diego Perez handleScrolling(context, child); 787c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 788c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen } 789c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen 790c46c84ee673934f340b27b40366a5a61669a4a1eJens Ole Lauridsen /** 7913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Sets up a {@link TabHost} object. 7923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param tabHost the TabHost to setup. 793b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta * @param layoutlibCallback The project callback object to access the project R class. 794bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez * @throws PostInflateException if TabHost is missing the required ids for TabHost 7953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 796b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback) 7973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 7983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // look for the TabWidget, and the FrameLayout. They have their own specific names 7993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View v = tabHost.findViewById(android.R.id.tabs); 8003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 8023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 8033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n"); 8043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 806952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta if (!(v instanceof TabWidget)) { 8073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 8083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n" + 8093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName())); 8103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet v = tabHost.findViewById(android.R.id.tabcontent); 8133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 815952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty) 816952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta //noinspection SpellCheckingInspection 8173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 8183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\"."); 8193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 821952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta if (!(v instanceof FrameLayout)) { 822952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta //noinspection SpellCheckingInspection 8233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 8243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" + 8253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName())); 8263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet FrameLayout content = (FrameLayout)v; 8293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 830952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta // now process the content of the frameLayout and dynamically create tabs for it. 8313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = content.getChildCount(); 8323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // this must be called before addTab() so that the TabHost searches its TabWidget 8343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // and FrameLayout. 835f59abd4701479e496d955cb8521a813e535aefa3Jerome Gaillard if (ReflectionUtils.isInstanceOf(tabHost, FragmentTabHostUtil.CN_FRAGMENT_TAB_HOST)) { 836f59abd4701479e496d955cb8521a813e535aefa3Jerome Gaillard FragmentTabHostUtil.setup(tabHost, getContext()); 837f59abd4701479e496d955cb8521a813e535aefa3Jerome Gaillard } else { 838f59abd4701479e496d955cb8521a813e535aefa3Jerome Gaillard tabHost.setup(); 839f59abd4701479e496d955cb8521a813e535aefa3Jerome Gaillard } 8403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 841f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye if (count == 0) { 842f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye // Create a dummy child to get a single tab 8436257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta TabSpec spec = tabHost.newTabSpec("tag") 8446257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta .setIndicator("Tab Label", tabHost.getResources() 8456257175afa5c892cb0a7cd14d958418c1720cb84Deepanshu Gupta .getDrawable(android.R.drawable.ic_menu_info_details, null)) 846bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez .setContent(tag -> new LinearLayout(getContext())); 847f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye tabHost.addTab(spec); 848f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye } else { 849952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta // for each child of the frameLayout, add a new TabSpec 850f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye for (int i = 0 ; i < count ; i++) { 851f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye View child = content.getChildAt(i); 852f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye String tabSpec = String.format("tab_spec%d", i+1); 8538a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta @SuppressWarnings("ConstantConditions") // child cannot be null. 854f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye int id = child.getId(); 855952c989b307d4b710ee1adba064f663808af9eb3Deepanshu Gupta @SuppressWarnings("deprecation") 856b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta Pair<ResourceType, String> resource = layoutlibCallback.resolveResourceId(id); 857f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye String name; 858f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye if (resource != null) { 859947b979a91ac1cd556244d875d8b8d4fec8fd474Xavier Ducrohet name = resource.getSecond(); 860f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye } else { 861f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye name = String.format("Tab %d", i+1); // default name if id is unresolved. 862f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye } 863f14c342b8a0024e5ca8c2c3ffce8b79abe03e941Tor Norbye tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id)); 8643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 86885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta /** 86985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the 87085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * bounds of all the views. 87185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * 87285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @param view the root View 873e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * @param hOffset horizontal offset for the view bounds. 874e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * @param vOffset vertical offset for the view bounds. 87585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object. 87685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the 87785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * content frame. 87885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * 87985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @return {@code ViewInfo} containing the bounds of the view and it children otherwise. 88085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta */ 881e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez private ViewInfo visit(View view, int hOffset, int vOffset, boolean setExtendedInfo, 88285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta boolean isContentFrame) { 883e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez ViewInfo result = createViewInfo(view, hOffset, vOffset, setExtendedInfo, isContentFrame); 884799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet 88585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta if (view instanceof ViewGroup) { 88685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta ViewGroup group = ((ViewGroup) view); 887e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez result.setChildren(visitAllChildren(group, isContentFrame ? 0 : hOffset, 888e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez isContentFrame ? 0 : vOffset, 88985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta setExtendedInfo, isContentFrame)); 89085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 89185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta return result; 89285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 893799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet 89485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta /** 89585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo} 8968d43509cc2c0f95bd07d6585dadfac296bc5d24dDeepanshu Gupta * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with 89785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * the children of the {@code mContentRoot}. 89885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * 89985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @param viewGroup the root View 900e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * @param hOffset horizontal offset from the top for the content view frame. 901e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * @param vOffset vertical offset from the top for the content view frame. 90285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object. 90385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the 90485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * content frame. {@code false} if the {@code ViewInfo} to be created is 90585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * part of the system decor. 90685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta */ 907e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int hOffset, int vOffset, 90885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta boolean setExtendedInfo, boolean isContentFrame) { 90985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta if (viewGroup == null) { 91085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta return null; 911799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet } 912799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet 91385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta if (!isContentFrame) { 914e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez vOffset += viewGroup.getTop(); 915e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez hOffset += viewGroup.getLeft(); 91685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 917799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet 91885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta int childCount = viewGroup.getChildCount(); 91985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta if (viewGroup == mContentRoot) { 920bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez List<ViewInfo> childrenWithoutOffset = new ArrayList<>(childCount); 921bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez List<ViewInfo> childrenWithOffset = new ArrayList<>(childCount); 92285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta for (int i = 0; i < childCount; i++) { 923e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez ViewInfo[] childViewInfo = 924e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez visitContentRoot(viewGroup.getChildAt(i), hOffset, vOffset, 9256208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet setExtendedInfo); 92685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta childrenWithoutOffset.add(childViewInfo[0]); 92785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta childrenWithOffset.add(childViewInfo[1]); 928799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet } 92985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta mViewInfoList = childrenWithOffset; 93085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta return childrenWithoutOffset; 93185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } else { 932bca9e5623c820c9aa1e959e3874442de9a9a6c32Diego Perez List<ViewInfo> children = new ArrayList<>(childCount); 93385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta for (int i = 0; i < childCount; i++) { 934e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez children.add(visit(viewGroup.getChildAt(i), hOffset, vOffset, setExtendedInfo, 93585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta isContentFrame)); 93685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 93785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta return children; 938799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet } 93985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 940799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet 94185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta /** 94285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the 94385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * bounds of all the views. It returns two {@code ViewInfo} objects with the same children, 94485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * one with the {@code offset} and other without the {@code offset}. The offset is needed to 94585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * get the right bounds if the {@code ViewInfo} hierarchy is accessed from 94685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the 94785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * offset is not needed. 94885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * 94985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at 95085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * index 1 is with the offset. 95185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta */ 952432578acb80cf2fa827ddb9595cf46edf0b340b0Deepanshu Gupta @NonNull 953e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez private ViewInfo[] visitContentRoot(View view, int hOffset, int vOffset, 954e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez boolean setExtendedInfo) { 95585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta ViewInfo[] result = new ViewInfo[2]; 95685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta if (view == null) { 95785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta return result; 95885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 95985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta 960e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez result[0] = createViewInfo(view, 0, 0, setExtendedInfo, true); 961e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez result[1] = createViewInfo(view, hOffset, vOffset, setExtendedInfo, true); 96285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta if (view instanceof ViewGroup) { 963e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez List<ViewInfo> children = 964e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez visitAllChildren((ViewGroup) view, 0, 0, setExtendedInfo, true); 96585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta result[0].setChildren(children); 96685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta result[1].setChildren(children); 96785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 96885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta return result; 969799fe3b371c812a0e94872f896b54afa44e94868Xavier Ducrohet } 9703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 97285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children 97385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not 97485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta * set. 975e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * @param hOffset horizontal offset for the view bounds. Used only if view is part of the 976e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * content frame. 977e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * @param vOffset vertial an offset for the view bounds. Used only if view is part of the 978e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez * content frame. 9793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 980e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez private ViewInfo createViewInfo(View view, int hOffset, int vOffset, boolean setExtendedInfo, 98185c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta boolean isContentFrame) { 9823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view == null) { 9833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 9843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 986777163c3facaed668b43061d726a572fd58f6f60Diego Perez ViewParent parent = view.getParent(); 98785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta ViewInfo result; 98885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta if (isContentFrame) { 989777163c3facaed668b43061d726a572fd58f6f60Diego Perez // Account for parent scroll values when calculating the bounding box 990777163c3facaed668b43061d726a572fd58f6f60Diego Perez int scrollX = parent != null ? ((View)parent).getScrollX() : 0; 991777163c3facaed668b43061d726a572fd58f6f60Diego Perez int scrollY = parent != null ? ((View)parent).getScrollY() : 0; 992777163c3facaed668b43061d726a572fd58f6f60Diego Perez 99370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // The view is part of the layout added by the user. Hence, 99470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // the ViewCookie may be obtained only through the Context. 99585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta result = new ViewInfo(view.getClass().getName(), 996e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez getContext().getViewKey(view), -scrollX + view.getLeft() + hOffset, 997e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez -scrollY + view.getTop() + vOffset, -scrollX + view.getRight() + hOffset, 998e48b02f441a8a90f0a1618ed2116c83441aae3bdDiego Perez -scrollY + view.getBottom() + vOffset, 999777163c3facaed668b43061d726a572fd58f6f60Diego Perez view, view.getLayoutParams()); 100085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } else { 100170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // We are part of the system decor. 100270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta SystemViewInfo r = new SystemViewInfo(view.getClass().getName(), 100341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta getViewKey(view), 100485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta view.getLeft(), view.getTop(), view.getRight(), 100585c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta view.getBottom(), view, view.getLayoutParams()); 100670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta result = r; 100770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // We currently mark three kinds of views: 100870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // 1. Menus in the Action Bar 100970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // 2. Menus in the Overflow popup. 101070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // 3. The overflow popup button. 101170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta if (view instanceof ListMenuItemView) { 101270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // Mark 2. 101370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // All menus in the popup are of type ListMenuItemView. 101470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta r.setViewType(ViewType.ACTION_BAR_OVERFLOW_MENU); 101570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta } else { 101670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // Mark 3. 101770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta ViewGroup.LayoutParams lp = view.getLayoutParams(); 101870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta if (lp instanceof ActionMenuView.LayoutParams && 101970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta ((ActionMenuView.LayoutParams) lp).isOverflowButton) { 102070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta r.setViewType(ViewType.ACTION_BAR_OVERFLOW); 102170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta } else { 102270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // Mark 1. 102370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // A view is a menu in the Action Bar is it is not the overflow button and of 102470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // its parent is of type ActionMenuView. We can also check if the view is 102570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // instanceof ActionMenuItemView but that will fail for menus using 102670114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta // actionProviderClass. 102770114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta while (parent != mViewRoot && parent instanceof ViewGroup) { 102870114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta if (parent instanceof ActionMenuView) { 102970114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta r.setViewType(ViewType.ACTION_BAR_MENU); 103070114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta break; 103170114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta } 103270114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta parent = parent.getParent(); 103370114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta } 103470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta } 103570114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta } 103685c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 10373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10386208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet if (setExtendedInfo) { 10396208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet MarginLayoutParams marginParams = null; 10406208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet LayoutParams params = view.getLayoutParams(); 10416208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet if (params instanceof MarginLayoutParams) { 10426208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet marginParams = (MarginLayoutParams) params; 10436208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet } 10446208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet result.setExtendedInfo(view.getBaseline(), 10456208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet marginParams != null ? marginParams.leftMargin : 0, 10466208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet marginParams != null ? marginParams.topMargin : 0, 10476208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet marginParams != null ? marginParams.rightMargin : 0, 10486208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet marginParams != null ? marginParams.bottomMargin : 0); 10496208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet } 10506208081afd488af51d4f7cbf858e2de59d47e4e5Xavier Ducrohet 10513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return result; 10523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 105470114b33f8054cc38090a2bbd213ebf15abee63dDeepanshu Gupta /* (non-Javadoc) 105541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta * The cookie for menu items are stored in menu item and not in the map from View stored in 105641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta * BridgeContext. 105741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta */ 1058432578acb80cf2fa827ddb9595cf46edf0b340b0Deepanshu Gupta @Nullable 105941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta private Object getViewKey(View view) { 106041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta BridgeContext context = getContext(); 106141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta if (!(view instanceof MenuView.ItemView)) { 106241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta return context.getViewKey(view); 106341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta } 106441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta MenuItemImpl menuItem; 106541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta if (view instanceof ActionMenuItemView) { 106641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta menuItem = ((ActionMenuItemView) view).getItemData(); 106741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta } else if (view instanceof ListMenuItemView) { 106841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta menuItem = ((ListMenuItemView) view).getItemData(); 106941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta } else if (view instanceof IconMenuItemView) { 107041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta menuItem = ((IconMenuItemView) view).getItemData(); 107141670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta } else { 107241670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta menuItem = null; 107341670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta } 107441670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta if (menuItem instanceof BridgeMenuItemImpl) { 107541670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta return ((BridgeMenuItemImpl) menuItem).getViewCookie(); 107641670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta } 107741670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta 107841670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta return null; 107941670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta } 108041670df819e35f5822cc166db775ed2e9e3dfb7dDeepanshu Gupta 1081620f80a7ee9796c2c41ec0a42d10d2913fc50c90Diego Perez public void invalidateRenderingSize() { 108285c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta mMeasuredScreenWidth = mMeasuredScreenHeight = -1; 108385c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 108485c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta 10853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public BufferedImage getImage() { 10863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return mImage; 10873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1089a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet public boolean isAlphaChannelImage() { 1090a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet return mIsAlphaChannelImage; 1091a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet } 1092a6a38c02bfd3f6a678ac1671f5744b8e439e075aXavier Ducrohet 1093e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet public List<ViewInfo> getViewInfos() { 1094e9a2ea4ac32589b372ec195d8be59391c686a8c6Xavier Ducrohet return mViewInfoList; 10953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10962d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet 109785c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta public List<ViewInfo> getSystemViewInfos() { 109885c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta return mSystemViewInfoList; 109985c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta } 110085c5ae75ab4b9041bb143f146ef5fc4547686210Deepanshu Gupta 110118be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta public Map<Object, PropertiesMap> getDefaultProperties() { 110218be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta return getContext().getDefaultProperties(); 110318be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta } 110418be29a3d14f1b3e840e8ee88b5a1951a6f6e9c8Deepanshu Gupta 1105ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public void setScene(RenderSession session) { 1106ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet mScene = session; 1107b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 1108b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 1109ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public RenderSession getSession() { 1110b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet return mScene; 1111b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 111295eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez 111395eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez public void dispose() { 1114e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez boolean createdLooper = false; 1115e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez if (Looper.myLooper() == null) { 1116e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez // Detaching the root view from the window will try to stop any running animations. 1117e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez // The stop method checks that it can run in the looper so, if there is no current 1118e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez // looper, we create a temporary one to complete the shutdown. 1119e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez Bridge.prepareThread(); 1120e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez createdLooper = true; 1121e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez } 112295eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez AttachInfo_Accessor.detachFromWindow(mViewRoot); 112395eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez if (mCanvas != null) { 112495eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez mCanvas.release(); 112595eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez mCanvas = null; 112695eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez } 112795eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez if (mViewInfoList != null) { 112895eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez mViewInfoList.clear(); 112995eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez } 113095eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez if (mSystemViewInfoList != null) { 113195eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez mSystemViewInfoList.clear(); 113295eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez } 113395eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez mImage = null; 113495eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez mViewRoot = null; 113595eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez mContentRoot = null; 1136e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez 1137e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez if (createdLooper) { 1138405d10472d7b8ba7ff86f46e734195128709a829Deepanshu Gupta Choreographer_Delegate.dispose(); 113967f948f353b652d3373c7bdb0c2a8715e8b4e9f6Diego Perez Bridge.cleanupThread(); 1140e4cf18face6980b0c7ac42761512cd93b89927c3Diego Perez } 114195eceea4f12c4f0e5170b1a14658f23e87e343d5Diego Perez } 11423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet} 1143