Merge "Add mechanism for Transitions to target a class."
diff --git a/api/current.txt b/api/current.txt
index 50339f5..54c9d90 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28030,6 +28030,7 @@
     ctor public Transition();
     method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
     method public android.transition.Transition addTarget(int);
+    method public android.transition.Transition addTarget(java.lang.Class);
     method public android.transition.Transition addTarget(android.view.View);
     method public boolean canRemoveViews();
     method public abstract void captureEndValues(android.transition.TransitionValues);
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index b93312bf..2549fde 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -88,8 +88,8 @@
  * transition uses a fadingMode of {@link Fade#OUT} instead of the default
  * out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
  * takes a set of {@link android.R.styleable#TransitionTarget target} tags, each
- * of which lists a specific <code>targetId</code>, <code>excludeId</code>, or
- * <code>excludeClass</code>, which this transition acts upon.
+ * of which lists a specific <code>targetId</code>, <code>targetClass</code>,
+ * <code>excludeId</code>, or <code>excludeClass</code>, which this transition acts upon.
  * Use of targets is optional, but can be used to either limit the time spent checking
  * attributes on unchanging views, or limiting the types of animations run on specific views.
  * In this case, we know that only the <code>grayscaleContainer</code> will be
@@ -116,6 +116,7 @@
     ArrayList<Integer> mTargetIdExcludes = null;
     ArrayList<View> mTargetExcludes = null;
     ArrayList<Class> mTargetTypeExcludes = null;
+    ArrayList<Class> mTargetTypes = null;
     ArrayList<Integer> mTargetIdChildExcludes = null;
     ArrayList<View> mTargetChildExcludes = null;
     ArrayList<Class> mTargetTypeChildExcludes = null;
@@ -569,19 +570,15 @@
                 }
             }
         }
-        if (mTargetIds.size() == 0 && mTargets.size() == 0) {
+        if (mTargetIds.size() == 0 && mTargets.size() == 0 && mTargetTypes == null) {
             return true;
         }
-        if (mTargetIds.size() > 0) {
-            for (int i = 0; i < mTargetIds.size(); ++i) {
-                if (mTargetIds.get(i) == targetId) {
-                    return true;
-                }
-            }
+        if (mTargetIds.contains((int) targetId) || mTargets.contains(target)) {
+            return true;
         }
-        if (target != null && mTargets.size() > 0) {
-            for (int i = 0; i < mTargets.size(); ++i) {
-                if (mTargets.get(i) == target) {
+        if (mTargetTypes != null) {
+            for (int i = 0; i < mTargetTypes.size(); ++i) {
+                if (mTargetTypes.get(i).isInstance(target)) {
                     return true;
                 }
             }
@@ -727,6 +724,36 @@
     }
 
     /**
+     * Adds the Class of a target view that this Transition is interested in
+     * animating. By default, there are no targetTypes, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targetTypes constrains
+     * the Transition to only listen for, and act on, views with these classes.
+     * Views with different classes will be ignored.
+     *
+     * <p>Note that any View that can be cast to targetType will be included, so
+     * if targetType is <code>View.class</code>, all Views will be included.</p>
+     *
+     * @see #addTarget(int)
+     * @see #addTarget(android.view.View)
+     * @see #excludeTarget(Class, boolean)
+     * @see #excludeChildren(Class, boolean)
+     *
+     * @param targetType The type to include when running this transition.
+     * @return The Transition to which the target class was added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(ImageView.class);</code>
+     */
+    public Transition addTarget(Class targetType) {
+        if (mTargetTypes == null) {
+            mTargetTypes = new ArrayList<Class>();
+        }
+        mTargetTypes.add(targetType);
+        return this;
+    }
+
+    /**
      * Removes the given targetId from the list of ids that this Transition
      * is interested in animating.
      *
@@ -1116,9 +1143,6 @@
         if (view == null) {
             return;
         }
-        if (!isValidTarget(view, view.getId())) {
-            return;
-        }
         boolean isListViewItem = false;
         if (view.getParent() instanceof ListView) {
             isListViewItem = true;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 2bdba81..a5e960a 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -231,22 +231,24 @@
                         com.android.internal.R.styleable.TransitionTarget_targetId, -1);
                 if (id >= 0) {
                     transition.addTarget(id);
+                } else if ((id = a.getResourceId(
+                        com.android.internal.R.styleable.TransitionTarget_excludeId, -1)) >= 0) {
+                    transition.excludeTarget(id, true);
                 } else {
-                    id = a.getResourceId(
-                            com.android.internal.R.styleable.TransitionTarget_excludeId, -1);
-                    if (id >= 0) {
-                        transition.excludeTarget(id, true);
-                    } else {
-                        String className = a.getString(
-                                com.android.internal.R.styleable.TransitionTarget_excludeClass);
+                    String className = a.getString(
+                            com.android.internal.R.styleable.TransitionTarget_excludeClass);
+                    try {
                         if (className != null) {
-                            try {
-                                Class clazz = Class.forName(className);
-                                transition.excludeTarget(clazz, true);
-                            } catch (ClassNotFoundException e) {
-                                throw new RuntimeException("Could not create " + className, e);
-                            }
+                            Class clazz = Class.forName(className);
+                            transition.excludeTarget(clazz, true);
+                        } else if ((className = a.getString(
+                                com.android.internal.R.styleable.TransitionTarget_targetClass))
+                                != null) {
+                            Class clazz = Class.forName(className);
+                            transition.addTarget(clazz);
                         }
+                    } catch (ClassNotFoundException e) {
+                        throw new RuntimeException("Could not create " + className, e);
                     }
                 }
             } else {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0a3ca2a..efc1b55 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5029,6 +5029,8 @@
         <attr name="excludeId" format="reference" />
         <!-- The fully-qualified name of the Class to exclude from this transition. -->
         <attr name="excludeClass" format="string" />
+        <!-- The fully-qualified name of the Class to include in this transition. -->
+        <attr name="targetClass" />
     </declare-styleable>
 
     <!-- Use <code>set</code> as the root tag of the XML resource that