RenderSessionImpl.java revision 0d829bd739dfcb3374971c776676bf2e53bab43c
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 19ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND; 20ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION; 21ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED; 22ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED; 23ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT; 24ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN; 25ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN; 26ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS; 27ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet 28ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.IAnimationListener; 29ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ILayoutPullParser; 30ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.IProjectCallback; 31907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohetimport com.android.ide.common.rendering.api.LayoutLog; 32ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Params; 330d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources; 34ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderSession; 35ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceDensity; 36ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ResourceValue; 37ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result; 38ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.StyleResourceValue; 39ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo; 40ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Params.RenderingMode; 410d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider; 42ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohetimport com.android.ide.common.rendering.api.Result.Status; 433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.internal.util.XmlUtils; 44ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge; 453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext; 463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeInflater; 47ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes; 483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindow; 493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindowSession; 503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser; 513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.Animator; 53ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.AnimatorInflater; 5433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohetimport android.animation.LayoutTransition; 5562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohetimport android.animation.LayoutTransition.TransitionListener; 563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate; 573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap; 583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate; 593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas; 603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.drawable.Drawable; 613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Handler; 623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.DisplayMetrics; 633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.TypedValue; 643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View; 653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.ViewGroup; 663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.AttachInfo; 673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec; 68ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohetimport android.view.ViewGroup.LayoutParams; 693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout; 703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost; 713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabWidget; 723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color; 743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D; 753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage; 763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList; 773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List; 783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map; 79ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.TimeUnit; 80ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.locks.ReentrantLock; 813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/** 83ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * Class implementing the render session. 843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 85ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * A session is a stateful representation of a layout file. It is initialized with data coming 86ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then 873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout. 883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 900d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohetpublic class RenderSessionImpl extends FrameworkResourceIdProvider { 913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final int DEFAULT_TITLE_BAR_HEIGHT = 25; 933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final int DEFAULT_STATUS_BAR_HEIGHT = 25; 943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 95ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 96ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * The current context being rendered. This is set through {@link #acquire(long)} and 97ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #init(long)}, and unset in {@link #release()}. 98ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 99ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet private static BridgeContext sCurrentContext = null; 100ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 101ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet private final Params mParams; 1023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene state 104ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet private RenderSession mScene; 1053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeContext mContext; 1063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeXmlBlockParser mBlockParser; 1073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeInflater mInflater; 1083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private int mScreenOffset; 1096a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet private ResourceValue mWindowBackground; 1103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private FrameLayout mViewRoot; 1111392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet private Canvas mCanvas; 1121392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet private int mMeasuredScreenWidth = -1; 1131392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet private int mMeasuredScreenHeight = -1; 1143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // information being returned through the API 1163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BufferedImage mImage; 1173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private ViewInfo mViewInfo; 1183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final class PostInflateException extends Exception { 1203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final long serialVersionUID = 1L; 1213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public PostInflateException(String message) { 1233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet super(message); 1243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 1283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Creates a layout scene with all the information coming from the layout bridge API. 1293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 130ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a 131ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * call to {@link RenderSessionImpl#acquire(long)} 1323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 1333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams) 1343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 135ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public RenderSessionImpl(Params params) { 1363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // copy the params. 137ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet mParams = new Params(params); 138ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 139ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 140ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 141ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Initializes and acquires the scene, creating various Android objects such as context, 142ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * inflater, and parser. 143ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 144ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @param timeout the time to wait if another rendering is happening. 145ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 146ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @return whether the scene was prepared 147ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 148ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #acquire(long) 149ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #release() 150ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 151ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result init(long timeout) { 152ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // acquire the lock. if the result is null, lock was just acquired, otherwise, return 153ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // the result. 154ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet Result result = acquireLock(timeout); 155ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (result != null) { 156ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return result; 157ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 1583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // setup the display Metrics. 1603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet DisplayMetrics metrics = new DisplayMetrics(); 1613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.densityDpi = mParams.getDensity(); 1623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT; 1633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.scaledDensity = metrics.density; 1643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.widthPixels = mParams.getScreenWidth(); 1653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.heightPixels = mParams.getScreenHeight(); 1663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.xdpi = mParams.getXdpi(); 1673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.ydpi = mParams.getYdpi(); 1683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1690d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet RenderResources resources = mParams.getResources(); 1703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // build the context 1720d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources, 173089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet mParams.getProjectCallback()); 1743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 175ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 1760d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet setUp(); 1773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the screen offset and window-background resource 1793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mWindowBackground = null; 1803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mScreenOffset = 0; 1810d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet StyleResourceValue theme = resources.getTheme(); 182089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet if (theme != null && mParams.isBgColorOverridden() == false) { 1830d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mWindowBackground = resources.findItemInTheme("windowBackground"); 1840d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mWindowBackground = resources.resolveResValue(mWindowBackground); 1853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1860d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mScreenOffset = getScreenOffset(resources, metrics); 1873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // build the inflater and parser. 1903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mInflater = new BridgeInflater(mContext, mParams.getProjectCallback()); 1913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.setBridgeInflater(mInflater); 1923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mInflater.setFactory2(mContext); 1933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(), 1953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext, false /* platformResourceFlag */); 196ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 197ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 1983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 201ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Prepares the scene for action. 202ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * <p> 203ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * This call is blocking if another rendering/inflating is currently happening, and will return 204ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * whether the preparation worked. 205ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 206ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * The preparation can fail if another rendering took too long and the timeout was elapsed. 207ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 208ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * More than one call to this from the same thread will have no effect and will return 209ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * {@link Result#SUCCESS}. 210ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 211ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * After scene actions have taken place, only one call to {@link #release()} must be 212ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * done. 213ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 214ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @param timeout the time to wait if another rendering is happening. 215ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 216ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @return whether the scene was prepared 217ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 218ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #release() 219ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 220ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if {@link #init(long)} was never called. 221ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 222ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result acquire(long timeout) { 223ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (mContext == null) { 224ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("After scene creation, #init() must be called"); 225ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 226ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 227ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // acquire the lock. if the result is null, lock was just acquired, otherwise, return 228ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // the result. 229ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet Result result = acquireLock(timeout); 230ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (result != null) { 231ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return result; 232ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 2333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2340d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet setUp(); 235ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 2363054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet return SUCCESS.createResult(); 2373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 240ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Acquire the lock so that the scene can be acted upon. 2413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 242ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * This returns null if the lock was just acquired, otherwise it returns 243ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * {@link Result#SUCCESS} if the lock already belonged to that thread, or another 244ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * instance (see {@link Result#getStatus()}) if an error occurred. 245ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 246ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @param timeout the time to wait if another rendering is happening. 247ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @return null if the lock was just acquire or another result depending on the state. 248ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 249ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 250ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene. 2513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 252ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet private Result acquireLock(long timeout) { 253ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet ReentrantLock lock = Bridge.getLock(); 254ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (lock.isHeldByCurrentThread() == false) { 255ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet try { 256ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS); 257ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 258ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (acquired == false) { 2593054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet return ERROR_TIMEOUT.createResult(); 260ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 261ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } catch (InterruptedException e) { 2623054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet return ERROR_LOCK_INTERRUPTED.createResult(); 263ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 264ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } else { 265ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // This thread holds the lock already. Checks that this wasn't for a different context. 266ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // If this is called by init, mContext will be null and so should sCurrentContext 267ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // anyway 268ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (mContext != sCurrentContext) { 269ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("Acquiring different scenes from same thread without releases"); 270ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 2713054fe698a6be732e24128541a1db867ec606a59Xavier Ducrohet return SUCCESS.createResult(); 272ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 2733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 274ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return null; 275ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 276ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 277ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 278ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Cleans up the scene after an action. 279ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 280ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet public void release() { 281ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet ReentrantLock lock = Bridge.getLock(); 282ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 283ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // with the use of finally blocks, it is possible to find ourself calling this 284ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // without a successful call to prepareScene. This test makes sure that unlock() will 285ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // not throw IllegalMonitorStateException. 286ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (lock.isHeldByCurrentThread()) { 2870d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet tearDown(); 288ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet lock.unlock(); 289ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 2903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 2930d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet * Sets up the session for rendering. 2940d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet * <p/> 2950d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet * The counterpart is {@link #tearDown()}. 2960d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet */ 2970d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet private void setUp() { 2980d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet // make sure the Resources object references the context (and other objects) for this 2990d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet // scene 3000d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mContext.initResources(); 3010d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet sCurrentContext = mContext; 3020d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet 3030d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet LayoutLog currentLog = mParams.getLog(); 3040d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet Bridge.setLog(currentLog); 3050d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mContext.getRenderResources().setFrameworkResourceIdProvider(this); 3060d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mContext.getRenderResources().setLogger(currentLog); 3070d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet } 3080d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet 3090d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet /** 3100d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet * Tear down the session after rendering. 3110d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet * <p/> 3120d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet * The counterpart is {@link #setUp()}. 3130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet */ 3140d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet private void tearDown() { 3150d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet // Make sure to remove static references, otherwise we could not unload the lib 3160d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mContext.disposeResources(); 3170d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet sCurrentContext = null; 3180d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet 3190d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet Bridge.setLog(null); 3200d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mContext.getRenderResources().setFrameworkResourceIdProvider(null); 3210d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet mContext.getRenderResources().setLogger(null); 3220d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet 3230d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet } 3240d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet 3250d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet /** 3263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Inflates the layout. 3273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 328ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 329ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 330ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 331ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #init(long)} was not called. 3323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 333ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result inflate() { 334ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 335ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 3363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 3373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot = new FrameLayout(mContext); 3393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Sets the project callback (custom view loader) to the fragment delegate so that 3413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // it can instantiate the custom Fragment. 3423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Fragment_Delegate.setProjectCallback(mParams.getProjectCallback()); 3433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View view = mInflater.inflate(mBlockParser, mViewRoot); 3453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // post-inflate process. For now this supports TabHost/TabWidget 3473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet postInflateProcess(view, mParams.getProjectCallback()); 3483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Fragment_Delegate.setProjectCallback(null); 3503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // set the AttachInfo on the root view. 3523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(), 3533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet new Handler(), null); 3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mHasWindowFocus = true; 3553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mWindowVisibility = View.VISIBLE; 3563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mInTouchMode = false; // this is so that we can display selections. 35790f9956c17660c35ee6fe934815c16e97bf0d3f8Xavier Ducrohet info.mHardwareAccelerated = false; 3583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.dispatchAttachedToWindow(info, 0); 3593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the background drawable 3613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mWindowBackground != null) { 3623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Drawable d = ResourceHelper.getDrawable(mWindowBackground, 3633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext, true /* isFramework */); 3643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.setBackgroundDrawable(d); 3653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 367ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 3683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (PostInflateException e) { 369ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_INFLATION.createResult(e.getMessage(), e); 3703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 3713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 3723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 3733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 3743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 3753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 377ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_INFLATION.createResult(t.getMessage(), t); 3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 3823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Renders the scene. 3833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 384ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 385ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 386ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 387ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 3881392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet * 3891392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet * @see SceneParams#getRenderingMode() 39033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @see LayoutScene#render(long) 3913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 392ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result render() { 393ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 394ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 3953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 3963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mViewRoot == null) { 397ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_NOT_INFLATED.createResult(); 3983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // measure the views 4003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int w_spec, h_spec; 4013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 402e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet RenderingMode renderingMode = mParams.getRenderingMode(); 403e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet 4041392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet // only do the screen measure when needed. 4051392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet boolean newRenderSize = false; 4061392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (mMeasuredScreenWidth == -1) { 4071392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet newRenderSize = true; 4081392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mMeasuredScreenWidth = mParams.getScreenWidth(); 4091392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mMeasuredScreenHeight = mParams.getScreenHeight(); 4101392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet 4111392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (renderingMode != RenderingMode.NORMAL) { 4121392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet // measure the full size needed by the layout. 4131392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, 4141392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet renderingMode.isHorizExpand() ? 4151392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet MeasureSpec.UNSPECIFIED // this lets us know the actual needed size 4161392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet : MeasureSpec.EXACTLY); 4171392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight - mScreenOffset, 4181392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet renderingMode.isVertExpand() ? 4191392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet MeasureSpec.UNSPECIFIED // this lets us know the actual needed size 4201392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet : MeasureSpec.EXACTLY); 4211392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mViewRoot.measure(w_spec, h_spec); 4221392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet 4231392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (renderingMode.isHorizExpand()) { 4241392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth(); 4251392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (neededWidth > mMeasuredScreenWidth) { 4261392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mMeasuredScreenWidth = neededWidth; 4271392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 428e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet } 4293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4301392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (renderingMode.isVertExpand()) { 4311392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight(); 4321392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (neededHeight > mMeasuredScreenHeight - mScreenOffset) { 4331392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mMeasuredScreenHeight = neededHeight + mScreenOffset; 4341392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 435e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet } 4363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // remeasure with the size we need 4403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // This must always be done before the call to layout 4411392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, MeasureSpec.EXACTLY); 4421392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight - mScreenOffset, 4433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet MeasureSpec.EXACTLY); 4443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.measure(w_spec, h_spec); 4453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now do the layout. 4471392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mViewRoot.layout(0, mScreenOffset, mMeasuredScreenWidth, mMeasuredScreenHeight); 4483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // draw the views 4503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // create the BufferedImage into which the layout will be rendered. 4511392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (newRenderSize || mCanvas == null) { 4521392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet if (mParams.getImageFactory() != null) { 4531392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mImage = mParams.getImageFactory().getImage(mMeasuredScreenWidth, 4541392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mMeasuredScreenHeight - mScreenOffset); 4551392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } else { 4561392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mImage = new BufferedImage(mMeasuredScreenWidth, 4571392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mMeasuredScreenHeight - mScreenOffset, BufferedImage.TYPE_INT_ARGB); 4581392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 4593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 460ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet if (mParams.isBgColorOverridden()) { 4611392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet Graphics2D gc = mImage.createGraphics(); 462ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet gc.setColor(new Color(mParams.getOverrideBgColor(), true)); 4631392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight - mScreenOffset); 4641392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet gc.dispose(); 4651392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4671392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet // create an Android bitmap around the BufferedImage 4681392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage, 4691392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet true /*isMutable*/, 4706a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet ResourceDensity.getEnum(mParams.getDensity())); 4713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4721392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet // create a Canvas around the Android bitmap 4731392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mCanvas = new Canvas(bitmap); 4741392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mCanvas.setDensity(mParams.getDensity()); 4751392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 4763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4771392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mViewRoot.draw(mCanvas); 4781392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet 4793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext); 4803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // success! 482ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 4833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 4843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 4853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 4863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 4873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 4883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 490ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_UNKNOWN.createResult(t.getMessage(), t); 4913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 495ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Animate an object 496ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * <p> 497ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 498ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 499ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 500ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 50133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 50233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @see LayoutScene#animate(Object, String, boolean, IAnimationListener) 503ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 504ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result animate(Object targetObject, String animationName, 505ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet boolean isFrameworkAnimation, IAnimationListener listener) { 506ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 507ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 508ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // find the animation file. 5096a5b91fceb1913cab6416bef99d7b28530d16ecfXavier Ducrohet ResourceValue animationResource = null; 510ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet int animationId = 0; 511ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (isFrameworkAnimation) { 5120d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet animationResource = mContext.getRenderResources().getFrameworkResource( 5130d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet RenderResources.RES_ANIMATOR, animationName); 514ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (animationResource != null) { 5150d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet animationId = Bridge.getResourceValue(RenderResources.RES_ANIMATOR, 516551346323dace2bdb2509a7f5c9a0a200794b29cXavier Ducrohet animationName); 517ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 518ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } else { 5190d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet animationResource = mContext.getRenderResources().getProjectResource( 5200d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet RenderResources.RES_ANIMATOR, animationName); 521ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (animationResource != null) { 522551346323dace2bdb2509a7f5c9a0a200794b29cXavier Ducrohet animationId = mContext.getProjectCallback().getResourceValue( 5230d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet RenderResources.RES_ANIMATOR, animationName); 524ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 525ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 526ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 527ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (animationResource != null) { 528ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet try { 52933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet Animator anim = AnimatorInflater.loadAnimator(mContext, animationId); 530ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (anim != null) { 531ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet anim.setTarget(targetObject); 532ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 53333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet new PlayAnimationThread(anim, this, animationName, listener).start(); 534ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 535ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 536ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 537ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } catch (Exception e) { 538b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet // get the real cause of the exception. 539b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet Throwable t = e; 540b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet while (t.getCause() != null) { 541b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet t = t.getCause(); 542b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 543b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 544ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_UNKNOWN.createResult(t.getMessage(), t); 545ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 546ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 547ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 548ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_ANIM_NOT_FOUND.createResult(); 549b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 550b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 55133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet /** 55233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * Insert a new child into an existing parent. 55333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * <p> 55433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 55533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 55633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 55733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 55833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 559ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * @see LayoutScene#insertChild(Object, ILayoutPullParser, int, IAnimationListener) 56033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet */ 561ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml, 56233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet final int index, IAnimationListener listener) { 563b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet checkLock(); 564b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 565b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet // create a block parser for the XML 566b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext, 567b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet false /* platformResourceFlag */); 568b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 569b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet // inflate the child without adding it to the root since we want to control where it'll 570b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet // get added. We do pass the parentView however to ensure that the layoutParams will 571b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet // be created correctly. 57233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); 573b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 57433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet invalidateRenderingSize(); 57533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 57633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet if (listener != null) { 57733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet new AnimationThread(this, "insertChild", listener) { 57833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 57933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet @Override 580ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result preAnimation() { 58133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet parentView.setLayoutTransition(new LayoutTransition()); 58233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet return addView(parentView, child, index); 58333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 58433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 58533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet @Override 58633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet public void postAnimation() { 58733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet parentView.setLayoutTransition(null); 58833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 58933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet }.start(); 59033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 59133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet // always return success since the real status will come through the listener. 592ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(child); 5931392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 5941392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet 59533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet // add it to the parentView in the correct location 596ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet Result result = addView(parentView, child, index); 59733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet if (result.isSuccess() == false) { 59833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet return result; 59933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 600b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 60133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet result = render(); 6021766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet if (result.isSuccess()) { 60333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet result = result.getCopyWithData(child); 6041766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet } 6051766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet 6061766c77e7e79afbb4fd2611837ac487f5610d71dXavier Ducrohet return result; 607b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 608b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 60933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet /** 61033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * Adds a given view to a given parent at a given index. 61133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 61233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @param parent the parent to receive the view 61333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @param view the view to add to the parent 61433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @param index the index where to do the add. 61533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 616ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * @return a Result with {@link Status#SUCCESS} or 617ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support 61833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * adding views. 61933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet */ 620ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet private Result addView(ViewGroup parent, View view, int index) { 62133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet try { 62233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet parent.addView(view, index); 623ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 62433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } catch (UnsupportedOperationException e) { 62533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet // looks like this is a view class that doesn't support children manipulation! 626ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_VIEWGROUP_NO_CHILDREN.createResult(); 62733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 62833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 62933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 63033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet /** 63133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * Moves a view to a new parent at a given location 63233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * <p> 63333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 63433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 63533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 63633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 63733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 63833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener) 63933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet */ 64062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet public Result moveChild(final ViewGroup newParentView, final View childView, final int index, 64124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet Map<String, String> layoutParamsMap, final IAnimationListener listener) { 642b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet checkLock(); 643b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 64433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet invalidateRenderingSize(); 64533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 646ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet LayoutParams layoutParams = null; 64733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet if (layoutParamsMap != null) { 64833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet // need to create a new LayoutParams object for the new parent. 64962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet layoutParams = newParentView.generateLayoutParams( 65033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet new BridgeLayoutParamsMapAttributes(layoutParamsMap)); 65133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 6521392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet 65362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // get the current parent of the view that needs to be moved. 65462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet final ViewGroup previousParent = (ViewGroup) childView.getParent(); 65562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet 65633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet if (listener != null) { 65733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet final LayoutParams params = layoutParams; 658ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet 65924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // there is no support for animating views across layouts, so in case the new and old 66024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // parent views are different we fake the animation through a no animation thread. 66124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (previousParent != newParentView) { 66224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet new Thread("not animated moveChild") { 66324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet @Override 66424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet public void run() { 66524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet Result result = moveView(previousParent, newParentView, childView, index, 66624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet params); 66724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (result.isSuccess() == false) { 66824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet listener.done(result); 66924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 67024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 67124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // ready to do the work, acquire the scene. 67224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet result = acquire(250); 67324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (result.isSuccess() == false) { 67424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet listener.done(result); 67524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet return; 67624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 67724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 67824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet try { 67924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet result = render(); 68024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (result.isSuccess()) { 68124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet listener.onNewFrame(RenderSessionImpl.this.getSession()); 68224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 68324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } finally { 68424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet release(); 68524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 68624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 68724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet listener.done(result); 68862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } 68924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet }.start(); 69024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } else { 69124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet new AnimationThread(this, "moveChild", listener) { 69262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet 69324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet @Override 69424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet public Result preAnimation() { 69524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // set up the transition for the parent. 69624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet LayoutTransition transition = new LayoutTransition(); 69724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet previousParent.setLayoutTransition(transition); 6985562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet 69924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // tweak the animation durations and start delays (to match the duration of 70024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // animation playing just before). 70124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // Note: Cannot user Animation.setDuration() directly. Have to set it 70224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // on the LayoutTransition. 70324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet transition.setDuration(LayoutTransition.DISAPPEARING, 100); 70424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // CHANGE_DISAPPEARING plays after DISAPPEARING 70524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100); 706ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet 70724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100); 70824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 70924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100); 71024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet // CHANGE_APPEARING plays after CHANGE_APPEARING 71124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet transition.setStartDelay(LayoutTransition.APPEARING, 100); 71224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 71324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet transition.setDuration(LayoutTransition.APPEARING, 100); 71424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 71524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet return moveView(previousParent, newParentView, childView, index, params); 71624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 71724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 71824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet @Override 71924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet public void postAnimation() { 72024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet previousParent.setLayoutTransition(null); 72124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet newParentView.setLayoutTransition(null); 72224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 72324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet }.start(); 72424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 72533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 72633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet // always return success since the real status will come through the listener. 727ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(layoutParams); 728b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 729b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 73062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet Result result = moveView(previousParent, newParentView, childView, index, layoutParams); 73133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet if (result.isSuccess() == false) { 73233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet return result; 73333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 734b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 73533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet result = render(); 736ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet if (layoutParams != null && result.isSuccess()) { 73733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet result = result.getCopyWithData(layoutParams); 738ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet } 739ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet 740ce63b05275ddd2acd9d2f39e9ab3cb3039f26677Xavier Ducrohet return result; 741b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 742b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 74333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet /** 74433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * Moves a View from its current parent to a new given parent at a new given location, with 74533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * an optional new {@link LayoutParams} instance 74633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 74762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet * @param previousParent the previous parent, still owning the child at the time of the call. 74862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet * @param newParent the new parent 74924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet * @param movedView the view to move 75033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @param index the new location in the new parent 75133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @param params an option (can be null) {@link LayoutParams} instance. 75233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 753ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * @return a Result with {@link Status#SUCCESS} or 754ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support 75533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * adding views. 75633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet */ 75724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet private Result moveView(ViewGroup previousParent, final ViewGroup newParent, 75824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet final View movedView, final int index, final LayoutParams params) { 7591392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet try { 76062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // check if there is a transition on the previousParent. 76124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet LayoutTransition previousTransition = previousParent.getLayoutTransition(); 76224cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (previousTransition != null) { 7635562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // in this case there is an animation. This means we have to wait for the child's 7645562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // parent reference to be null'ed out so that we can add it to the new parent. 7655562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // It is technically removed right before the DISAPPEARING animation is done (if 7665562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // the animation of this type is not null, otherwise it's after which is impossible 7675562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // to handle). 7685562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // Because there is no move animation, if the new parent is the same as the old 7695562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before 7705562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // adding the child or the child will appear in its new location before the 7715562208aafcaccf366dd8cd906700f48c6c342a8Xavier Ducrohet // other children have made room for it. 77262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet 77362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // add a listener to the transition to be notified of the actual removal. 77424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet previousTransition.addTransitionListener(new TransitionListener() { 77524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet private int mChangeDisappearingCount = 0; 77662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet 77762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet public void startTransition(LayoutTransition transition, ViewGroup container, 77862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet View view, int transitionType) { 77924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) { 78024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet mChangeDisappearingCount++; 78124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 78262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } 78333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 78462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet public void endTransition(LayoutTransition transition, ViewGroup container, 78562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet View view, int transitionType) { 78624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) { 78724cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet mChangeDisappearingCount--; 78824cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet } 78924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet 79024cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet if (transitionType == LayoutTransition.CHANGE_DISAPPEARING && 79124cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet mChangeDisappearingCount == 0) { 79262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // add it to the parentView in the correct location 79362039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet if (params != null) { 79424cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet newParent.addView(movedView, index, params); 79562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } else { 79624cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet newParent.addView(movedView, index); 79762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } 79862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } 79962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } 80062039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet }); 80162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet 80262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // remove the view from the current parent. 80324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet previousParent.removeView(movedView); 80462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet 80562039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // and return since adding the view to the new parent is done in the listener. 80662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet return SUCCESS.createResult(); 80733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } else { 80862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // standard code with no animation. pretty simple. 80924cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet previousParent.removeView(movedView); 81033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 81162039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet // add it to the parentView in the correct location 81262039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet if (params != null) { 81324cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet newParent.addView(movedView, index, params); 81462039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } else { 81524cdf6c407351a157880a0a1bbf65c95af753418Xavier Ducrohet newParent.addView(movedView, index); 81662039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } 81762039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet 81862039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet return SUCCESS.createResult(); 81962039873060d26a7be141573b0f468c5ba0414dcXavier Ducrohet } 8201392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } catch (UnsupportedOperationException e) { 8211392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet // looks like this is a view class that doesn't support children manipulation! 822ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_VIEWGROUP_NO_CHILDREN.createResult(); 823b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 82433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 82533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 82633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet /** 82733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * Removes a child from its current parent. 82833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * <p> 82933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 83033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 83133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 83233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 83333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 83433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @see LayoutScene#removeChild(Object, IAnimationListener) 83533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet */ 836ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result removeChild(final View childView, IAnimationListener listener) { 83733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet checkLock(); 838b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 8391392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet invalidateRenderingSize(); 8401392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet 84133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet final ViewGroup parent = (ViewGroup) childView.getParent(); 84233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 84333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet if (listener != null) { 84433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet new AnimationThread(this, "moveChild", listener) { 84533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 84633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet @Override 847ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Result preAnimation() { 84833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet parent.setLayoutTransition(new LayoutTransition()); 84933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet return removeView(parent, childView); 85033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 85133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 85233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet @Override 85333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet public void postAnimation() { 85433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet parent.setLayoutTransition(null); 85533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 85633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet }.start(); 85733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 85833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet // always return success since the real status will come through the listener. 859ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 86033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 86133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 862ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet Result result = removeView(parent, childView); 86333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet if (result.isSuccess() == false) { 86433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet return result; 86533840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 86633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 867b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet return render(); 868ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 869ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 870ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 87133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * Removes a given view from its current parent. 87233840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 87333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * @param view the view to remove from its parent 87433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * 875ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * @return a Result with {@link Status#SUCCESS} or 876ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet * {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support 87733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet * adding views. 87833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet */ 879ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet private Result removeView(ViewGroup parent, View view) { 88033840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet try { 88133840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet parent.removeView(view); 882ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return SUCCESS.createResult(); 88333840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } catch (UnsupportedOperationException e) { 88433840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet // looks like this is a view class that doesn't support children manipulation! 885ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet return ERROR_VIEWGROUP_NO_CHILDREN.createResult(); 88633840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 88733840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet } 88833840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet 88933840c00b3b56db9613dcd33abd69601b711ce69Xavier Ducrohet /** 890907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet * Returns the log associated with the session. 891907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet * @return the log or null if there are none. 892907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet */ 893907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet public LayoutLog getLog() { 894907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet if (mParams != null) { 895907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet return mParams.getLog(); 896907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet } 897907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet 898907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet return null; 899907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet } 900907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet 901907c716cce7b8fa785d9005081d25d3ecc2d5365Xavier Ducrohet /** 902ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Checks that the lock is owned by the current thread and that the current context is the one 903ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * from this scene. 904ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 905ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 906ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 907ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 908ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet private void checkLock() { 909ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet ReentrantLock lock = Bridge.getLock(); 910ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (lock.isHeldByCurrentThread() == false) { 911ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("scene must be acquired first. see #acquire(long)"); 912ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 913ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (sCurrentContext != mContext) { 914ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("Thread acquired a scene but is rendering a different one"); 915ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 916ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 917ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 9183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 9193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Returns the top screen offset. This depends on whether the current theme defines the user 9203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * of the title and status bars. 921089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet * @param resolver The {@link ResourceResolver} 922089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet * @param metrics The display metrics 9233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @return the pixel height offset 9243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 9250d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet private int getScreenOffset(RenderResources resolver, DisplayMetrics metrics) { 9263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int offset = 0; 9273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the title bar flag from the current theme. 929089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet ResourceValue value = resolver.findItemInTheme("windowNoTitle"); 9303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // because it may reference something else, we resolve it. 932089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet value = resolver.resolveResValue(value); 9333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // if there's a value and it's true (default is false) 9353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value == null || value.getValue() == null || 9363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) { 9373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // default size of the window title bar 9383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT; 9393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get value from the theme. 941089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet value = resolver.findItemInTheme("windowTitleSize"); 9423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // resolve it 944089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet value = resolver.resolveResValue(value); 9453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value != null) { 9473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the numerical value, if available 9483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet TypedValue typedValue = ResourceHelper.getValue(value.getValue()); 9493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (typedValue != null) { 9503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the pixel value based on the display metrics 951089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet defaultOffset = (int)typedValue.getDimension(metrics); 9523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet offset += defaultOffset; 9563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the fullscreen flag from the current theme. 959089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet value = resolver.findItemInTheme("windowFullscreen"); 9603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // because it may reference something else, we resolve it. 962089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet value = resolver.resolveResValue(value); 9633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value == null || value.getValue() == null || 9653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) { 9663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // default value 9683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT; 9693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 970089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet // get the real value 9710d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet value = resolver.getFrameworkResource(RenderResources.RES_DIMEN, "status_bar_height"); 9723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value != null) { 9733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet TypedValue typedValue = ResourceHelper.getValue(value.getValue()); 9743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (typedValue != null) { 9753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the pixel value based on the display metrics 976089143ffed72bb47fd8d870f29caffb646138781Xavier Ducrohet defaultOffset = (int)typedValue.getDimension(metrics); 9773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // add the computed offset. 9813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet offset += defaultOffset; 9823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return offset; 9853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 9883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Post process on a view hierachy that was just inflated. 9893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the 9903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically 9913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * based on the content of the {@link FrameLayout}. 9923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param view the root view to process. 9933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param projectCallback callback to the project. 9943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 9953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void postInflateProcess(View view, IProjectCallback projectCallback) 9963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 9973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view instanceof TabHost) { 9983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet setupTabHost((TabHost)view, projectCallback); 9993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else if (view instanceof ViewGroup) { 10003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewGroup group = (ViewGroup)view; 10013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = group.getChildCount(); 10023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int c = 0 ; c < count ; c++) { 10033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View child = group.getChildAt(c); 10043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet postInflateProcess(child, projectCallback); 10053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 10103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Sets up a {@link TabHost} object. 10113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param tabHost the TabHost to setup. 10123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param projectCallback The project callback object to access the project R class. 10133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @throws PostInflateException 10143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 10153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback) 10163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 10173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // look for the TabWidget, and the FrameLayout. They have their own specific names 10183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View v = tabHost.findViewById(android.R.id.tabs); 10193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 10213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 10223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n"); 10233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if ((v instanceof TabWidget) == false) { 10263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 10273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n" + 10283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName())); 10293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet v = tabHost.findViewById(android.R.id.tabcontent); 10323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 10343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty) 10353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 10363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\"."); 10373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if ((v instanceof FrameLayout) == false) { 10403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 10413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" + 10423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName())); 10433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet FrameLayout content = (FrameLayout)v; 10463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now process the content of the framelayout and dynamically create tabs for it. 10483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = content.getChildCount(); 10493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (count == 0) { 10513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 10523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "The FrameLayout for the TabHost has no content. Rendering failed.\n"); 10533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // this must be called before addTab() so that the TabHost searches its TabWidget 10563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // and FrameLayout. 10573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet tabHost.setup(); 10583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // for each child of the framelayout, add a new TabSpec 10603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int i = 0 ; i < count ; i++) { 10613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View child = content.getChildAt(i); 10623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String tabSpec = String.format("tab_spec%d", i+1); 10633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int id = child.getId(); 10643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String[] resource = projectCallback.resolveResourceValue(id); 10653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String name; 10663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (resource != null) { 10673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = resource[0]; // 0 is resource name, 1 is resource type. 10683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else { 10693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = String.format("Tab %d", i+1); // default name if id is unresolved. 10703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id)); 10723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 10773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Visits a View and its children and generate a {@link ViewInfo} containing the 10783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * bounds of all the views. 10793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param view the root View 10803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param context the context. 10813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 10823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private ViewInfo visit(View view, BridgeContext context) { 10833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view == null) { 10843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 10853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewInfo result = new ViewInfo(view.getClass().getName(), 10883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet context.getViewKey(view), 10892d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), 10902d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet view, view.getLayoutParams()); 10913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 10923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view instanceof ViewGroup) { 10933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewGroup group = ((ViewGroup) view); 10943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet List<ViewInfo> children = new ArrayList<ViewInfo>(); 10953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int i = 0; i < group.getChildCount(); i++) { 10963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet children.add(visit(group.getChildAt(i), context)); 10973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 10983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet result.setChildren(children); 10993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 11003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 11013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return result; 11023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 11033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 11041392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet private void invalidateRenderingSize() { 11051392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet mMeasuredScreenWidth = mMeasuredScreenHeight = -1; 11061392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet } 11071392615c49943383baf51262e2df6975266b4c2fXavier Ducrohet 11083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public BufferedImage getImage() { 11093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return mImage; 11103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 11113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 11123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public ViewInfo getViewInfo() { 11133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return mViewInfo; 11143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 11152d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet 1116ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public Map<String, String> getDefaultProperties(Object viewObject) { 11172d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet return mContext.getDefaultPropMap(viewObject); 11182d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet } 1119b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 1120ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public void setScene(RenderSession session) { 1121ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet mScene = session; 1122b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 1123b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet 1124ecb67b629266bd616da571c1e391164a4f8c8e93Xavier Ducrohet public RenderSession getSession() { 1125b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet return mScene; 1126b12b63f973ebf8fdc4f36f77dd29bd1bed436609Xavier Ducrohet } 11270d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet 11280d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet // --- FrameworkResourceIdProvider methods 11290d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet 11300d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet @Override 11310d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet public Integer getId(String resType, String resName) { 11320d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet return Bridge.getResourceValue(resType, resName); 11330d829bd739dfcb3374971c776676bf2e53bab43cXavier Ducrohet } 11343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet} 1135