RenderSessionImpl.java revision 2d240967c9bc38cbf69967457b33f953f8826e96
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 193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.internal.util.XmlUtils; 203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IProjectCallback; 213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IResourceValue; 223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IStyleResourceValue; 233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.LayoutBridge; 243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.SceneParams; 253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.SceneResult; 263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.ViewInfo; 273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.api.IDensityBasedResourceValue.Density; 283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.BridgeConstants; 293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext; 303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeInflater; 313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindow; 323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeWindowSession; 333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser; 343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.app.Fragment_Delegate; 363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap; 373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Bitmap_Delegate; 383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas; 393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.Canvas_Delegate; 403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.graphics.drawable.Drawable; 413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Handler; 423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.os.Looper; 433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.DisplayMetrics; 443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.util.TypedValue; 453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View; 463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.ViewGroup; 473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.AttachInfo; 483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.view.View.MeasureSpec; 493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.FrameLayout; 503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabHost; 513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport android.widget.TabWidget; 523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Color; 543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.Graphics2D; 553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.awt.image.BufferedImage; 563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.ArrayList; 573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Collection; 583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.HashMap; 593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.List; 603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetimport java.util.Map; 613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet/** 633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Class managing a layout "scene". 643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * A scene is a stateful representation of a layout file. It is initialized with data coming through 663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * the {@link LayoutBridge} API to inflate the layout. Further actions and rendering can then 673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * be done on the layout. 683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohetpublic class LayoutSceneImpl { 713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final int DEFAULT_TITLE_BAR_HEIGHT = 25; 733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final int DEFAULT_STATUS_BAR_HEIGHT = 25; 743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private final SceneParams mParams; 763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene state 783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeContext mContext; 793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeXmlBlockParser mBlockParser; 803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BridgeInflater mInflater; 813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IStyleResourceValue mCurrentTheme; 823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private int mScreenOffset; 833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IResourceValue mWindowBackground; 843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private FrameLayout mViewRoot; 853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // information being returned through the API 873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private BufferedImage mImage; 883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private ViewInfo mViewInfo; 893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final class PostInflateException extends Exception { 913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private static final long serialVersionUID = 1L; 923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public PostInflateException(String message) { 943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet super(message); 953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Creates a layout scene with all the information coming from the layout bridge API. 1003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 1013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * This also calls {@link LayoutSceneImpl#prepare()}. 1023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 1033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b> 1043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * 1053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams) 1063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 1073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public LayoutSceneImpl(SceneParams params) { 1083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // we need to make sure the Looper has been initialized for this thread. 1093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // this is required for View that creates Handler objects. 1103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (Looper.myLooper() == null) { 1113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Looper.prepare(); 1123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // copy the params. 1153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams = new SceneParams(params); 1163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // setup the display Metrics. 1183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet DisplayMetrics metrics = new DisplayMetrics(); 1193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.densityDpi = mParams.getDensity(); 1203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT; 1213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.scaledDensity = metrics.density; 1223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.widthPixels = mParams.getScreenWidth(); 1233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.heightPixels = mParams.getScreenHeight(); 1243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.xdpi = mParams.getXdpi(); 1253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet metrics.ydpi = mParams.getYdpi(); 1263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // find the current theme and compute the style inheritance map 1283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<IStyleResourceValue, IStyleResourceValue> styleParentMap = 1293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet new HashMap<IStyleResourceValue, IStyleResourceValue>(); 1303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mCurrentTheme = computeStyleMaps(mParams.getThemeName(), mParams.getIsProjectTheme(), 1323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getProjectResources().get(BridgeConstants.RES_STYLE), 1333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getFrameworkResources().get(BridgeConstants.RES_STYLE), styleParentMap); 1343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // build the context 1363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext = new BridgeContext(mParams.getProjectKey(), metrics, mCurrentTheme, 1373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getProjectResources(), mParams.getFrameworkResources(), 1383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet styleParentMap, mParams.getProjectCallback(), mParams.getLogger()); 1393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // make sure the Resources object references the context (and other objects) for this 1413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene 1423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.initResources(); 1433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the screen offset and window-background resource 1453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mWindowBackground = null; 1463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mScreenOffset = 0; 1473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mCurrentTheme != null && mParams.isCustomBackgroundEnabled() == false) { 1483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground"); 1493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mWindowBackground = mContext.resolveResValue(mWindowBackground); 1503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme, mContext); 1523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // build the inflater and parser. 1553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mInflater = new BridgeInflater(mContext, mParams.getProjectCallback()); 1563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.setBridgeInflater(mInflater); 1573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mInflater.setFactory2(mContext); 1583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(), 1603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext, false /* platformResourceFlag */); 1613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 1643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Prepares the scene for action. 1653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 1663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b> 1673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 1683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public void prepare() { 1693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // we need to make sure the Looper has been initialized for this thread. 1703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // this is required for View that creates Handler objects. 1713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (Looper.myLooper() == null) { 1723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Looper.prepare(); 1733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // make sure the Resources object references the context (and other objects) for this 1763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // scene 1773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.initResources(); 1783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 1813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Cleans up the scene after an action. 1823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 1833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b> 1843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 1853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public void cleanup() { 1863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // clean up the looper 1873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Looper.sThreadLocal.remove(); 1883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Make sure to remove static references, otherwise we could not unload the lib 1903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext.disposeResources(); 1913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 1923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 1933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 1943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Inflates the layout. 1953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 1963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b> 1973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 1983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public SceneResult inflate() { 1993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 2003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot = new FrameLayout(mContext); 2023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Sets the project callback (custom view loader) to the fragment delegate so that 2043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // it can instantiate the custom Fragment. 2053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Fragment_Delegate.setProjectCallback(mParams.getProjectCallback()); 2063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View view = mInflater.inflate(mBlockParser, mViewRoot); 2083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // post-inflate process. For now this supports TabHost/TabWidget 2103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet postInflateProcess(view, mParams.getProjectCallback()); 2113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Fragment_Delegate.setProjectCallback(null); 2133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // set the AttachInfo on the root view. 2153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(), 2163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet new Handler(), null); 2173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mHasWindowFocus = true; 2183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mWindowVisibility = View.VISIBLE; 2193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet info.mInTouchMode = false; // this is so that we can display selections. 2203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.dispatchAttachedToWindow(info, 0); 2213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the background drawable 2233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mWindowBackground != null) { 2243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Drawable d = ResourceHelper.getDrawable(mWindowBackground, 2253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mContext, true /* isFramework */); 2263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.setBackgroundDrawable(d); 2273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return SceneResult.SUCCESS; 2303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (PostInflateException e) { 2313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Error during post inflation process:\n" + e.getMessage()); 2323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 2333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 2343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 2353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 2363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 2373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // log it 2403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getLogger().error(t); 2413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Unknown error during inflation.", t); 2433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 2473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Renders the scene. 2483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p> 2493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b> 2503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 2513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public SceneResult render() { 2523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet try { 2533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mViewRoot == null) { 2543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Layout has not been inflated!"); 2553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // measure the views 2573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int w_spec, h_spec; 2583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int renderScreenWidth = mParams.getScreenWidth(); 2603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int renderScreenHeight = mParams.getScreenHeight(); 2613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mParams.getRenderFullSize()) { 2633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // measure the full size needed by the layout. 2643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth, 2653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size 2663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset, 2673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size 2683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.measure(w_spec, h_spec); 2693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth(); 2713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (neededWidth > renderScreenWidth) { 2723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet renderScreenWidth = neededWidth; 2733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight(); 2763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (neededHeight > renderScreenHeight - mScreenOffset) { 2773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet renderScreenHeight = neededHeight + mScreenOffset; 2783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 2803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // remeasure with the size we need 2823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // This must always be done before the call to layout 2833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth, MeasureSpec.EXACTLY); 2843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset, 2853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet MeasureSpec.EXACTLY); 2863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.measure(w_spec, h_spec); 2873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now do the layout. 2893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.layout(0, mScreenOffset, renderScreenWidth, renderScreenHeight); 2903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // draw the views 2923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // create the BufferedImage into which the layout will be rendered. 2933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset, 2943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet BufferedImage.TYPE_INT_ARGB); 2953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 2963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (mParams.isCustomBackgroundEnabled()) { 2973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Graphics2D gc = mImage.createGraphics(); 2988396d6f3a1f8cb397a1ef54f0a38893d64d7c275Tor Norbye gc.setColor(new Color(mParams.getCustomBackgroundColor(), true)); 2993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet gc.fillRect(0, 0, renderScreenWidth, renderScreenHeight - mScreenOffset); 3003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet gc.dispose(); 3013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // create an Android bitmap around the BufferedImage 3043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage, 3053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Density.getEnum(mParams.getDensity())); 3063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // create a Canvas around the Android bitmap 3083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Canvas canvas = new Canvas(bitmap); 3093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // to set the logger, get the native delegate 3113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); 3123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet canvasDelegate.setLogger(mParams.getLogger()); 3133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewRoot.draw(canvas); 3153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet canvasDelegate.dispose(); 3163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext); 3183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // success! 3203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return SceneResult.SUCCESS; 3213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } catch (Throwable e) { 3223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real cause of the exception. 3233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Throwable t = e; 3243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet while (t.getCause() != null) { 3253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet t = t.getCause(); 3263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // log it 3293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getLogger().error(t); 3303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return new SceneResult("Unknown error during inflation.", t); 3323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 3363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Compute style information from the given list of style for the project and framework. 3373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param themeName the name of the current theme. In order to differentiate project and 3383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * platform themes sharing the same name, all project themes must be prepended with 3393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * a '*' character. 3403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param isProjectTheme Is this a project theme 3413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inProjectStyleMap the project style map 3423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inFrameworkStyleMap the framework style map 3433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param outInheritanceMap the map of style inheritance. This is filled by the method 3443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @return the {@link IStyleResourceValue} matching <var>themeName</var> 3453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 3463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IStyleResourceValue computeStyleMaps( 3473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String themeName, boolean isProjectTheme, Map<String, 3483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue> inProjectStyleMap, Map<String, IResourceValue> inFrameworkStyleMap, 3493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) { 3503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (inProjectStyleMap != null && inFrameworkStyleMap != null) { 3523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // first, get the theme 3533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue theme = null; 3543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // project theme names have been prepended with a * 3563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (isProjectTheme) { 3573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet theme = inProjectStyleMap.get(themeName); 3583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else { 3593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet theme = inFrameworkStyleMap.get(themeName); 3603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (theme instanceof IStyleResourceValue) { 3633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the inheritance map for both the project and framework styles 3643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap, 3653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet inFrameworkStyleMap, outInheritanceMap); 3663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Compute the style inheritance for the framework styles/themes. 3683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // Since, for those, the style parent values do not contain 'android:' 3693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // we want to force looking in the framework style only to avoid using 3703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // similarly named styles from the project. 3713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // To do this, we pass null in lieu of the project style map. 3723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */, 3733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet inFrameworkStyleMap, outInheritanceMap); 3743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return (IStyleResourceValue)theme; 3763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 3803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 3813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 3833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Compute the parent style for all the styles in a given list. 3843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param styles the styles for which we compute the parent. 3853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inProjectStyleMap the map of project styles. 3863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inFrameworkStyleMap the map of framework styles. 3873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param outInheritanceMap the map of style inheritance. This is filled by the method. 3883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 3893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void computeStyleInheritance(Collection<IResourceValue> styles, 3903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inProjectStyleMap, 3913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inFrameworkStyleMap, 3923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) { 3933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (IResourceValue value : styles) { 3943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value instanceof IStyleResourceValue) { 3953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IStyleResourceValue style = (IStyleResourceValue)value; 3963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IStyleResourceValue parentStyle = null; 3973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 3983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // first look for a specified parent. 3993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String parentName = style.getParentStyle(); 4003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // no specified parent? try to infer it from the name of the style. 4023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parentName == null) { 4033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parentName = getParentName(value.getName()); 4043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parentName != null) { 4073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap); 4083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parentStyle != null) { 4103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet outInheritanceMap.put(style, parentStyle); 4113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 4183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Searches for and returns the {@link IStyleResourceValue} from a given name. 4193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p/>The format of the name can be: 4203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <ul> 4213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <li>[android:]<name></li> 4223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <li>[android:]style/<name></li> 4233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <li>@[android:]style/<name></li> 4243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * </ul> 4253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param parentName the name of the style. 4263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inProjectStyleMap the project style map. Can be <code>null</code> 4273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param inFrameworkStyleMap the framework style map. 4283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @return The matching {@link IStyleResourceValue} object or <code>null</code> if not found. 4293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 4303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private IStyleResourceValue getStyle(String parentName, 4313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inProjectStyleMap, 4323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> inFrameworkStyleMap) { 4333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet boolean frameworkOnly = false; 4343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String name = parentName; 4363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // remove the useless @ if it's there 4383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) { 4393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length()); 4403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // check for framework identifier. 4433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) { 4443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet frameworkOnly = true; 4453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = name.substring(BridgeConstants.PREFIX_ANDROID.length()); 4463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // at this point we could have the format <type>/<name>. we want only the name as long as 4493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // the type is style. 4503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) { 4513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = name.substring(BridgeConstants.REFERENCE_STYLE.length()); 4523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else if (name.indexOf('/') != -1) { 4533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 4543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue parent = null; 4573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // if allowed, search in the project resources. 4593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (frameworkOnly == false && inProjectStyleMap != null) { 4603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parent = inProjectStyleMap.get(name); 4613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // if not found, then look in the framework resources. 4643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parent == null) { 4653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet parent = inFrameworkStyleMap.get(name); 4663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // make sure the result is the proper class type and return it. 4693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (parent instanceof IStyleResourceValue) { 4703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return (IStyleResourceValue)parent; 4713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet mParams.getLogger().error( 4743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String.format("Unable to resolve parent style name: %s", parentName)); 4753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 4773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 4803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Computes the name of the parent style, or <code>null</code> if the style is a root style. 4813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 4823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private String getParentName(String styleName) { 4833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int index = styleName.lastIndexOf('.'); 4843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (index != -1) { 4853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return styleName.substring(0, index); 4863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 4893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 4903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 4913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 4923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Returns the top screen offset. This depends on whether the current theme defines the user 4933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * of the title and status bars. 4943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param frameworkResources The framework resources 4953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param currentTheme The current theme 4963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param context The context 4973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @return the pixel height offset 4983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 4993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private int getScreenOffset(Map<String, Map<String, IResourceValue>> frameworkResources, 5003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IStyleResourceValue currentTheme, BridgeContext context) { 5013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int offset = 0; 5023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the title bar flag from the current theme. 5043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet IResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle"); 5053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // because it may reference something else, we resolve it. 5073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.resolveResValue(value); 5083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // if there's a value and it's true (default is false) 5103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value == null || value.getValue() == null || 5113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) { 5123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // default size of the window title bar 5133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT; 5143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get value from the theme. 5163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.findItemInStyle(currentTheme, "windowTitleSize"); 5173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // resolve it 5193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.resolveResValue(value); 5203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value != null) { 5223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the numerical value, if available 5233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet TypedValue typedValue = ResourceHelper.getValue(value.getValue()); 5243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (typedValue != null) { 5253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the pixel value based on the display metrics 5263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics); 5273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet offset += defaultOffset; 5313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the fullscreen flag from the current theme. 5343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.findItemInStyle(currentTheme, "windowFullscreen"); 5353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // because it may reference something else, we resolve it. 5373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = context.resolveResValue(value); 5383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value == null || value.getValue() == null || 5403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) { 5413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // default value 5433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT; 5443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // get the real value, first the list of Dimensions from the framework map 5463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet Map<String, IResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN); 5473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now get the value 5493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet value = dimens.get("status_bar_height"); 5503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (value != null) { 5513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet TypedValue typedValue = ResourceHelper.getValue(value.getValue()); 5523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (typedValue != null) { 5533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // compute the pixel value based on the display metrics 5543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics); 5553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // add the computed offset. 5593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet offset += defaultOffset; 5603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return offset; 5633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 5673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Post process on a view hierachy that was just inflated. 5683bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the 5693bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically 5703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * based on the content of the {@link FrameLayout}. 5713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param view the root view to process. 5723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param projectCallback callback to the project. 5733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 5743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void postInflateProcess(View view, IProjectCallback projectCallback) 5753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 5763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view instanceof TabHost) { 5773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet setupTabHost((TabHost)view, projectCallback); 5783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else if (view instanceof ViewGroup) { 5793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewGroup group = (ViewGroup)view; 5803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = group.getChildCount(); 5813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int c = 0 ; c < count ; c++) { 5823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View child = group.getChildAt(c); 5833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet postInflateProcess(child, projectCallback); 5843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 5873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 5893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Sets up a {@link TabHost} object. 5903bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param tabHost the TabHost to setup. 5913bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param projectCallback The project callback object to access the project R class. 5923bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @throws PostInflateException 5933bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 5943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback) 5953bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throws PostInflateException { 5963bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // look for the TabWidget, and the FrameLayout. They have their own specific names 5973bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View v = tabHost.findViewById(android.R.id.tabs); 5983bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 5993bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 6003bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 6013bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n"); 6023bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6033bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6043bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if ((v instanceof TabWidget) == false) { 6053bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 6063bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a TabWidget with id \"android:id/tabs\".\n" + 6073bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName())); 6083bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6093bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6103bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet v = tabHost.findViewById(android.R.id.tabcontent); 6113bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6123bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (v == null) { 6133bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty) 6143bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 6153bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\"."); 6163bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6173bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6183bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if ((v instanceof FrameLayout) == false) { 6193bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException(String.format( 6203bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" + 6213bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName())); 6223bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6233bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6243bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet FrameLayout content = (FrameLayout)v; 6253bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6263bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // now process the content of the framelayout and dynamically create tabs for it. 6273bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet final int count = content.getChildCount(); 6283bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6293bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (count == 0) { 6303bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet throw new PostInflateException( 6313bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet "The FrameLayout for the TabHost has no content. Rendering failed.\n"); 6323bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6333bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6343bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // this must be called before addTab() so that the TabHost searches its TabWidget 6353bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // and FrameLayout. 6363bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet tabHost.setup(); 6373bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6383bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet // for each child of the framelayout, add a new TabSpec 6393bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int i = 0 ; i < count ; i++) { 6403bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet View child = content.getChildAt(i); 6413bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String tabSpec = String.format("tab_spec%d", i+1); 6423bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet int id = child.getId(); 6433bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String[] resource = projectCallback.resolveResourceValue(id); 6443bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet String name; 6453bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (resource != null) { 6463bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = resource[0]; // 0 is resource name, 1 is resource type. 6473bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } else { 6483bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet name = String.format("Tab %d", i+1); // default name if id is unresolved. 6493bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6503bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id)); 6513bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6523bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6533bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6543bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6553bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet /** 6563bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * Visits a View and its children and generate a {@link ViewInfo} containing the 6573bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * bounds of all the views. 6583bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param view the root View 6593bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet * @param context the context. 6603bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet */ 6613bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet private ViewInfo visit(View view, BridgeContext context) { 6623bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view == null) { 6633bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return null; 6643bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6653bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6663bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewInfo result = new ViewInfo(view.getClass().getName(), 6673bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet context.getViewKey(view), 6682d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), 6692d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet view, view.getLayoutParams()); 6703bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6713bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet if (view instanceof ViewGroup) { 6723bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet ViewGroup group = ((ViewGroup) view); 6733bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet List<ViewInfo> children = new ArrayList<ViewInfo>(); 6743bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet for (int i = 0; i < group.getChildCount(); i++) { 6753bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet children.add(visit(group.getChildAt(i), context)); 6763bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6773bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet result.setChildren(children); 6783bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6793bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6803bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return result; 6813bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6823bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6833bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public BufferedImage getImage() { 6843bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return mImage; 6853bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6863bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet 6873bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet public ViewInfo getViewInfo() { 6883bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet return mViewInfo; 6893bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet } 6902d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet 6912d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet public Map<String, String> getDefaultViewPropertyValues(Object viewObject) { 6922d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet return mContext.getDefaultPropMap(viewObject); 6932d240967c9bc38cbf69967457b33f953f8826e96Xavier Ducrohet } 6943bd98986a97e4e1921616a0a86983307e68ceb6cXavier Ducrohet} 695