Work on fragments in layouts.
- Change semantics if IDs associated with these fragments, to
work correctly when placed in a container. If the container
has an ID or you have supplied a tag, the fragment's ID is
optional.
- To do this, there is a new LayoutInflater API that allows code
creating views to access the parent container that view will
be in.
- Fix issues with state management around these fragments. Now
correctly retains state when switching to a layout that doesn't
include the fragment.
Also:
- Add new simple list layouts for items that want to show an
activated state.
- Add new Activity.dump() that can be invoked with adb shell
dumpsys; the default implementation dumps fragment state.
Change-Id: I192f35e3ea8c53fbd26cf909095f2a994abfc1b6
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 458274f..d24af52 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -67,6 +67,7 @@
// these are optional, set by the caller
private boolean mFactorySet;
private Factory mFactory;
+ private Factory2 mFactory2;
private Filter mFilter;
private final Object[] mConstructorArgs = new Object[2];
@@ -122,12 +123,33 @@
public View onCreateView(String name, Context context, AttributeSet attrs);
}
- private static class FactoryMerger implements Factory {
+ public interface Factory2 extends Factory {
+ /**
+ * Version of {@link #onCreateView(String, Context, AttributeSet)}
+ * that also supplies the parent that the view created view will be
+ * placed in.
+ *
+ * @param parent The parent that the created view will be placed
+ * in; <em>note that this may be null</em>.
+ * @param name Tag name to be inflated.
+ * @param context The context the view is being created in.
+ * @param attrs Inflation attributes as specified in XML file.
+ *
+ * @return View Newly created view. Return null for the default
+ * behavior.
+ */
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
+ }
+
+ private static class FactoryMerger implements Factory2 {
private final Factory mF1, mF2;
+ private final Factory2 mF12, mF22;
- FactoryMerger(Factory f1, Factory f2) {
+ FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {
mF1 = f1;
mF2 = f2;
+ mF12 = f12;
+ mF22 = f22;
}
public View onCreateView(String name, Context context, AttributeSet attrs) {
@@ -135,6 +157,14 @@
if (v != null) return v;
return mF2.onCreateView(name, context, attrs);
}
+
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+ View v = mF12 != null ? mF12.onCreateView(parent, name, context, attrs)
+ : mF1.onCreateView(name, context, attrs);
+ if (v != null) return v;
+ return mF22 != null ? mF22.onCreateView(parent, name, context, attrs)
+ : mF2.onCreateView(name, context, attrs);
+ }
}
/**
@@ -162,6 +192,7 @@
protected LayoutInflater(LayoutInflater original, Context newContext) {
mContext = newContext;
mFactory = original.mFactory;
+ mFactory2 = original.mFactory2;
mFilter = original.mFilter;
}
@@ -200,7 +231,7 @@
}
/**
- * Return the current factory (or null). This is called on each element
+ * Return the current {@link Factory} (or null). This is called on each element
* name. If the factory returns a View, add that to the hierarchy. If it
* returns null, proceed to call onCreateView(name).
*/
@@ -209,6 +240,17 @@
}
/**
+ * Return the current {@link Factory2}. Returns null if no factory is set
+ * or the set factory does not implement the {@link Factory2} interface.
+ * This is called on each element
+ * name. If the factory returns a View, add that to the hierarchy. If it
+ * returns null, proceed to call onCreateView(name).
+ */
+ public final Factory2 getFactory2() {
+ return mFactory2;
+ }
+
+ /**
* Attach a custom Factory interface for creating views while using
* this LayoutInflater. This must not be null, and can only be set once;
* after setting, you can not change the factory. This is
@@ -234,7 +276,26 @@
if (mFactory == null) {
mFactory = factory;
} else {
- mFactory = new FactoryMerger(factory, mFactory);
+ mFactory = new FactoryMerger(factory, null, mFactory, mFactory2);
+ }
+ }
+
+ /**
+ * Like {@link #setFactory}, but allows you to set a {@link Factory2}
+ * interface.
+ */
+ public void setFactory2(Factory2 factory) {
+ if (mFactorySet) {
+ throw new IllegalStateException("A factory has already been set on this LayoutInflater");
+ }
+ if (factory == null) {
+ throw new NullPointerException("Given factory can not be null");
+ }
+ mFactorySet = true;
+ if (mFactory == null) {
+ mFactory = mFactory2 = factory;
+ } else {
+ mFactory = new FactoryMerger(factory, factory, mFactory, mFactory2);
}
}
@@ -384,7 +445,7 @@
rInflate(parser, root, attrs, false);
} else {
// Temp is the root view that was found in the xml
- View temp = createViewFromTag(name, attrs);
+ View temp = createViewFromTag(root, name, attrs);
ViewGroup.LayoutParams params = null;
@@ -557,10 +618,27 @@
return createView(name, "android.view.", attrs);
}
+ /**
+ * Version of {@link #onCreateView(String, AttributeSet)} that also
+ * takes the future parent of the view being constructure. The default
+ * implementation simply calls {@link #onCreateView(String, AttributeSet)}.
+ *
+ * @param parent The future parent of the returned view. <em>Note that
+ * this may be null.</em>
+ * @param name The fully qualified class name of the View to be create.
+ * @param attrs An AttributeSet of attributes to apply to the View.
+ *
+ * @return View The View created.
+ */
+ protected View onCreateView(View parent, String name, AttributeSet attrs)
+ throws ClassNotFoundException {
+ return onCreateView(name, attrs);
+ }
+
/*
* default visibility so the BridgeInflater can override it.
*/
- View createViewFromTag(String name, AttributeSet attrs) {
+ View createViewFromTag(View parent, String name, AttributeSet attrs) {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
@@ -568,12 +646,14 @@
if (DEBUG) System.out.println("******** Creating view: " + name);
try {
- View view = (mFactory == null) ? null : mFactory.onCreateView(name,
- mContext, attrs);
+ View view;
+ if (mFactory2 != null) view = mFactory2.onCreateView(parent, name, mContext, attrs);
+ else if (mFactory != null) view = mFactory.onCreateView(name, mContext, attrs);
+ else view = null;
if (view == null) {
if (-1 == name.indexOf('.')) {
- view = onCreateView(name, attrs);
+ view = onCreateView(parent, name, attrs);
} else {
view = createView(name, null, attrs);
}
@@ -628,7 +708,7 @@
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
- final View view = createViewFromTag(name, attrs);
+ final View view = createViewFromTag(parent, name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs, true);
@@ -689,7 +769,7 @@
// Inflate all children.
rInflate(childParser, parent, childAttrs, false);
} else {
- final View view = createViewFromTag(childName, childAttrs);
+ final View view = createViewFromTag(parent, childName, childAttrs);
final ViewGroup group = (ViewGroup) parent;
// We try to load the layout params set in the <include /> tag. If