Merge change 4544 into donut
* changes: Connect TabHost/TabWidget/FrameLayout in the layout editor.
This commit is contained in:
@@ -55,6 +55,8 @@ import android.view.View.AttachInfo;
|
|||||||
import android.view.View.MeasureSpec;
|
import android.view.View.MeasureSpec;
|
||||||
import android.view.WindowManager.LayoutParams;
|
import android.view.WindowManager.LayoutParams;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.TabHost;
|
||||||
|
import android.widget.TabWidget;
|
||||||
|
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@@ -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[]>();
|
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>();
|
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 =
|
private final static Map<String, Map<String, Integer>> sRFullMap =
|
||||||
new HashMap<String, Map<String,Integer>>();
|
new HashMap<String, Map<String,Integer>>();
|
||||||
@@ -294,6 +297,7 @@ public final class Bridge implements ILayoutBridge {
|
|||||||
* (non-Javadoc)
|
* (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)
|
* @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,
|
public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
|
||||||
int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
|
int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
|
||||||
Map<String, Map<String, IResourceValue>> projectResources,
|
Map<String, Map<String, IResourceValue>> projectResources,
|
||||||
@@ -370,6 +374,9 @@ public final class Bridge implements ILayoutBridge {
|
|||||||
|
|
||||||
View view = inflater.inflate(parser, root);
|
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.
|
// set the AttachInfo on the root view.
|
||||||
AttachInfo info = new AttachInfo(new WindowSession(), new Window(),
|
AttachInfo info = new AttachInfo(new WindowSession(), new Window(),
|
||||||
new Handler(), null);
|
new Handler(), null);
|
||||||
@@ -402,6 +409,9 @@ public final class Bridge implements ILayoutBridge {
|
|||||||
|
|
||||||
return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context),
|
return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context),
|
||||||
canvas.getImage());
|
canvas.getImage());
|
||||||
|
} catch (PostInflateException e) {
|
||||||
|
return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n"
|
||||||
|
+ e.getMessage());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// get the real cause of the exception.
|
// get the real cause of the exception.
|
||||||
Throwable t = e;
|
Throwable t = e;
|
||||||
@@ -710,6 +720,94 @@ public final class Bridge implements ILayoutBridge {
|
|||||||
return offset;
|
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
|
* Returns the bitmap for a specific path, from a specific project cache, or from the
|
||||||
* framework cache.
|
* framework cache.
|
||||||
@@ -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
|
* Implementation of {@link IWindowSession} so that mSession is not null in
|
||||||
* the {@link SurfaceView}.
|
* the {@link SurfaceView}.
|
||||||
|
|||||||
Reference in New Issue
Block a user