RenderSessionImpl.java revision ddea50d03cdda807bbaea54beffd7a341c51f770
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 19ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport static com.android.layoutlib.api.SceneResult.SceneStatus.ERROR_LOCK_INTERRUPTED; 20ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport static com.android.layoutlib.api.SceneResult.SceneStatus.ERROR_TIMEOUT; 21ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport static com.android.layoutlib.api.SceneResult.SceneStatus.SUCCESS; 22ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.internal.util.XmlUtils; 243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IProjectCallback; 253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IResourceValue; 263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IStyleResourceValue; 273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.LayoutBridge; 283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.SceneParams; 293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.SceneResult; 303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.ViewInfo; 313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IDensityBasedResourceValue.Density; 32ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.api.LayoutScene.IAnimationListener; 33e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohetimport com.android.layoutlib.api.SceneParams.RenderingMode; 34ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge; 353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.BridgeConstants; 363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext; 373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeInflater; 383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindow; 393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindowSession; 403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser; 413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 42ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.AnimatorInflater; 43ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport android.animation.ObjectAnimator; 443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate; 453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap; 463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate; 473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas; 483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas_Delegate; 493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.drawable.Drawable; 503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Handler; 513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Looper; 523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.DisplayMetrics; 533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.TypedValue; 543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View; 553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.ViewGroup; 563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.AttachInfo; 573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec; 583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout; 593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost; 603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabWidget; 613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color; 633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D; 643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage; 653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList; 663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Collection; 673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.HashMap; 683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List; 693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map; 70ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.TimeUnit; 71ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohetimport java.util.concurrent.locks.ReentrantLock; 723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/** 743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Class managing a layout "scene". 753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * A scene is a stateful representation of a layout file. It is initialized with data coming through 773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * the {@link LayoutBridge} API to inflate the layout. Further actions and rendering can then 783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout. 793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetpublic class LayoutSceneImpl { 823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final int DEFAULT_TITLE_BAR_HEIGHT = 25; 843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final int DEFAULT_STATUS_BAR_HEIGHT = 25; 853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 86ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 87ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * The current context being rendered. This is set through {@link #acquire(long)} and 88ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #init(long)}, and unset in {@link #release()}. 89ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 90ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet private static BridgeContext sCurrentContext = null; 91ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private final SceneParams mParams; 933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene state 953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeContext mContext; 963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeXmlBlockParser mBlockParser; 973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeInflater mInflater; 983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IStyleResourceValue mCurrentTheme; 993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private int mScreenOffset; 1003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IResourceValue mWindowBackground; 1013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private FrameLayout mViewRoot; 1023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // information being returned through the API 1043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BufferedImage mImage; 1053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private ViewInfo mViewInfo; 1063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final class PostInflateException extends Exception { 1083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final long serialVersionUID = 1L; 1093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public PostInflateException(String message) { 1113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet super(message); 1123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 1163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Creates a layout scene with all the information coming from the layout bridge API. 1173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 118ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * This <b>must</b> be followed by a call to {@link LayoutSceneImpl#init()}, which act as a 119ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * call to {@link LayoutSceneImpl#acquire(long)} 1203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 1213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams) 1223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 1233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public LayoutSceneImpl(SceneParams params) { 1243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // copy the params. 1253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams = new SceneParams(params); 126ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 127ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 128ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 129ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Initializes and acquires the scene, creating various Android objects such as context, 130ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * inflater, and parser. 131ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 132ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @param timeout the time to wait if another rendering is happening. 133ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 134ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @return whether the scene was prepared 135ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 136ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #acquire(long) 137ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #release() 138ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 139ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet public SceneResult init(long timeout) { 140ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // acquire the lock. if the result is null, lock was just acquired, otherwise, return 141ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // the result. 142ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet SceneResult result = acquireLock(timeout); 143ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (result != null) { 144ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return result; 145ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 1463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // setup the display Metrics. 1483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet DisplayMetrics metrics = new DisplayMetrics(); 1493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.densityDpi = mParams.getDensity(); 1503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT; 1513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.scaledDensity = metrics.density; 1523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.widthPixels = mParams.getScreenWidth(); 1533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.heightPixels = mParams.getScreenHeight(); 1543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.xdpi = mParams.getXdpi(); 1553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.ydpi = mParams.getYdpi(); 1563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // find the current theme and compute the style inheritance map 1583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<IStyleResourceValue, IStyleResourceValue> styleParentMap = 1593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet new HashMap<IStyleResourceValue, IStyleResourceValue>(); 1603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mCurrentTheme = computeStyleMaps(mParams.getThemeName(), mParams.getIsProjectTheme(), 1623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getProjectResources().get(BridgeConstants.RES_STYLE), 1633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getFrameworkResources().get(BridgeConstants.RES_STYLE), styleParentMap); 1643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // build the context 1663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext = new BridgeContext(mParams.getProjectKey(), metrics, mCurrentTheme, 1673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getProjectResources(), mParams.getFrameworkResources(), 1683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet styleParentMap, mParams.getProjectCallback(), mParams.getLogger()); 1693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 170ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // set the current rendering context 171ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet sCurrentContext = mContext; 172ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 1733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // make sure the Resources object references the context (and other objects) for this 1743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene 1753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.initResources(); 1763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the screen offset and window-background resource 1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mWindowBackground = null; 1793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mScreenOffset = 0; 1803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mCurrentTheme != null && mParams.isCustomBackgroundEnabled() == false) { 1813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground"); 1823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mWindowBackground = mContext.resolveResValue(mWindowBackground); 1833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 184ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme, 185ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet mContext); 1863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // build the inflater and parser. 1893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mInflater = new BridgeInflater(mContext, mParams.getProjectCallback()); 1903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.setBridgeInflater(mInflater); 1913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mInflater.setFactory2(mContext); 1923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(), 1943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext, false /* platformResourceFlag */); 195ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 196ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return SceneResult.SUCCESS; 1973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 200ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Prepares the current thread for rendering. 201ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 202ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Note that while this can be called several time, the first call to {@link #cleanupThread()} 203ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * will do the clean-up, and make the thread unable to do further scene actions. 2043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 205ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet public void prepareThread() { 2063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // we need to make sure the Looper has been initialized for this thread. 2073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // this is required for View that creates Handler objects. 2083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (Looper.myLooper() == null) { 2093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Looper.prepare(); 2103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 211ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 212ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 213ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 214ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Cleans up thread-specific data. After this, the thread cannot be used for scene actions. 215ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * <p> 216ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Note that it doesn't matter how many times {@link #prepareThread()} was called, a single 217ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * call to this will prevent the thread from doing further scene actions 218ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 219ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet public void cleanupThread() { 220ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // clean up the looper 221ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet Looper.sThreadLocal.remove(); 222ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 223ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 224ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 225ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Prepares the scene for action. 226ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * <p> 227ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * This call is blocking if another rendering/inflating is currently happening, and will return 228ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * whether the preparation worked. 229ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 230ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * The preparation can fail if another rendering took too long and the timeout was elapsed. 231ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 232ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * More than one call to this from the same thread will have no effect and will return 233ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link SceneResult#SUCCESS}. 234ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 235ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * After scene actions have taken place, only one call to {@link #release()} must be 236ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * done. 237ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 238ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @param timeout the time to wait if another rendering is happening. 239ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 240ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @return whether the scene was prepared 241ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 242ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @see #release() 243ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 244ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if {@link #init(long)} was never called. 245ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 246ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet public SceneResult acquire(long timeout) { 247ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (mContext == null) { 248ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("After scene creation, #init() must be called"); 249ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 250ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 251ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // acquire the lock. if the result is null, lock was just acquired, otherwise, return 252ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // the result. 253ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet SceneResult result = acquireLock(timeout); 254ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (result != null) { 255ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return result; 256ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 2573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // make sure the Resources object references the context (and other objects) for this 2593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene 2603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.initResources(); 261ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet sCurrentContext = mContext; 262ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 263ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return SUCCESS.getResult(); 2643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 267ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Acquire the lock so that the scene can be acted upon. 2683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 269ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * This returns null if the lock was just acquired, otherwise it returns 270ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link SceneResult#SUCCESS} if the lock already belonged to that thread, or another 271ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * instance (see {@link SceneResult#getStatus()}) if an error occurred. 272ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 273ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @param timeout the time to wait if another rendering is happening. 274ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @return null if the lock was just acquire or another result depending on the state. 275ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 276ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 277ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene. 2783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 279ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet private SceneResult acquireLock(long timeout) { 280ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet ReentrantLock lock = Bridge.getLock(); 281ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (lock.isHeldByCurrentThread() == false) { 282ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet try { 283ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS); 284ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 285ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (acquired == false) { 286ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return ERROR_TIMEOUT.getResult(); 287ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 288ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } catch (InterruptedException e) { 289ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return ERROR_LOCK_INTERRUPTED.getResult(); 290ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 291ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } else { 292ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // This thread holds the lock already. Checks that this wasn't for a different context. 293ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // If this is called by init, mContext will be null and so should sCurrentContext 294ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // anyway 295ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (mContext != sCurrentContext) { 296ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("Acquiring different scenes from same thread without releases"); 297ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 298ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return SUCCESS.getResult(); 299ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 3003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 301ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return null; 302ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 303ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 304ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 305ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Cleans up the scene after an action. 306ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 307ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet public void release() { 308ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet ReentrantLock lock = Bridge.getLock(); 309ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 310ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // with the use of finally blocks, it is possible to find ourself calling this 311ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // without a successful call to prepareScene. This test makes sure that unlock() will 312ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // not throw IllegalMonitorStateException. 313ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (lock.isHeldByCurrentThread()) { 314ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // Make sure to remove static references, otherwise we could not unload the lib 315ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet mContext.disposeResources(); 316ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet sCurrentContext = null; 317ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 318ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet lock.unlock(); 319ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 3203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 3233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Inflates the layout. 3243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 325ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 326ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 327ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 328ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #init(long)} was not called. 3293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 3303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public SceneResult inflate() { 331ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 332ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 3333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 3343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot = new FrameLayout(mContext); 3363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Sets the project callback (custom view loader) to the fragment delegate so that 3383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // it can instantiate the custom Fragment. 3393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Fragment_Delegate.setProjectCallback(mParams.getProjectCallback()); 3403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View view = mInflater.inflate(mBlockParser, mViewRoot); 3423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // post-inflate process. For now this supports TabHost/TabWidget 3443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet postInflateProcess(view, mParams.getProjectCallback()); 3453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Fragment_Delegate.setProjectCallback(null); 3473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // set the AttachInfo on the root view. 3493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(), 3503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet new Handler(), null); 3513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mHasWindowFocus = true; 3523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mWindowVisibility = View.VISIBLE; 3533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mInTouchMode = false; // this is so that we can display selections. 3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.dispatchAttachedToWindow(info, 0); 3553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the background drawable 3573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mWindowBackground != null) { 3583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Drawable d = ResourceHelper.getDrawable(mWindowBackground, 3593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext, true /* isFramework */); 3603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.setBackgroundDrawable(d); 3613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return SceneResult.SUCCESS; 3643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (PostInflateException e) { 3653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Error during post inflation process:\n" + e.getMessage()); 3663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 3673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 3683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 3693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 3703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 3713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // log it 3743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getLogger().error(t); 3753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Unknown error during inflation.", t); 3773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 3813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Renders the scene. 3823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 383ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 384ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 385ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 386ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 3873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 3883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public SceneResult render() { 389ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 390ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 3913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 392ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet long current = System.currentTimeMillis(); 3933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mViewRoot == null) { 3943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Layout has not been inflated!"); 3953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // measure the views 3973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int w_spec, h_spec; 3983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int renderScreenWidth = mParams.getScreenWidth(); 4003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int renderScreenHeight = mParams.getScreenHeight(); 4013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 402e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet RenderingMode renderingMode = mParams.getRenderingMode(); 403e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet 404e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet if (renderingMode != RenderingMode.NORMAL) { 4053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // measure the full size needed by the layout. 4063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth, 407e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet renderingMode.isHorizExpand() ? 408e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet MeasureSpec.UNSPECIFIED // this lets us know the actual needed size 409e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet : MeasureSpec.EXACTLY); 4103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset, 411e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet renderingMode.isVertExpand() ? 412e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet MeasureSpec.UNSPECIFIED // this lets us know the actual needed size 413e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet : MeasureSpec.EXACTLY); 4143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.measure(w_spec, h_spec); 4153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 416e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet if (renderingMode.isHorizExpand()) { 417e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth(); 418e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet if (neededWidth > renderScreenWidth) { 419e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet renderScreenWidth = neededWidth; 420e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet } 4213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 423e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet if (renderingMode.isVertExpand()) { 424e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight(); 425e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet if (neededHeight > renderScreenHeight - mScreenOffset) { 426e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet renderScreenHeight = neededHeight + mScreenOffset; 427e489a969de010782fcc0ab048c7357d42ada9400Xavier Ducrohet } 4283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // remeasure with the size we need 4323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // This must always be done before the call to layout 4333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth, MeasureSpec.EXACTLY); 4343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset, 4353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet MeasureSpec.EXACTLY); 4363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.measure(w_spec, h_spec); 4373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now do the layout. 4393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.layout(0, mScreenOffset, renderScreenWidth, renderScreenHeight); 4403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // draw the views 4423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // create the BufferedImage into which the layout will be rendered. 4433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset, 4443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet BufferedImage.TYPE_INT_ARGB); 4453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mParams.isCustomBackgroundEnabled()) { 4473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Graphics2D gc = mImage.createGraphics(); 4488396d6f3a1f8cb397a1ef54f0a38893d64d7c275Tor Norbye gc.setColor(new Color(mParams.getCustomBackgroundColor(), true)); 4493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet gc.fillRect(0, 0, renderScreenWidth, renderScreenHeight - mScreenOffset); 4503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet gc.dispose(); 4513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // create an Android bitmap around the BufferedImage 4543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage, 455e4d978793ab8b4fdf88c7a6235d9ba17860c7bdaXavier Ducrohet true /*isMutable*/, 4563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Density.getEnum(mParams.getDensity())); 4573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // create a Canvas around the Android bitmap 4593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Canvas canvas = new Canvas(bitmap); 460e4d978793ab8b4fdf88c7a6235d9ba17860c7bdaXavier Ducrohet canvas.setDensity(mParams.getDensity()); 4613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // to set the logger, get the native delegate 4633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); 4643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet canvasDelegate.setLogger(mParams.getLogger()); 4653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.draw(canvas); 4673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet canvasDelegate.dispose(); 4683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext); 4703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 471ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet System.out.println("rendering (ms): " + (System.currentTimeMillis() - current)); 472ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 4733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // success! 4743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return SceneResult.SUCCESS; 4753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 4763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 4773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 4783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 4793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 4803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // log it 4833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getLogger().error(t); 4843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Unknown error during inflation.", t); 4863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 490ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Animate an object 491ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * <p> 492ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * {@link #acquire(long)} must have been called before this. 493ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 494ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 495ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 496ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 497ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet public SceneResult animate(Object targetObject, String animationName, 498ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet boolean isFrameworkAnimation, IAnimationListener listener) { 499ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet checkLock(); 500ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 501ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet // find the animation file. 502ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet IResourceValue animationResource = null; 503ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet int animationId = 0; 504ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (isFrameworkAnimation) { 505ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet animationResource = mContext.getFrameworkResource("anim", animationName); 506ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (animationResource != null) { 507ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet animationId = Bridge.getResourceValue("anim", animationName); 508ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 509ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } else { 510ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet animationResource = mContext.getProjectResource("anim", animationName); 511ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (animationResource != null) { 512ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet animationId = mContext.getProjectCallback().getResourceValue("anim", animationName); 513ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 514ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 515ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 516ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (animationResource != null) { 517ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet try { 518ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator( 519ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet mContext, animationId); 520ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (anim != null) { 521ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet anim.setTarget(targetObject); 522ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 523ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet new AnimationThread(this, anim, listener).start(); 524ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 525ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return SceneResult.SUCCESS; 526ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 527ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } catch (Exception e) { 528ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet e.printStackTrace(); 529ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return new SceneResult("", e); 530ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 531ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 532ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 533ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet return new SceneResult("Failed to find animation"); 534ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 535ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 536ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 537ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * Checks that the lock is owned by the current thread and that the current context is the one 538ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * from this scene. 539ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * 540ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * @throws IllegalStateException if the current context is different than the one owned by 541ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet * the scene, or if {@link #acquire(long)} was not called. 542ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet */ 543ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet private void checkLock() { 544ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet ReentrantLock lock = Bridge.getLock(); 545ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (lock.isHeldByCurrentThread() == false) { 546ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("scene must be acquired first. see #acquire(long)"); 547ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 548ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet if (sCurrentContext != mContext) { 549ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet throw new IllegalStateException("Thread acquired a scene but is rendering a different one"); 550ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 551ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet } 552ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 553ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet 554ddea50d03cdda807bbaea54beffd7a341c51f770Xavier Ducrohet /** 5553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Compute style information from the given list of style for the project and framework. 5563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param themeName the name of the current theme. In order to differentiate project and 5573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * platform themes sharing the same name, all project themes must be prepended with 5583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * a '*' character. 5593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param isProjectTheme Is this a project theme 5603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inProjectStyleMap the project style map 5613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inFrameworkStyleMap the framework style map 5623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param outInheritanceMap the map of style inheritance. This is filled by the method 5633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @return the {@link IStyleResourceValue} matching <var>themeName</var> 5643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 5653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IStyleResourceValue computeStyleMaps( 5663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String themeName, boolean isProjectTheme, Map<String, 5673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue> inProjectStyleMap, Map<String, IResourceValue> inFrameworkStyleMap, 5683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) { 5693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (inProjectStyleMap != null && inFrameworkStyleMap != null) { 5713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // first, get the theme 5723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue theme = null; 5733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // project theme names have been prepended with a * 5753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (isProjectTheme) { 5763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet theme = inProjectStyleMap.get(themeName); 5773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else { 5783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet theme = inFrameworkStyleMap.get(themeName); 5793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (theme instanceof IStyleResourceValue) { 5823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the inheritance map for both the project and framework styles 5833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap, 5843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet inFrameworkStyleMap, outInheritanceMap); 5853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Compute the style inheritance for the framework styles/themes. 5873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Since, for those, the style parent values do not contain 'android:' 5883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // we want to force looking in the framework style only to avoid using 5893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // similarly named styles from the project. 5903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // To do this, we pass null in lieu of the project style map. 5913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */, 5923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet inFrameworkStyleMap, outInheritanceMap); 5933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return (IStyleResourceValue)theme; 5953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 5993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 6023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Compute the parent style for all the styles in a given list. 6033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param styles the styles for which we compute the parent. 6043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inProjectStyleMap the map of project styles. 6053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inFrameworkStyleMap the map of framework styles. 6063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param outInheritanceMap the map of style inheritance. This is filled by the method. 6073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 6083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void computeStyleInheritance(Collection<IResourceValue> styles, 6093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inProjectStyleMap, 6103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inFrameworkStyleMap, 6113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) { 6123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (IResourceValue value : styles) { 6133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value instanceof IStyleResourceValue) { 6143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IStyleResourceValue style = (IStyleResourceValue)value; 6153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IStyleResourceValue parentStyle = null; 6163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // first look for a specified parent. 6183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String parentName = style.getParentStyle(); 6193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // no specified parent? try to infer it from the name of the style. 6213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parentName == null) { 6223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parentName = getParentName(value.getName()); 6233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parentName != null) { 6263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap); 6273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parentStyle != null) { 6293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet outInheritanceMap.put(style, parentStyle); 6303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 6373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Searches for and returns the {@link IStyleResourceValue} from a given name. 6383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p/>The format of the name can be: 6393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <ul> 6403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <li>[android:]<name></li> 6413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <li>[android:]style/<name></li> 6423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <li>@[android:]style/<name></li> 6433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * </ul> 6443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param parentName the name of the style. 6453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inProjectStyleMap the project style map. Can be <code>null</code> 6463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inFrameworkStyleMap the framework style map. 6473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @return The matching {@link IStyleResourceValue} object or <code>null</code> if not found. 6483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 6493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IStyleResourceValue getStyle(String parentName, 6503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inProjectStyleMap, 6513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inFrameworkStyleMap) { 6523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet boolean frameworkOnly = false; 6533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String name = parentName; 6553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // remove the useless @ if it's there 6573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) { 6583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length()); 6593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // check for framework identifier. 6623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) { 6633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet frameworkOnly = true; 6643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = name.substring(BridgeConstants.PREFIX_ANDROID.length()); 6653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // at this point we could have the format <type>/<name>. we want only the name as long as 6683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // the type is style. 6693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) { 6703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = name.substring(BridgeConstants.REFERENCE_STYLE.length()); 6713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else if (name.indexOf('/') != -1) { 6723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 6733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue parent = null; 6763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // if allowed, search in the project resources. 6783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (frameworkOnly == false && inProjectStyleMap != null) { 6793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parent = inProjectStyleMap.get(name); 6803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // if not found, then look in the framework resources. 6833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parent == null) { 6843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parent = inFrameworkStyleMap.get(name); 6853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // make sure the result is the proper class type and return it. 6883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parent instanceof IStyleResourceValue) { 6893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return (IStyleResourceValue)parent; 6903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getLogger().error( 6933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String.format("Unable to resolve parent style name: %s", parentName)); 6943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 6963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 6993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Computes the name of the parent style, or <code>null</code> if the style is a root style. 7003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 7013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private String getParentName(String styleName) { 7023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int index = styleName.lastIndexOf('.'); 7033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (index != -1) { 7043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return styleName.substring(0, index); 7053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 7083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 7113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Returns the top screen offset. This depends on whether the current theme defines the user 7123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * of the title and status bars. 7133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param frameworkResources The framework resources 7143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param currentTheme The current theme 7153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param context The context 7163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @return the pixel height offset 7173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 7183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private int getScreenOffset(Map<String, Map<String, IResourceValue>> frameworkResources, 7193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IStyleResourceValue currentTheme, BridgeContext context) { 7203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int offset = 0; 7213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the title bar flag from the current theme. 7233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle"); 7243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // because it may reference something else, we resolve it. 7263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.resolveResValue(value); 7273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // if there's a value and it's true (default is false) 7293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value == null || value.getValue() == null || 7303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) { 7313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // default size of the window title bar 7323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT; 7333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get value from the theme. 7353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.findItemInStyle(currentTheme, "windowTitleSize"); 7363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // resolve it 7383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.resolveResValue(value); 7393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value != null) { 7413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the numerical value, if available 7423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet TypedValue typedValue = ResourceHelper.getValue(value.getValue()); 7433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (typedValue != null) { 7443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the pixel value based on the display metrics 7453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics); 7463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet offset += defaultOffset; 7503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the fullscreen flag from the current theme. 7533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.findItemInStyle(currentTheme, "windowFullscreen"); 7543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // because it may reference something else, we resolve it. 7563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.resolveResValue(value); 7573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value == null || value.getValue() == null || 7593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) { 7603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // default value 7623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT; 7633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real value, first the list of Dimensions from the framework map 7653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN); 7663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now get the value 7683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = dimens.get("status_bar_height"); 7693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value != null) { 7703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet TypedValue typedValue = ResourceHelper.getValue(value.getValue()); 7713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (typedValue != null) { 7723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the pixel value based on the display metrics 7733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics); 7743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // add the computed offset. 7783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet offset += defaultOffset; 7793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return offset; 7823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 7843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 7853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 7863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Post process on a view hierachy that was just inflated. 7873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the 7883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically 7893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * based on the content of the {@link FrameLayout}. 7903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param view the root view to process. 7913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param projectCallback callback to the project. 7923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 7933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void postInflateProcess(View view, IProjectCallback projectCallback) 7943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 7953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view instanceof TabHost) { 7963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet setupTabHost((TabHost)view, projectCallback); 7973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else if (view instanceof ViewGroup) { 7983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewGroup group = (ViewGroup)view; 7993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = group.getChildCount(); 8003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int c = 0 ; c < count ; c++) { 8013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View child = group.getChildAt(c); 8023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet postInflateProcess(child, projectCallback); 8033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 8083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Sets up a {@link TabHost} object. 8093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param tabHost the TabHost to setup. 8103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param projectCallback The project callback object to access the project R class. 8113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @throws PostInflateException 8123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 8133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback) 8143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 8153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // look for the TabWidget, and the FrameLayout. They have their own specific names 8163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View v = tabHost.findViewById(android.R.id.tabs); 8173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 8193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 8203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n"); 8213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if ((v instanceof TabWidget) == false) { 8243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 8253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n" + 8263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName())); 8273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet v = tabHost.findViewById(android.R.id.tabcontent); 8303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 8323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty) 8333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 8343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\"."); 8353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if ((v instanceof FrameLayout) == false) { 8383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 8393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" + 8403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName())); 8413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet FrameLayout content = (FrameLayout)v; 8443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now process the content of the framelayout and dynamically create tabs for it. 8463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = content.getChildCount(); 8473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (count == 0) { 8493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 8503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "The FrameLayout for the TabHost has no content. Rendering failed.\n"); 8513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // this must be called before addTab() so that the TabHost searches its TabWidget 8543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // and FrameLayout. 8553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet tabHost.setup(); 8563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // for each child of the framelayout, add a new TabSpec 8583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int i = 0 ; i < count ; i++) { 8593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View child = content.getChildAt(i); 8603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String tabSpec = String.format("tab_spec%d", i+1); 8613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int id = child.getId(); 8623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String[] resource = projectCallback.resolveResourceValue(id); 8633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String name; 8643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (resource != null) { 8653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = resource[0]; // 0 is resource name, 1 is resource type. 8663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else { 8673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = String.format("Tab %d", i+1); // default name if id is unresolved. 8683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id)); 8703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 8753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Visits a View and its children and generate a {@link ViewInfo} containing the 8763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * bounds of all the views. 8773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param view the root View 8783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param context the context. 8793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 8803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private ViewInfo visit(View view, BridgeContext context) { 8813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view == null) { 8823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 8833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewInfo result = new ViewInfo(view.getClass().getName(), 8863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet context.getViewKey(view), 8872d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), 8882d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet view, view.getLayoutParams()); 8893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view instanceof ViewGroup) { 8913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewGroup group = ((ViewGroup) view); 8923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet List<ViewInfo> children = new ArrayList<ViewInfo>(); 8933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int i = 0; i < group.getChildCount(); i++) { 8943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet children.add(visit(group.getChildAt(i), context)); 8953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet result.setChildren(children); 8973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 8983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 8993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return result; 9003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public BufferedImage getImage() { 9033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return mImage; 9043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 9063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public ViewInfo getViewInfo() { 9073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return mViewInfo; 9083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 9092d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet 9102d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet public Map<String, String> getDefaultViewPropertyValues(Object viewObject) { 9112d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet return mContext.getDefaultPropMap(viewObject); 9122d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet } 9133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet} 914