From 0633549799ec02e8aaea3242ea66bd501f3bb604 Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Thu, 6 Jan 2011 18:14:35 -0800 Subject: [PATCH] Removed XmlAdapters from frameworks. Has been moved to samples. Change-Id: Icc0530d78df9755a4a1fe9314fa557a91da408c6 --- api/current.xml | 2 +- core/java/android/widget/AbsListView.java | 10 - core/java/android/widget/Adapters.java | 1235 --------------------- core/res/res/values/attrs.xml | 71 -- 4 files changed, 1 insertion(+), 1317 deletions(-) delete mode 100644 core/java/android/widget/Adapters.java diff --git a/api/current.xml b/api/current.xml index ae55230a4bb33..bf004c70fa490 100644 --- a/api/current.xml +++ b/api/current.xml @@ -258107,7 +258107,7 @@ deprecated="not deprecated" visibility="public" > - + diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index fa74b4c2900b6..da27ea894b0be 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -738,16 +738,6 @@ public abstract class AbsListView extends AdapterView implements Te boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true); setSmoothScrollbarEnabled(smoothScrollbar); - final int adapterId = a.getResourceId(R.styleable.AbsListView_adapter, 0); - if (adapterId != 0) { - final Context c = context; - post(new Runnable() { - public void run() { - setAdapter(Adapters.loadAdapter(c, adapterId)); - } - }); - } - setChoiceMode(a.getInt(R.styleable.AbsListView_choiceMode, CHOICE_MODE_NONE)); setFastScrollAlwaysVisible( a.getBoolean(R.styleable.AbsListView_fastScrollAlwaysVisible, false)); diff --git a/core/java/android/widget/Adapters.java b/core/java/android/widget/Adapters.java deleted file mode 100644 index 3849aa42c9736..0000000000000 --- a/core/java/android/widget/Adapters.java +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.widget; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import android.app.Activity; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.database.Cursor; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.AsyncTask; -import android.util.AttributeSet; -import android.util.Xml; -import android.view.View; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.HashMap; - -/** - * @hide -- not sure if we really want this in the framework. - * - *

This class can be used to load {@link android.widget.Adapter adapters} defined in - * XML resources. XML-defined adapters can be used to easily create adapters in your - * own application or to pass adapters to other processes.

- * - *

Types of adapters

- *

Adapters defined using XML resources can only be one of the following supported - * types. Arbitrary adapters are not supported to guarantee the safety of the loaded - * code when adapters are loaded across packages.

- *
    - *
  • Cursor adapter: a cursor adapter can be used - * to display the content of a cursor, most often coming from a content provider
  • - *
- *

The complete XML format definition of each adapter type is available below.

- * - * - *

Cursor adapter

- *

A cursor adapter XML definition starts with the - * <cursor-adapter /> - * tag and may contain one or more instances of the following tags:

- * - * - * - *

<cursor-adapter />

- *

The <cursor-adapter /> element defines the beginning of the - * document and supports the following attributes:

- *
    - *
  • android:layout: Reference to the XML layout to be inflated for - * each item of the adapter. This attribute is mandatory.
  • - *
  • android:selection: Selection expression, used when the - * android:uri attribute is defined or when the adapter is loaded with - * {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}. - * This attribute is optional.
  • - *
  • android:sortOrder: Sort expression, used when the - * android:uri attribute is defined or when the adapter is loaded with - * {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}. - * This attribute is optional.
  • - *
  • android:uri: URI of the content provider to query to retrieve a cursor. - * Specifying this attribute is equivalent to calling - * {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}. - * If you call this method, the value of the XML attribute is ignored. This attribute is - * optional.
  • - *
- *

In addition, you can specify one or more instances of - * <select /> and - * <bind /> tags as children - * of <cursor-adapter />.

- * - * - *

<select />

- *

The <select /> tag is used to select columns from the cursor - * when doing the query. This can be very useful when using transformations in the - * <bind /> elements. It can also be very useful if you are providing - * your own binder or - * transformation classes. - * <select /> elements are ignored if you supply the cursor yourself.

- *

The <select /> supports the following attributes:

- *
    - *
  • android:column: Name of the column to select in the cursor during the - * query operation
  • - *
- *

Note: The column named _id is always implicitly - * selected.

- * - * - *

<bind />

- *

The <bind /> tag is used to bind a column from the cursor to - * a {@link android.view.View}. A column bound using this tag is automatically selected - * during the query and a matching - * <select /> tag is therefore - * not required.

- * - *

Each binding is declared as a one to one matching but - * custom binder classes or special - * data transformations can - * allow you to bind several columns to a single view. In this case you must use the - * <select /> tag to make - * sure any required column is part of the query.

- * - *

The <bind /> tag supports the following attributes:

- *
- * - *

In addition, a <bind /> can contain zero or more instances of - * data transformations children - * tags.

- * - * - *

Binding data types

- *

For a binding to occur the data type of the bound column/view pair must be specified. - * The following data types are currently supported:

- *
    - *
  • string: The content of the column is interpreted as a string and must be - * bound to a {@link android.widget.TextView}
  • - *
  • image: The content of the column is interpreted as a blob describing an - * image and must be bound to an {@link android.widget.ImageView}
  • - *
  • image-uri: The content of the column is interpreted as a URI to an image - * and must be bound to an {@link android.widget.ImageView}
  • - *
  • drawable: The content of the column is interpreted as a resource id to a - * drawable and must be bound to an {@link android.widget.ImageView}
  • - *
  • tag: The content of the column is interpreted as a string and will be set as - * the tag (using {@link View#setTag(Object)} of the associated View. This can be used to - * associate meta-data to your view, that can be used for instance by a listener.
  • - *
  • A fully qualified class name: The name of a class corresponding to an implementation of - * {@link android.widget.Adapters.CursorBinder}. Cursor binders can be used to provide - * bindings not supported by default. Custom binders cannot be used with - * {@link android.content.Context#isRestricted() restricted contexts}, for instance in an - * application widget
  • - *
- * - * - *

Binding transformations

- *

When defining a data binding you can specify an optional transformation by using one - * of the following tags as a child of a <bind /> elements:

- *
    - *
  • <map />: Maps a constant string to a string or a resource. Use - * one instance of this tag per value you want to map
  • - *
  • <transform />: Transforms a column's value using an expression - * or an instance of {@link android.widget.Adapters.CursorTransformation}
  • - *
- *

While several <map /> tags can be used at the same time, you cannot - * mix <map /> and <transform /> tags. If several - * <transform /> tags are specified, only the last one is retained.

- * - * - *

<map />

- *

A map element simply specifies a value to match from and a value to match to. When - * a column's value equals the value to match from, it is replaced with the value to match - * to. The following attributes are supported:

- *
    - *
  • android:fromValue: The value to match from. This attribute is mandatory
  • - *
  • android:toValue: The value to match to. This value can be either a string - * or a resource identifier. This value is interpreted as a resource identifier when the - * data binding is of type drawable. This attribute is mandatory
  • - *
- * - *
- *

<transform />

- *

A simple transform that occurs either by calling a specified class or by performing - * simple text substitution. The following attributes are supported:

- *
    - *
  • android:withExpression: The transformation expression. The expression is - * a string containing column names surrounded with curly braces { and }. During the - * transformation each column name is replaced by its value. All columns must have been - * selected in the query. An example of expression is "First name: {first_name}, - * last name: {last_name}". This attribute is mandatory - * if android:withClass is not specified and ignored if android:withClass - * is specified
  • - *
  • android:withClass: A fully qualified class name corresponding to an - * implementation of {@link android.widget.Adapters.CursorTransformation}. Custom - * transformations cannot be used with - * {@link android.content.Context#isRestricted() restricted contexts}, for instance in - * an app widget This attribute is mandatory if android:withExpression is - * not specified
  • - *
- * - *

Example

- *

The following example defines a cursor adapter that queries all the contacts with - * a phone number using the contacts content provider. Each contact is displayed with - * its display name, its favorite status and its photo. To display photos, a custom data - * binder is declared:

- * - *
- * <cursor-adapter xmlns:android="http://schemas.android.com/apk/res/android"
- *     android:uri="content://com.android.contacts/contacts"
- *     android:selection="has_phone_number=1"
- *     android:layout="@layout/contact_item">
- *
- *     <bind android:from="display_name" android:to="@id/name" android:as="string" />
- *     <bind android:from="starred" android:to="@id/star" android:as="drawable">
- *         <map android:fromValue="0" android:toValue="@android:drawable/star_big_off" />
- *         <map android:fromValue="1" android:toValue="@android:drawable/star_big_on" />
- *     </bind>
- *     <bind android:from="_id" android:to="@id/name"
- *              android:as="com.google.android.test.adapters.ContactPhotoBinder" />
- *
- * </cursor-adapter>
- * 
- * - *

Related APIs

- *
    - *
  • {@link android.widget.Adapters#loadAdapter(android.content.Context, int, Object[])}
  • - *
  • {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[])}
  • - *
  • {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}
  • - *
  • {@link android.widget.Adapters.CursorBinder}
  • - *
  • {@link android.widget.Adapters.CursorTransformation}
  • - *
  • {@link android.widget.CursorAdapter}
  • - *
- * - * @see android.widget.Adapter - * @see android.content.ContentProvider - * - * attr ref android.R.styleable#CursorAdapter_layout - * attr ref android.R.styleable#CursorAdapter_selection - * attr ref android.R.styleable#CursorAdapter_sortOrder - * attr ref android.R.styleable#CursorAdapter_uri - * attr ref android.R.styleable#CursorAdapter_BindItem_as - * attr ref android.R.styleable#CursorAdapter_BindItem_from - * attr ref android.R.styleable#CursorAdapter_BindItem_to - * attr ref android.R.styleable#CursorAdapter_MapItem_fromValue - * attr ref android.R.styleable#CursorAdapter_MapItem_toValue - * attr ref android.R.styleable#CursorAdapter_SelectItem_column - * attr ref android.R.styleable#CursorAdapter_TransformItem_withClass - * attr ref android.R.styleable#CursorAdapter_TransformItem_withExpression - */ -@SuppressWarnings({"JavadocReference"}) -public class Adapters { - private static final String ADAPTER_CURSOR = "cursor-adapter"; - - /** - *

Interface used to bind a {@link android.database.Cursor} column to a View. This - * interface can be used to provide bindings for data types not supported by the - * standard implementation of {@link android.widget.Adapters}.

- * - *

A binder is provided with a cursor transformation which may or may not be used - * to transform the value retrieved from the cursor. The transformation is guaranteed - * to never be null so it's always safe to apply the transformation.

- * - *

The binder is associated with a Context but can be re-used with multiple cursors. - * As such, the implementation should make no assumption about the Cursor in use.

- * - * @see android.view.View - * @see android.database.Cursor - * @see android.widget.Adapters.CursorTransformation - */ - public static abstract class CursorBinder { - /** - *

The context associated with this binder.

- */ - protected final Context mContext; - - /** - *

The transformation associated with this binder. This transformation is never - * null and may or may not be applied to the Cursor data during the - * {@link #bind(android.view.View, android.database.Cursor, int)} operation.

- * - * @see #bind(android.view.View, android.database.Cursor, int) - */ - protected final CursorTransformation mTransformation; - - /** - *

Creates a new Cursor binder.

- * - * @param context The context associated with this binder. - * @param transformation The transformation associated with this binder. This - * transformation may or may not be applied by the binder and is guaranteed - * to not be null. - */ - public CursorBinder(Context context, CursorTransformation transformation) { - mContext = context; - mTransformation = transformation; - } - - /** - *

Binds the specified Cursor column to the supplied View. The binding operation - * can query other Cursor columns as needed. During the binding operation, values - * retrieved from the Cursor may or may not be transformed using this binder's - * cursor transformation.

- * - * @param view The view to bind data to. - * @param cursor The cursor to bind data from. - * @param columnIndex The column index in the cursor where the data to bind resides. - * - * @see #mTransformation - * - * @return True if the column was successfully bound to the View, false otherwise. - */ - public abstract boolean bind(View view, Cursor cursor, int columnIndex); - } - - /** - *

Interface used to transform data coming out of a {@link android.database.Cursor} - * before it is bound to a {@link android.view.View}.

- * - *

Transformations are used to transform text-based data (in the form of a String), - * or to transform data into a resource identifier. A default implementation is provided - * to generate resource identifiers.

- * - * @see android.database.Cursor - * @see android.widget.Adapters.CursorBinder - */ - public static abstract class CursorTransformation { - /** - *

The context associated with this transformation.

- */ - protected final Context mContext; - - /** - *

Creates a new Cursor transformation.

- * - * @param context The context associated with this transformation. - */ - public CursorTransformation(Context context) { - mContext = context; - } - - /** - *

Transforms the specified Cursor column into a String. The transformation - * can simply return the content of the column as a String (this is known - * as the identity transformation) or manipulate the content. For instance, - * a transformation can perform text substitutions or concatenate other - * columns with the specified column.

- * - * @param cursor The cursor that contains the data to transform. - * @param columnIndex The index of the column to transform. - * - * @return A String containing the transformed value of the column. - */ - public abstract String transform(Cursor cursor, int columnIndex); - - /** - *

Transforms the specified Cursor column into a resource identifier. - * The default implementation simply interprets the content of the column - * as an integer.

- * - * @param cursor The cursor that contains the data to transform. - * @param columnIndex The index of the column to transform. - * - * @return A resource identifier. - */ - public int transformToResource(Cursor cursor, int columnIndex) { - return cursor.getInt(columnIndex); - } - } - - /** - *

Loads the {@link android.widget.CursorAdapter} defined in the specified - * XML resource. The content of the adapter is loaded from the content provider - * identified by the supplied URI.

- * - *

Note: If the supplied {@link android.content.Context} is - * an {@link android.app.Activity}, the cursor returned by the content provider - * will be automatically managed. Otherwise, you are responsible for managing the - * cursor yourself.

- * - *

The format of the XML definition of the cursor adapter is documented at - * the top of this page.

- * - * @param context The context to load the XML resource from. - * @param id The identifier of the XML resource declaring the adapter. - * @param uri The URI of the content provider. - * @param parameters Optional parameters to pass to the CursorAdapter, used - * to substitute values in the selection expression. - * - * @return A {@link android.widget.CursorAdapter} - * - * @throws IllegalArgumentException If the XML resource does not contain - * a valid <cursor-adapter /> definition. - * - * @see android.content.ContentProvider - * @see android.widget.CursorAdapter - * @see #loadAdapter(android.content.Context, int, Object[]) - */ - public static CursorAdapter loadCursorAdapter(Context context, int id, String uri, - Object... parameters) { - - XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR, - parameters); - - if (uri != null) { - adapter.setUri(uri); - } - adapter.load(); - - return adapter; - } - - /** - *

Loads the {@link android.widget.CursorAdapter} defined in the specified - * XML resource. The content of the adapter is loaded from the specified cursor. - * You are responsible for managing the supplied cursor.

- * - *

The format of the XML definition of the cursor adapter is documented at - * the top of this page.

- * - * @param context The context to load the XML resource from. - * @param id The identifier of the XML resource declaring the adapter. - * @param cursor The cursor containing the data for the adapter. - * @param parameters Optional parameters to pass to the CursorAdapter, used - * to substitute values in the selection expression. - * - * @return A {@link android.widget.CursorAdapter} - * - * @throws IllegalArgumentException If the XML resource does not contain - * a valid <cursor-adapter /> definition. - * - * @see android.content.ContentProvider - * @see android.widget.CursorAdapter - * @see android.database.Cursor - * @see #loadAdapter(android.content.Context, int, Object[]) - */ - public static CursorAdapter loadCursorAdapter(Context context, int id, Cursor cursor, - Object... parameters) { - - XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR, - parameters); - - if (cursor != null) { - adapter.changeCursor(cursor); - } - - return adapter; - } - - /** - *

Loads the adapter defined in the specified XML resource. The XML definition of - * the adapter must follow the format definition of one of the supported adapter - * types described at the top of this page.

- * - *

Note: If the loaded adapter is a {@link android.widget.CursorAdapter} - * and the supplied {@link android.content.Context} is an {@link android.app.Activity}, - * the cursor returned by the content provider will be automatically managed. Otherwise, - * you are responsible for managing the cursor yourself.

- * - * @param context The context to load the XML resource from. - * @param id The identifier of the XML resource declaring the adapter. - * @param parameters Optional parameters to pass to the adapter. - * - * @return An adapter instance. - * - * @see #loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[]) - * @see #loadCursorAdapter(android.content.Context, int, String, Object[]) - */ - public static BaseAdapter loadAdapter(Context context, int id, Object... parameters) { - final BaseAdapter adapter = loadAdapter(context, id, null, parameters); - if (adapter instanceof ManagedAdapter) { - ((ManagedAdapter) adapter).load(); - } - return adapter; - } - - /** - * Loads an adapter from the specified XML resource. The optional assertName can - * be used to exit early if the adapter defined in the XML resource is not of the - * expected type. - * - * @param context The context to associate with the adapter. - * @param id The resource id of the XML document defining the adapter. - * @param assertName The mandatory name of the adapter in the XML document. - * Ignored if null. - * @param parameters Optional parameters passed to the adapter. - * - * @return An instance of {@link android.widget.BaseAdapter}. - */ - private static BaseAdapter loadAdapter(Context context, int id, String assertName, - Object... parameters) { - - XmlResourceParser parser = null; - try { - parser = context.getResources().getXml(id); - return createAdapterFromXml(context, parser, Xml.asAttributeSet(parser), - id, parameters, assertName); - } catch (XmlPullParserException ex) { - Resources.NotFoundException rnf = new Resources.NotFoundException( - "Can't load adapter resource ID " + - context.getResources().getResourceEntryName(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - Resources.NotFoundException rnf = new Resources.NotFoundException( - "Can't load adapter resource ID " + - context.getResources().getResourceEntryName(id)); - rnf.initCause(ex); - throw rnf; - } finally { - if (parser != null) parser.close(); - } - } - - /** - * Generates an adapter using the specified XML parser. This method is responsible - * for choosing the type of the adapter to create based on the content of the - * XML parser. - * - * This method will generate an {@link IllegalArgumentException} if - * assertName is not null and does not match the root tag of the XML - * document. - */ - private static BaseAdapter createAdapterFromXml(Context c, - XmlPullParser parser, AttributeSet attrs, int id, Object[] parameters, - String assertName) throws XmlPullParserException, IOException { - - BaseAdapter adapter = null; - - // Make sure we are on a start tag. - int type; - int depth = parser.getDepth(); - - while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && - type != XmlPullParser.END_DOCUMENT) { - - if (type != XmlPullParser.START_TAG) { - continue; - } - - String name = parser.getName(); - if (assertName != null && !assertName.equals(name)) { - throw new IllegalArgumentException("The adapter defined in " + - c.getResources().getResourceEntryName(id) + " must be a <" + - assertName + " />"); - } - - if (ADAPTER_CURSOR.equals(name)) { - adapter = createCursorAdapter(c, parser, attrs, id, parameters); - } else { - throw new IllegalArgumentException("Unknown adapter name " + parser.getName() + - " in " + c.getResources().getResourceEntryName(id)); - } - } - - return adapter; - - } - - /** - * Creates an XmlCursorAdapter using an XmlCursorAdapterParser. - */ - private static XmlCursorAdapter createCursorAdapter(Context c, XmlPullParser parser, - AttributeSet attrs, int id, Object[] parameters) - throws IOException, XmlPullParserException { - - return new XmlCursorAdapterParser(c, parser, attrs, id).parse(parameters); - } - - /** - * Parser that can generate XmlCursorAdapter instances. This parser is responsible for - * handling all the attributes and child nodes for a <cursor-adapter />. - */ - private static class XmlCursorAdapterParser { - private static final String ADAPTER_CURSOR_BIND = "bind"; - private static final String ADAPTER_CURSOR_SELECT = "select"; - private static final String ADAPTER_CURSOR_AS_STRING = "string"; - private static final String ADAPTER_CURSOR_AS_IMAGE = "image"; - private static final String ADAPTER_CURSOR_AS_TAG = "tag"; - private static final String ADAPTER_CURSOR_AS_IMAGE_URI = "image-uri"; - private static final String ADAPTER_CURSOR_AS_DRAWABLE = "drawable"; - private static final String ADAPTER_CURSOR_MAP = "map"; - private static final String ADAPTER_CURSOR_TRANSFORM = "transform"; - - private final Context mContext; - private final XmlPullParser mParser; - private final AttributeSet mAttrs; - private final int mId; - - private final HashMap mBinders; - private final ArrayList mFrom; - private final ArrayList mTo; - private final CursorTransformation mIdentity; - private final Resources mResources; - - public XmlCursorAdapterParser(Context c, XmlPullParser parser, AttributeSet attrs, int id) { - mContext = c; - mParser = parser; - mAttrs = attrs; - mId = id; - - mResources = mContext.getResources(); - mBinders = new HashMap(); - mFrom = new ArrayList(); - mTo = new ArrayList(); - mIdentity = new IdentityTransformation(mContext); - } - - public XmlCursorAdapter parse(Object[] parameters) - throws IOException, XmlPullParserException { - - Resources resources = mResources; - TypedArray a = resources.obtainAttributes(mAttrs, com.android.internal.R.styleable.CursorAdapter); - - String uri = a.getString(com.android.internal.R.styleable.CursorAdapter_uri); - String selection = a.getString(com.android.internal.R.styleable.CursorAdapter_selection); - String sortOrder = a.getString(com.android.internal.R.styleable.CursorAdapter_sortOrder); - int layout = a.getResourceId(com.android.internal.R.styleable.CursorAdapter_layout, 0); - if (layout == 0) { - throw new IllegalArgumentException("The layout specified in " + - resources.getResourceEntryName(mId) + " does not exist"); - } - - a.recycle(); - - XmlPullParser parser = mParser; - int type; - int depth = parser.getDepth(); - - while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && - type != XmlPullParser.END_DOCUMENT) { - - if (type != XmlPullParser.START_TAG) { - continue; - } - - String name = parser.getName(); - - if (ADAPTER_CURSOR_BIND.equals(name)) { - parseBindTag(); - } else if (ADAPTER_CURSOR_SELECT.equals(name)) { - parseSelectTag(); - } else { - throw new RuntimeException("Unknown tag name " + parser.getName() + " in " + - resources.getResourceEntryName(mId)); - } - } - - String[] fromArray = mFrom.toArray(new String[mFrom.size()]); - int[] toArray = new int[mTo.size()]; - for (int i = 0; i < toArray.length; i++) { - toArray[i] = mTo.get(i); - } - - String[] selectionArgs = null; - if (parameters != null) { - selectionArgs = new String[parameters.length]; - for (int i = 0; i < selectionArgs.length; i++) { - selectionArgs[i] = (String) parameters[i]; - } - } - - return new XmlCursorAdapter(mContext, layout, uri, fromArray, toArray, selection, - selectionArgs, sortOrder, mBinders); - } - - private void parseSelectTag() { - TypedArray a = mResources.obtainAttributes(mAttrs, - com.android.internal.R.styleable.CursorAdapter_SelectItem); - - String fromName = a.getString(com.android.internal.R.styleable.CursorAdapter_SelectItem_column); - if (fromName == null) { - throw new IllegalArgumentException("A select item in " + - mResources.getResourceEntryName(mId) + - " does not have a 'column' attribute"); - } - - a.recycle(); - - mFrom.add(fromName); - mTo.add(View.NO_ID); - } - - private void parseBindTag() throws IOException, XmlPullParserException { - Resources resources = mResources; - TypedArray a = resources.obtainAttributes(mAttrs, - com.android.internal.R.styleable.CursorAdapter_BindItem); - - String fromName = a.getString(com.android.internal.R.styleable.CursorAdapter_BindItem_from); - if (fromName == null) { - throw new IllegalArgumentException("A bind item in " + - resources.getResourceEntryName(mId) + " does not have a 'from' attribute"); - } - - int toName = a.getResourceId(com.android.internal.R.styleable.CursorAdapter_BindItem_to, 0); - if (toName == 0) { - throw new IllegalArgumentException("A bind item in " + - resources.getResourceEntryName(mId) + " does not have a 'to' attribute"); - } - - String asType = a.getString(com.android.internal.R.styleable.CursorAdapter_BindItem_as); - if (asType == null) { - throw new IllegalArgumentException("A bind item in " + - resources.getResourceEntryName(mId) + " does not have an 'as' attribute"); - } - - mFrom.add(fromName); - mTo.add(toName); - mBinders.put(fromName, findBinder(asType)); - - a.recycle(); - } - - private CursorBinder findBinder(String type) throws IOException, XmlPullParserException { - final XmlPullParser parser = mParser; - final Context context = mContext; - CursorTransformation transformation = mIdentity; - - int tagType; - int depth = parser.getDepth(); - - final boolean isDrawable = ADAPTER_CURSOR_AS_DRAWABLE.equals(type); - - while (((tagType = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && tagType != XmlPullParser.END_DOCUMENT) { - - if (tagType != XmlPullParser.START_TAG) { - continue; - } - - String name = parser.getName(); - - if (ADAPTER_CURSOR_TRANSFORM.equals(name)) { - transformation = findTransformation(); - } else if (ADAPTER_CURSOR_MAP.equals(name)) { - if (!(transformation instanceof MapTransformation)) { - transformation = new MapTransformation(context); - } - findMap(((MapTransformation) transformation), isDrawable); - } else { - throw new RuntimeException("Unknown tag name " + parser.getName() + " in " + - context.getResources().getResourceEntryName(mId)); - } - } - - if (ADAPTER_CURSOR_AS_STRING.equals(type)) { - return new StringBinder(context, transformation); - } else if (ADAPTER_CURSOR_AS_TAG.equals(type)) { - return new TagBinder(context, transformation); - } else if (ADAPTER_CURSOR_AS_IMAGE.equals(type)) { - return new ImageBinder(context, transformation); - } else if (ADAPTER_CURSOR_AS_IMAGE_URI.equals(type)) { - return new ImageUriBinder(context, transformation); - } else if (isDrawable) { - return new DrawableBinder(context, transformation); - } else { - return createBinder(type, transformation); - } - } - - private CursorBinder createBinder(String type, CursorTransformation transformation) { - if (mContext.isRestricted()) return null; - - try { - final Class klass = Class.forName(type, true, mContext.getClassLoader()); - if (CursorBinder.class.isAssignableFrom(klass)) { - final Constructor c = klass.getDeclaredConstructor( - Context.class, CursorTransformation.class); - return (CursorBinder) c.newInstance(mContext, transformation); - } - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Cannot instanciate binder type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + type, e); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException("Cannot instanciate binder type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + type, e); - } catch (InvocationTargetException e) { - throw new IllegalArgumentException("Cannot instanciate binder type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + type, e); - } catch (InstantiationException e) { - throw new IllegalArgumentException("Cannot instanciate binder type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + type, e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Cannot instanciate binder type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + type, e); - } - - return null; - } - - private void findMap(MapTransformation transformation, boolean drawable) { - Resources resources = mResources; - - TypedArray a = resources.obtainAttributes(mAttrs, - com.android.internal.R.styleable.CursorAdapter_MapItem); - - String from = a.getString(com.android.internal.R.styleable.CursorAdapter_MapItem_fromValue); - if (from == null) { - throw new IllegalArgumentException("A map item in " + - resources.getResourceEntryName(mId) + - " does not have a 'fromValue' attribute"); - } - - if (!drawable) { - String to = a.getString(com.android.internal.R.styleable.CursorAdapter_MapItem_toValue); - if (to == null) { - throw new IllegalArgumentException("A map item in " + - resources.getResourceEntryName(mId) + - " does not have a 'toValue' attribute"); - } - transformation.addStringMapping(from, to); - } else { - int to = a.getResourceId(com.android.internal.R.styleable.CursorAdapter_MapItem_toValue, 0); - if (to == 0) { - throw new IllegalArgumentException("A map item in " + - resources.getResourceEntryName(mId) + - " does not have a 'toValue' attribute"); - } - transformation.addResourceMapping(from, to); - } - - a.recycle(); - } - - private CursorTransformation findTransformation() { - Resources resources = mResources; - CursorTransformation transformation = null; - TypedArray a = resources.obtainAttributes(mAttrs, - com.android.internal.R.styleable.CursorAdapter_TransformItem); - - String className = a.getString(com.android.internal.R.styleable.CursorAdapter_TransformItem_withClass); - if (className == null) { - String expression = a.getString( - com.android.internal.R.styleable.CursorAdapter_TransformItem_withExpression); - transformation = createExpressionTransformation(expression); - } else if (!mContext.isRestricted()) { - try { - final Class klas = Class.forName(className, true, mContext.getClassLoader()); - if (CursorTransformation.class.isAssignableFrom(klas)) { - final Constructor c = klas.getDeclaredConstructor(Context.class); - transformation = (CursorTransformation) c.newInstance(mContext); - } - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Cannot instanciate transform type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + className, e); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException("Cannot instanciate transform type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + className, e); - } catch (InvocationTargetException e) { - throw new IllegalArgumentException("Cannot instanciate transform type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + className, e); - } catch (InstantiationException e) { - throw new IllegalArgumentException("Cannot instanciate transform type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + className, e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Cannot instanciate transform type in " + - mContext.getResources().getResourceEntryName(mId) + ": " + className, e); - } - } - - a.recycle(); - - if (transformation == null) { - throw new IllegalArgumentException("A transform item in " + - resources.getResourceEntryName(mId) + " must have a 'withClass' or " + - "'withExpression' attribute"); - } - - return transformation; - } - - private CursorTransformation createExpressionTransformation(String expression) { - return new ExpressionTransformation(mContext, expression); - } - } - - /** - * Interface used by adapters that require to be loaded after creation. - */ - private static interface ManagedAdapter { - /** - * Loads the content of the adapter, asynchronously. - */ - void load(); - } - - /** - * Implementation of a Cursor adapter defined in XML. This class is a thin wrapper - * of a SimpleCursorAdapter. The main difference is the ability to handle CursorBinders. - */ - private static class XmlCursorAdapter extends SimpleCursorAdapter implements ManagedAdapter { - private String mUri; - private final String mSelection; - private final String[] mSelectionArgs; - private final String mSortOrder; - private final String[] mColumns; - private final CursorBinder[] mBinders; - private AsyncTask mLoadTask; - - XmlCursorAdapter(Context context, int layout, String uri, String[] from, int[] to, - String selection, String[] selectionArgs, String sortOrder, - HashMap binders) { - - super(context, layout, null, from, to); - mContext = context; - mUri = uri; - mSelection = selection; - mSelectionArgs = selectionArgs; - mSortOrder = sortOrder; - mColumns = new String[from.length + 1]; - // This is mandatory in CursorAdapter - mColumns[0] = "_id"; - System.arraycopy(from, 0, mColumns, 1, from.length); - - CursorBinder basic = new StringBinder(context, new IdentityTransformation(context)); - final int count = from.length; - mBinders = new CursorBinder[count]; - - for (int i = 0; i < count; i++) { - CursorBinder binder = binders.get(from[i]); - if (binder == null) binder = basic; - mBinders[i] = binder; - } - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - final int count = mTo.length; - final int[] from = mFrom; - final int[] to = mTo; - final CursorBinder[] binders = mBinders; - - for (int i = 0; i < count; i++) { - final View v = view.findViewById(to[i]); - if (v != null) { - binders[i].bind(v, cursor, from[i]); - } - } - } - - public void load() { - if (mUri != null) { - mLoadTask = new QueryTask().execute(); - } - } - - void setUri(String uri) { - mUri = uri; - } - - @Override - public void changeCursor(Cursor c) { - if (mLoadTask != null && mLoadTask.getStatus() != QueryTask.Status.FINISHED) { - mLoadTask.cancel(true); - mLoadTask = null; - } - super.changeCursor(c); - } - - class QueryTask extends AsyncTask { - @Override - protected Cursor doInBackground(Void... params) { - if (mContext instanceof Activity) { - return ((Activity) mContext).managedQuery( - Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder); - } else { - return mContext.getContentResolver().query( - Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder); - } - } - - @Override - protected void onPostExecute(Cursor cursor) { - if (!isCancelled()) { - XmlCursorAdapter.super.changeCursor(cursor); - } - } - } - } - - /** - * Identity transformation, returns the content of the specified column as a String, - * without performing any manipulation. This is used when no transformation is specified. - */ - private static class IdentityTransformation extends CursorTransformation { - public IdentityTransformation(Context context) { - super(context); - } - - @Override - public String transform(Cursor cursor, int columnIndex) { - return cursor.getString(columnIndex); - } - } - - /** - * An expression transformation is a simple template based replacement utility. - * In an expression, each segment of the form {([^}]+)} is replaced - * with the value of the column of name $1. - */ - private static class ExpressionTransformation extends CursorTransformation { - private final ExpressionNode mFirstNode = new ConstantExpressionNode(""); - private final StringBuilder mBuilder = new StringBuilder(); - - public ExpressionTransformation(Context context, String expression) { - super(context); - - parse(expression); - } - - private void parse(String expression) { - ExpressionNode node = mFirstNode; - int segmentStart; - int count = expression.length(); - - for (int i = 0; i < count; i++) { - char c = expression.charAt(i); - // Start a column name segment - segmentStart = i; - if (c == '{') { - while (i < count && (c = expression.charAt(i)) != '}') { - i++; - } - // We've reached the end, but the expression didn't close - if (c != '}') { - throw new IllegalStateException("The transform expression contains a " + - "non-closed column name: " + - expression.substring(segmentStart + 1, i)); - } - node.next = new ColumnExpressionNode(expression.substring(segmentStart + 1, i)); - } else { - while (i < count && (c = expression.charAt(i)) != '{') { - i++; - } - node.next = new ConstantExpressionNode(expression.substring(segmentStart, i)); - // Rewind if we've reached a column expression - if (c == '{') i--; - } - node = node.next; - } - } - - @Override - public String transform(Cursor cursor, int columnIndex) { - final StringBuilder builder = mBuilder; - builder.delete(0, builder.length()); - - ExpressionNode node = mFirstNode; - // Skip the first node - while ((node = node.next) != null) { - builder.append(node.asString(cursor)); - } - - return builder.toString(); - } - - static abstract class ExpressionNode { - public ExpressionNode next; - - public abstract String asString(Cursor cursor); - } - - static class ConstantExpressionNode extends ExpressionNode { - private final String mConstant; - - ConstantExpressionNode(String constant) { - mConstant = constant; - } - - @Override - public String asString(Cursor cursor) { - return mConstant; - } - } - - static class ColumnExpressionNode extends ExpressionNode { - private final String mColumnName; - private Cursor mSignature; - private int mColumnIndex = -1; - - ColumnExpressionNode(String columnName) { - mColumnName = columnName; - } - - @Override - public String asString(Cursor cursor) { - if (cursor != mSignature || mColumnIndex == -1) { - mColumnIndex = cursor.getColumnIndex(mColumnName); - mSignature = cursor; - } - - return cursor.getString(mColumnIndex); - } - } - } - - /** - * A map transformation offers a simple mapping between specified String values - * to Strings or integers. - */ - private static class MapTransformation extends CursorTransformation { - private final HashMap mStringMappings; - private final HashMap mResourceMappings; - - public MapTransformation(Context context) { - super(context); - mStringMappings = new HashMap(); - mResourceMappings = new HashMap(); - } - - void addStringMapping(String from, String to) { - mStringMappings.put(from, to); - } - - void addResourceMapping(String from, int to) { - mResourceMappings.put(from, to); - } - - @Override - public String transform(Cursor cursor, int columnIndex) { - final String value = cursor.getString(columnIndex); - final String transformed = mStringMappings.get(value); - return transformed == null ? value : transformed; - } - - @Override - public int transformToResource(Cursor cursor, int columnIndex) { - final String value = cursor.getString(columnIndex); - final Integer transformed = mResourceMappings.get(value); - try { - return transformed == null ? Integer.parseInt(value) : transformed; - } catch (NumberFormatException e) { - return 0; - } - } - } - - /** - * Binds a String to a TextView. - */ - private static class StringBinder extends CursorBinder { - public StringBinder(Context context, CursorTransformation transformation) { - super(context, transformation); - } - - @Override - public boolean bind(View view, Cursor cursor, int columnIndex) { - if (view instanceof TextView) { - final String text = mTransformation.transform(cursor, columnIndex); - ((TextView) view).setText(text); - return true; - } - return false; - } - } - - /** - * Binds an image blob to an ImageView. - */ - private static class ImageBinder extends CursorBinder { - public ImageBinder(Context context, CursorTransformation transformation) { - super(context, transformation); - } - - @Override - public boolean bind(View view, Cursor cursor, int columnIndex) { - if (view instanceof ImageView) { - final byte[] data = cursor.getBlob(columnIndex); - ((ImageView) view).setImageBitmap(BitmapFactory.decodeByteArray(data, 0, - data.length)); - return true; - } - return false; - } - } - - private static class TagBinder extends CursorBinder { - public TagBinder(Context context, CursorTransformation transformation) { - super(context, transformation); - } - - @Override - public boolean bind(View view, Cursor cursor, int columnIndex) { - final String text = mTransformation.transform(cursor, columnIndex); - view.setTag(text); - return true; - } - } - - /** - * Binds an image URI to an ImageView. - */ - private static class ImageUriBinder extends CursorBinder { - public ImageUriBinder(Context context, CursorTransformation transformation) { - super(context, transformation); - } - - @Override - public boolean bind(View view, Cursor cursor, int columnIndex) { - if (view instanceof ImageView) { - ((ImageView) view).setImageURI(Uri.parse( - mTransformation.transform(cursor, columnIndex))); - return true; - } - return false; - } - } - - /** - * Binds a drawable resource identifier to an ImageView. - */ - private static class DrawableBinder extends CursorBinder { - public DrawableBinder(Context context, CursorTransformation transformation) { - super(context, transformation); - } - - @Override - public boolean bind(View view, Cursor cursor, int columnIndex) { - if (view instanceof ImageView) { - final int resource = mTransformation.transformToResource(cursor, columnIndex); - if (resource == 0) return false; - - ((ImageView) view).setImageResource(resource); - return true; - } - return false; - } - } -} diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index f909bd6385118..7275ef49e681f 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2047,9 +2047,6 @@ will use only the number of items in the adapter and the number of items visible on screen to determine the scrollbar's properties. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -