summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/preference/GenericInflater.java65
-rw-r--r--core/java/android/preference/PreferenceInflater.java8
-rw-r--r--core/java/android/view/LayoutInflater.java31
3 files changed, 58 insertions, 46 deletions
diff --git a/core/java/android/preference/GenericInflater.java b/core/java/android/preference/GenericInflater.java
index 3003290..bb058c4 100644
--- a/core/java/android/preference/GenericInflater.java
+++ b/core/java/android/preference/GenericInflater.java
@@ -16,10 +16,6 @@
package android.preference;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.util.HashMap;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -31,17 +27,21 @@ import android.view.ContextThemeWrapper;
import android.view.InflateException;
import android.view.LayoutInflater;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+
// TODO: fix generics
/**
* Generic XML inflater. This has been adapted from {@link LayoutInflater} and
* quickly passed over to use generics.
*
* @hide
- * @param T The type of the items to inflate
- * @param P The type of parents (that is those items that contain other items).
+ * @param <T> The type of the items to inflate
+ * @param <P> The type of parents (that is those items that contain other items).
* Must implement {@link GenericInflater.Parent}
*/
-abstract class GenericInflater<T, P extends GenericInflater.Parent> {
+abstract class GenericInflater<T, P extends GenericInflater.Parent<T>> {
private final boolean DEBUG = false;
protected final Context mContext;
@@ -52,10 +52,11 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
private final Object[] mConstructorArgs = new Object[2];
- private static final Class[] mConstructorSignature = new Class[] {
+ private static final Class<?>[] mConstructorSignature = new Class[] {
Context.class, AttributeSet.class};
- private static final HashMap sConstructorMap = new HashMap();
+ private static final HashMap<String, Constructor<?>> sConstructorMap =
+ new HashMap<String, Constructor<?>>();
private String mDefaultPackage;
@@ -134,7 +135,7 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
* @return Returns a brand spanking new inflater object associated with
* the given Context.
*/
- public abstract GenericInflater cloneInContext(Context newContext);
+ public abstract GenericInflater<T,P> cloneInContext(Context newContext);
/**
* Sets the default package that will be searched for classes to construct
@@ -287,22 +288,21 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
* attachToRoot is true, this is root; otherwise it is the root of
* the inflated XML file.
*/
- public T inflate(XmlPullParser parser, P root,
- boolean attachToRoot) {
+ public T inflate(XmlPullParser parser, P root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
mConstructorArgs[0] = mContext;
- T result = (T) root;
+ P result = root;
try {
// Look for the root node.
int type;
- while ((type = parser.next()) != parser.START_TAG
- && type != parser.END_DOCUMENT) {
- ;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Do nothing
}
- if (type != parser.START_TAG) {
+ if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
@@ -317,7 +317,8 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
T xmlRoot = createItemFromTag(parser, parser.getName(),
attrs);
- result = (T) onMergeRoots(root, attachToRoot, (P) xmlRoot);
+ // Unsafe cast. The current name is not guaranteed to be a P.
+ result = onMergeRoots(root, attachToRoot, (P) xmlRoot);
if (DEBUG) {
System.out.println("-----> start inflating children");
@@ -343,7 +344,8 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
throw ex;
}
- return result;
+ // Unsafe cast
+ return (T) result;
}
}
@@ -362,17 +364,17 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
* @param name The full name of the class to be instantiated.
* @param attrs The XML attributes supplied for this instance.
*
- * @return The newly instantied item, or null.
+ * @return The newly instantiated item, or null.
*/
public final T createItem(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
- Constructor constructor = (Constructor) sConstructorMap.get(name);
+ Constructor<?> constructor = sConstructorMap.get(name);
try {
if (null == constructor) {
// Class not found in the cache, see if it's real,
// and try to add it
- Class clazz = mContext.getClassLoader().loadClass(
+ Class<?> clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name);
constructor = clazz.getConstructor(mConstructorSignature);
sConstructorMap.put(name, constructor);
@@ -380,6 +382,8 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
Object[] args = mConstructorArgs;
args[1] = attrs;
+ // This cast is NOT safe. The name class name is not guaranteed to be a
+ // child class of T.
return (T) constructor.newInstance(args);
} catch (NoSuchMethodException e) {
@@ -457,15 +461,15 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
* Recursive method used to descend down the xml hierarchy and instantiate
* items, instantiate their children, and then call onFinishInflate().
*/
- private void rInflate(XmlPullParser parser, T parent, final AttributeSet attrs)
+ private void rInflate(XmlPullParser parser, P parent, final AttributeSet attrs)
throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
- while (((type = parser.next()) != parser.END_TAG ||
- parser.getDepth() > depth) && type != parser.END_DOCUMENT) {
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
- if (type != parser.START_TAG) {
+ if (type != XmlPullParser.START_TAG) {
continue;
}
@@ -485,12 +489,13 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
.println("Creating params from parent: " + parent);
}
- ((P) parent).addItemFromInflater(item);
+ parent.addItemFromInflater(item);
if (DEBUG) {
System.out.println("-----> start inflating children");
}
- rInflate(parser, item, attrs);
+ // Unsafe cast
+ rInflate(parser, (P)item, attrs);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
@@ -508,8 +513,10 @@ abstract class GenericInflater<T, P extends GenericInflater.Parent> {
* @param attrs An AttributeSet of attributes to apply to the item.
* @return Whether you created a custom object (true), or whether this
* inflater should proceed to create an item.
+ *
+ * @throws XmlPullParserException In case of parsing error.
*/
- protected boolean onCreateCustomFromTag(XmlPullParser parser, T parent,
+ protected boolean onCreateCustomFromTag(XmlPullParser parser, P parent,
final AttributeSet attrs) throws XmlPullParserException {
return false;
}
diff --git a/core/java/android/preference/PreferenceInflater.java b/core/java/android/preference/PreferenceInflater.java
index 779e746..542e734 100644
--- a/core/java/android/preference/PreferenceInflater.java
+++ b/core/java/android/preference/PreferenceInflater.java
@@ -16,18 +16,16 @@
package android.preference;
-import java.io.IOException;
-import java.util.Map;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import android.app.AliasActivity;
import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
import android.util.Log;
+import java.io.IOException;
+
/**
* The {@link PreferenceInflater} is used to inflate preference hierarchies from
* XML files.
@@ -63,7 +61,7 @@ class PreferenceInflater extends GenericInflater<Preference, PreferenceGroup> {
}
@Override
- protected boolean onCreateCustomFromTag(XmlPullParser parser, Preference parentPreference,
+ protected boolean onCreateCustomFromTag(XmlPullParser parser, PreferenceGroup parentPreference,
AttributeSet attrs) throws XmlPullParserException {
final String tag = parser.getName();
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index e5985c1..428f308 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -16,15 +16,15 @@
package android.view;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
import android.util.Xml;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.HashMap;
@@ -71,11 +71,11 @@ public abstract class LayoutInflater {
private final Object[] mConstructorArgs = new Object[2];
- private static final Class[] mConstructorSignature = new Class[] {
+ private static final Class<?>[] mConstructorSignature = new Class[] {
Context.class, AttributeSet.class};
- private static final HashMap<String, Constructor> sConstructorMap =
- new HashMap<String, Constructor>();
+ private static final HashMap<String, Constructor<? extends View>> sConstructorMap =
+ new HashMap<String, Constructor<? extends View>>();
private HashMap<String, Boolean> mFilterMap;
@@ -453,18 +453,18 @@ public abstract class LayoutInflater {
* @param name The full name of the class to be instantiated.
* @param attrs The XML attributes supplied for this instance.
*
- * @return View The newly instantied view, or null.
+ * @return View The newly instantiated view, or null.
*/
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
- Constructor constructor = sConstructorMap.get(name);
- Class clazz = null;
+ Constructor<? extends View> constructor = sConstructorMap.get(name);
+ Class<? extends View> clazz = null;
try {
if (constructor == null) {
// Class not found in the cache, see if it's real, and try to add it
clazz = mContext.getClassLoader().loadClass(
- prefix != null ? (prefix + name) : name);
+ prefix != null ? (prefix + name) : name).asSubclass(View.class);
if (mFilter != null && clazz != null) {
boolean allowed = mFilter.onLoadClass(clazz);
@@ -482,7 +482,7 @@ public abstract class LayoutInflater {
if (allowedState == null) {
// New class -- remember whether it is allowed
clazz = mContext.getClassLoader().loadClass(
- prefix != null ? (prefix + name) : name);
+ prefix != null ? (prefix + name) : name).asSubclass(View.class);
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
mFilterMap.put(name, allowed);
@@ -497,7 +497,7 @@ public abstract class LayoutInflater {
Object[] args = mConstructorArgs;
args[1] = attrs;
- return (View) constructor.newInstance(args);
+ return constructor.newInstance(args);
} catch (NoSuchMethodException e) {
InflateException ie = new InflateException(attrs.getPositionDescription()
@@ -506,6 +506,13 @@ public abstract class LayoutInflater {
ie.initCause(e);
throw ie;
+ } catch (ClassCastException e) {
+ // If loaded class is not a View subclass
+ InflateException ie = new InflateException(attrs.getPositionDescription()
+ + ": Class is not a View "
+ + (prefix != null ? (prefix + name) : name));
+ ie.initCause(e);
+ throw ie;
} catch (ClassNotFoundException e) {
// If loadClass fails, we should propagate the exception.
throw e;