Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +180 −74 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ import android.view.View.AttachInfo; import android.view.View.MeasureSpec; import android.view.WindowManager.LayoutParams; import android.widget.FrameLayout; import android.widget.TabHost; import android.widget.TabWidget; import java.lang.ref.SoftReference; import java.lang.reflect.Field; Loading Loading @@ -82,15 +84,16 @@ public final class Bridge implements ILayoutBridge { } /** * Maps from id to resource name/type. * Maps from id to resource name/type. This is for android.R only. */ private final static Map<Integer, String[]> sRMap = new HashMap<Integer, String[]>(); /** * Same as sRMap except for int[] instead of int resources. * Same as sRMap except for int[] instead of int resources. This is for android.R only. */ private final static Map<int[], String> sRArrayMap = new HashMap<int[], String>(); /** * Reverse map compared to sRMap, resource type -> (resource name -> id) * Reverse map compared to sRMap, resource type -> (resource name -> id). * This is for android.R only. */ private final static Map<String, Map<String, Integer>> sRFullMap = new HashMap<String, Map<String,Integer>>(); Loading Loading @@ -294,6 +297,7 @@ public final class Bridge implements ILayoutBridge { * (non-Javadoc) * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog) */ @Deprecated public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey, int screenWidth, int screenHeight, String themeName, boolean isProjectTheme, Map<String, Map<String, IResourceValue>> projectResources, Loading Loading @@ -370,6 +374,9 @@ public final class Bridge implements ILayoutBridge { View view = inflater.inflate(parser, root); // post-inflate process. For now this supports TabHost/TabWidget postInflateProcess(view, customViewLoader); // set the AttachInfo on the root view. AttachInfo info = new AttachInfo(new WindowSession(), new Window(), new Handler(), null); Loading Loading @@ -402,6 +409,9 @@ public final class Bridge implements ILayoutBridge { return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context), canvas.getImage()); } catch (PostInflateException e) { return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n" + e.getMessage()); } catch (Throwable e) { // get the real cause of the exception. Throwable t = e; Loading Loading @@ -710,6 +720,94 @@ public final class Bridge implements ILayoutBridge { return offset; } /** * Post process on a view hierachy that was just inflated. * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically * based on the content of the {@link FrameLayout}. * @param view the root view to process. * @param projectCallback callback to the project. */ private void postInflateProcess(View view, IProjectCallback projectCallback) throws PostInflateException { if (view instanceof TabHost) { setupTabHost((TabHost)view, projectCallback); } else if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup)view; final int count = group.getChildCount(); for (int c = 0 ; c < count ; c++) { View child = group.getChildAt(c); postInflateProcess(child, projectCallback); } } } /** * Sets up a {@link TabHost} object. * @param tabHost the TabHost to setup. * @param projectCallback The project callback object to access the project R class. * @throws PostInflateException */ private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback) throws PostInflateException { // look for the TabWidget, and the FrameLayout. They have their own specific names View v = tabHost.findViewById(android.R.id.tabs); if (v == null) { throw new PostInflateException( "TabHost requires a TabWidget with id \"android:id/tabs\".\n"); } if ((v instanceof TabWidget) == false) { throw new PostInflateException(String.format( "TabHost requires a TabWidget with id \"android:id/tabs\".\n" + "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName())); } v = tabHost.findViewById(android.R.id.tabcontent); if (v == null) { // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty) throw new PostInflateException( "TabHost requires a FrameLayout with id \"android:id/tabcontent\"."); } if ((v instanceof FrameLayout) == false) { throw new PostInflateException(String.format( "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" + "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName())); } FrameLayout content = (FrameLayout)v; // now process the content of the framelayout and dynamically create tabs for it. final int count = content.getChildCount(); if (count == 0) { throw new PostInflateException( "The FrameLayout for the TabHost has no content. Rendering failed.\n"); } // this must be called before addTab() so that the TabHost searches its TabWidget // and FrameLayout. tabHost.setup(); // for each child of the framelayout, add a new TabSpec for (int i = 0 ; i < count ; i++) { View child = content.getChildAt(i); String tabSpec = String.format("tab_spec%d", i+1); int id = child.getId(); String[] resource = projectCallback.resolveResourceValue(id); String name; if (resource != null) { name = resource[0]; // 0 is resource name, 1 is resource type. } else { name = String.format("Tab %d", i+1); // default name if id is unresolved. } tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id)); } } /** * Returns the bitmap for a specific path, from a specific project cache, or from the * framework cache. Loading Loading @@ -805,6 +903,14 @@ public final class Bridge implements ILayoutBridge { } } private static final class PostInflateException extends Exception { private static final long serialVersionUID = 1L; public PostInflateException(String message) { super(message); } } /** * Implementation of {@link IWindowSession} so that mSession is not null in * the {@link SurfaceView}. Loading Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +180 −74 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ import android.view.View.AttachInfo; import android.view.View.MeasureSpec; import android.view.WindowManager.LayoutParams; import android.widget.FrameLayout; import android.widget.TabHost; import android.widget.TabWidget; import java.lang.ref.SoftReference; import java.lang.reflect.Field; Loading Loading @@ -82,15 +84,16 @@ public final class Bridge implements ILayoutBridge { } /** * Maps from id to resource name/type. * Maps from id to resource name/type. This is for android.R only. */ private final static Map<Integer, String[]> sRMap = new HashMap<Integer, String[]>(); /** * Same as sRMap except for int[] instead of int resources. * Same as sRMap except for int[] instead of int resources. This is for android.R only. */ private final static Map<int[], String> sRArrayMap = new HashMap<int[], String>(); /** * Reverse map compared to sRMap, resource type -> (resource name -> id) * Reverse map compared to sRMap, resource type -> (resource name -> id). * This is for android.R only. */ private final static Map<String, Map<String, Integer>> sRFullMap = new HashMap<String, Map<String,Integer>>(); Loading Loading @@ -294,6 +297,7 @@ public final class Bridge implements ILayoutBridge { * (non-Javadoc) * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog) */ @Deprecated public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey, int screenWidth, int screenHeight, String themeName, boolean isProjectTheme, Map<String, Map<String, IResourceValue>> projectResources, Loading Loading @@ -370,6 +374,9 @@ public final class Bridge implements ILayoutBridge { View view = inflater.inflate(parser, root); // post-inflate process. For now this supports TabHost/TabWidget postInflateProcess(view, customViewLoader); // set the AttachInfo on the root view. AttachInfo info = new AttachInfo(new WindowSession(), new Window(), new Handler(), null); Loading Loading @@ -402,6 +409,9 @@ public final class Bridge implements ILayoutBridge { return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context), canvas.getImage()); } catch (PostInflateException e) { return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n" + e.getMessage()); } catch (Throwable e) { // get the real cause of the exception. Throwable t = e; Loading Loading @@ -710,6 +720,94 @@ public final class Bridge implements ILayoutBridge { return offset; } /** * Post process on a view hierachy that was just inflated. * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically * based on the content of the {@link FrameLayout}. * @param view the root view to process. * @param projectCallback callback to the project. */ private void postInflateProcess(View view, IProjectCallback projectCallback) throws PostInflateException { if (view instanceof TabHost) { setupTabHost((TabHost)view, projectCallback); } else if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup)view; final int count = group.getChildCount(); for (int c = 0 ; c < count ; c++) { View child = group.getChildAt(c); postInflateProcess(child, projectCallback); } } } /** * Sets up a {@link TabHost} object. * @param tabHost the TabHost to setup. * @param projectCallback The project callback object to access the project R class. * @throws PostInflateException */ private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback) throws PostInflateException { // look for the TabWidget, and the FrameLayout. They have their own specific names View v = tabHost.findViewById(android.R.id.tabs); if (v == null) { throw new PostInflateException( "TabHost requires a TabWidget with id \"android:id/tabs\".\n"); } if ((v instanceof TabWidget) == false) { throw new PostInflateException(String.format( "TabHost requires a TabWidget with id \"android:id/tabs\".\n" + "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName())); } v = tabHost.findViewById(android.R.id.tabcontent); if (v == null) { // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty) throw new PostInflateException( "TabHost requires a FrameLayout with id \"android:id/tabcontent\"."); } if ((v instanceof FrameLayout) == false) { throw new PostInflateException(String.format( "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" + "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName())); } FrameLayout content = (FrameLayout)v; // now process the content of the framelayout and dynamically create tabs for it. final int count = content.getChildCount(); if (count == 0) { throw new PostInflateException( "The FrameLayout for the TabHost has no content. Rendering failed.\n"); } // this must be called before addTab() so that the TabHost searches its TabWidget // and FrameLayout. tabHost.setup(); // for each child of the framelayout, add a new TabSpec for (int i = 0 ; i < count ; i++) { View child = content.getChildAt(i); String tabSpec = String.format("tab_spec%d", i+1); int id = child.getId(); String[] resource = projectCallback.resolveResourceValue(id); String name; if (resource != null) { name = resource[0]; // 0 is resource name, 1 is resource type. } else { name = String.format("Tab %d", i+1); // default name if id is unresolved. } tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id)); } } /** * Returns the bitmap for a specific path, from a specific project cache, or from the * framework cache. Loading Loading @@ -805,6 +903,14 @@ public final class Bridge implements ILayoutBridge { } } private static final class PostInflateException extends Exception { private static final long serialVersionUID = 1L; public PostInflateException(String message) { super(message); } } /** * Implementation of {@link IWindowSession} so that mSession is not null in * the {@link SurfaceView}. Loading