Adjust standard Transition structure

- Expose ChangeBounds#setResizeClip
- Expose Visibility transition
- Fade extends Visibility
- The internal constructor of Transition is hidden from external
  descendants

Change-Id: Iab1b14a86edfbc89f1aa8d3386a177e542a1b741
diff --git a/api/current.txt b/api/current.txt
index b16f3892..2a73e14 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -892,13 +892,12 @@
     ctor public ChangeBounds();
     method public void captureEndValues(android.support.transition.TransitionValues);
     method public void captureStartValues(android.support.transition.TransitionValues);
+    method public void setResizeClip(boolean);
   }
 
-  public class Fade extends android.support.transition.Transition {
+  public class Fade extends android.support.transition.Visibility {
     ctor public Fade(int);
     ctor public Fade();
-    method public void captureEndValues(android.support.transition.TransitionValues);
-    method public void captureStartValues(android.support.transition.TransitionValues);
     field public static final int IN = 1; // 0x1
     field public static final int OUT = 2; // 0x2
   }
@@ -916,7 +915,6 @@
 
   public abstract class Transition {
     ctor public Transition();
-    ctor protected Transition(boolean);
     method public android.support.transition.Transition addListener(android.support.transition.Transition.TransitionListener);
     method public android.support.transition.Transition addTarget(android.view.View);
     method public android.support.transition.Transition addTarget(int);
@@ -982,6 +980,15 @@
     field public android.view.View view;
   }
 
+  public abstract class Visibility extends android.support.transition.Transition {
+    ctor public Visibility();
+    method public void captureEndValues(android.support.transition.TransitionValues);
+    method public void captureStartValues(android.support.transition.TransitionValues);
+    method public boolean isVisible(android.support.transition.TransitionValues);
+    method public android.animation.Animator onAppear(android.view.ViewGroup, android.support.transition.TransitionValues, int, android.support.transition.TransitionValues, int);
+    method public android.animation.Animator onDisappear(android.view.ViewGroup, android.support.transition.TransitionValues, int, android.support.transition.TransitionValues, int);
+  }
+
 }
 
 package android.support.v13.app {
diff --git a/transition/base/android/support/transition/ChangeBoundsInterface.java b/transition/base/android/support/transition/ChangeBoundsInterface.java
new file mode 100644
index 0000000..3dc5a23
--- /dev/null
+++ b/transition/base/android/support/transition/ChangeBoundsInterface.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.support.transition;
+
+/**
+ * Interface for platform specific ChangeBounds implementations.
+ */
+interface ChangeBoundsInterface {
+
+    void setResizeClip(boolean resizeClip);
+
+}
diff --git a/transition/base/android/support/transition/VisibilityImpl.java b/transition/base/android/support/transition/VisibilityImpl.java
new file mode 100644
index 0000000..88c8c4b
--- /dev/null
+++ b/transition/base/android/support/transition/VisibilityImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.support.transition;
+
+import android.animation.Animator;
+import android.view.ViewGroup;
+
+/**
+ * Interface for platform specific Visibility implementations on top of {@link TransitionImpl}.
+ */
+interface VisibilityImpl {
+
+    boolean isVisible(TransitionValues values);
+
+    Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility);
+
+    Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility);
+
+}
diff --git a/transition/base/android/support/transition/VisibilityInterface.java b/transition/base/android/support/transition/VisibilityInterface.java
new file mode 100644
index 0000000..69fdf4e0
--- /dev/null
+++ b/transition/base/android/support/transition/VisibilityInterface.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.support.transition;
+
+import android.animation.Animator;
+import android.view.ViewGroup;
+
+/**
+ * Used to reference android.support.transition.Visibility in a backward compatible manner.
+ */
+interface VisibilityInterface extends TransitionInterface {
+
+    boolean isVisible(TransitionValues values);
+
+    Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility);
+
+    Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility);
+
+}
diff --git a/transition/ics/android/support/transition/ChangeBoundsIcs.java b/transition/ics/android/support/transition/ChangeBoundsIcs.java
index 9b070fe..4f52c7d 100644
--- a/transition/ics/android/support/transition/ChangeBoundsIcs.java
+++ b/transition/ics/android/support/transition/ChangeBoundsIcs.java
@@ -16,10 +16,15 @@
 
 package android.support.transition;
 
-class ChangeBoundsIcs extends TransitionIcs {
+class ChangeBoundsIcs extends TransitionIcs implements ChangeBoundsInterface {
 
     public ChangeBoundsIcs(TransitionInterface transition) {
         init(transition, new ChangeBoundsPort());
     }
 
+    @Override
+    public void setResizeClip(boolean resizeClip) {
+        ((ChangeBoundsPort) mTransition).setResizeClip(resizeClip);
+    }
+
 }
diff --git a/transition/ics/android/support/transition/FadeIcs.java b/transition/ics/android/support/transition/FadeIcs.java
index e72a28f..28ed45d 100644
--- a/transition/ics/android/support/transition/FadeIcs.java
+++ b/transition/ics/android/support/transition/FadeIcs.java
@@ -16,7 +16,10 @@
 
 package android.support.transition;
 
-class FadeIcs extends TransitionIcs {
+import android.animation.Animator;
+import android.view.ViewGroup;
+
+class FadeIcs extends TransitionIcs implements VisibilityImpl {
 
     public FadeIcs(TransitionInterface transition) {
         init(transition, new FadePort());
@@ -26,4 +29,23 @@
         init(transition, new FadePort(fadingMode));
     }
 
+    @Override
+    public boolean isVisible(TransitionValues values) {
+        return ((FadePort) mTransition).isVisible(values);
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        return ((FadePort) mTransition).onAppear(sceneRoot, startValues, startVisibility,
+                endValues, endVisibility);
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+            int startVisibility, TransitionValues endValues, int endVisibility) {
+        return ((FadePort) mTransition).onDisappear(sceneRoot, startValues, startVisibility,
+                startValues, startVisibility);
+    }
+
 }
diff --git a/transition/ics/android/support/transition/TransitionIcs.java b/transition/ics/android/support/transition/TransitionIcs.java
index f5215df..6a78a18 100644
--- a/transition/ics/android/support/transition/TransitionIcs.java
+++ b/transition/ics/android/support/transition/TransitionIcs.java
@@ -27,7 +27,9 @@
 class TransitionIcs extends TransitionImpl {
 
     /* package */ TransitionPort mTransition;
-    private TransitionInterface mExternalTransition;
+
+    /* package */ TransitionInterface mExternalTransition;
+
     private CompatListener mCompatListener;
 
     @Override
diff --git a/transition/ics/android/support/transition/VisibilityIcs.java b/transition/ics/android/support/transition/VisibilityIcs.java
new file mode 100644
index 0000000..28c6e61
--- /dev/null
+++ b/transition/ics/android/support/transition/VisibilityIcs.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 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.support.transition;
+
+import android.animation.Animator;
+import android.view.ViewGroup;
+
+class VisibilityIcs extends TransitionIcs implements VisibilityImpl {
+
+    @Override
+    public void init(TransitionInterface external, Object internal) {
+        mExternalTransition = external;
+        if (internal == null) {
+            mTransition = new VisibilityWrapper((VisibilityInterface) external);
+        } else {
+            mTransition = (VisibilityPort) internal;
+        }
+    }
+
+    @Override
+    public boolean isVisible(TransitionValues values) {
+        return ((VisibilityPort) mTransition).isVisible(values);
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        return ((VisibilityPort) mTransition).onAppear(sceneRoot, startValues, startVisibility,
+                endValues, endVisibility);
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+            int startVisibility, TransitionValues endValues, int endVisibility) {
+        return ((VisibilityPort) mTransition).onDisappear(sceneRoot, startValues, startVisibility,
+                endValues, endVisibility);
+    }
+
+    private static class VisibilityWrapper extends VisibilityPort {
+
+        private VisibilityInterface mVisibility;
+
+        VisibilityWrapper(VisibilityInterface visibility) {
+            mVisibility = visibility;
+        }
+
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            mVisibility.captureStartValues(transitionValues);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            mVisibility.captureEndValues(transitionValues);
+        }
+
+        @Override
+        public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+                TransitionValues endValues) {
+            return mVisibility.createAnimator(sceneRoot, startValues, endValues);
+        }
+
+        @Override
+        public boolean isVisible(TransitionValues values) {
+            return mVisibility.isVisible(values);
+        }
+
+        @Override
+        public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues,
+                int startVisibility,
+                TransitionValues endValues, int endVisibility) {
+            return mVisibility.onAppear(sceneRoot, startValues, startVisibility,
+                    endValues, endVisibility);
+        }
+
+        @Override
+        public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+                int startVisibility, TransitionValues endValues, int endVisibility) {
+            return mVisibility.onDisappear(sceneRoot, startValues, startVisibility,
+                    endValues, endVisibility);
+        }
+
+    }
+
+}
diff --git a/transition/kitkat/android/support/transition/ChangeBoundsKitKat.java b/transition/kitkat/android/support/transition/ChangeBoundsKitKat.java
index 3f453ab..704c32f5 100644
--- a/transition/kitkat/android/support/transition/ChangeBoundsKitKat.java
+++ b/transition/kitkat/android/support/transition/ChangeBoundsKitKat.java
@@ -16,10 +16,15 @@
 
 package android.support.transition;
 
-class ChangeBoundsKitKat extends TransitionKitKat {
+class ChangeBoundsKitKat extends TransitionKitKat implements ChangeBoundsInterface {
 
     public ChangeBoundsKitKat(TransitionInterface transition) {
         init(transition, new android.transition.ChangeBounds());
     }
 
+    @Override
+    public void setResizeClip(boolean resizeClip) {
+        ((android.transition.ChangeBounds) mTransition).setResizeClip(resizeClip);
+    }
+
 }
diff --git a/transition/kitkat/android/support/transition/FadeKitKat.java b/transition/kitkat/android/support/transition/FadeKitKat.java
index 0e378fd..7edd220 100644
--- a/transition/kitkat/android/support/transition/FadeKitKat.java
+++ b/transition/kitkat/android/support/transition/FadeKitKat.java
@@ -16,7 +16,10 @@
 
 package android.support.transition;
 
-class FadeKitKat extends TransitionKitKat {
+import android.animation.Animator;
+import android.view.ViewGroup;
+
+class FadeKitKat extends TransitionKitKat implements VisibilityImpl {
 
     public FadeKitKat(TransitionInterface transition) {
         init(transition, new android.transition.Fade());
@@ -26,4 +29,25 @@
         init(transition, new android.transition.Fade(fadingMode));
     }
 
+    @Override
+    public boolean isVisible(TransitionValues values) {
+        return ((android.transition.Fade) mTransition).isVisible(convertToPlatform(values));
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        return ((android.transition.Fade) mTransition).onAppear(sceneRoot,
+                convertToPlatform(startValues), startVisibility,
+                convertToPlatform(endValues), endVisibility);
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+            int startVisibility, TransitionValues endValues, int endVisibility) {
+        return ((android.transition.Fade) mTransition).onDisappear(sceneRoot,
+                convertToPlatform(startValues), startVisibility,
+                convertToPlatform(endValues), endVisibility);
+    }
+
 }
diff --git a/transition/kitkat/android/support/transition/TransitionKitKat.java b/transition/kitkat/android/support/transition/TransitionKitKat.java
index 0a0e4a6..78e4b767 100644
--- a/transition/kitkat/android/support/transition/TransitionKitKat.java
+++ b/transition/kitkat/android/support/transition/TransitionKitKat.java
@@ -29,11 +29,11 @@
 
     /* package */ android.transition.Transition mTransition;
 
-    private TransitionInterface mExternalTransition;
+    /* package */ TransitionInterface mExternalTransition;
 
     private CompatListener mCompatListener;
 
-    private static void copyValues(android.transition.TransitionValues source,
+    static void copyValues(android.transition.TransitionValues source,
             android.support.transition.TransitionValues dest) {
         if (source == null) {
             return;
@@ -44,7 +44,7 @@
         }
     }
 
-    private static void copyValues(android.support.transition.TransitionValues source,
+    static void copyValues(android.support.transition.TransitionValues source,
             android.transition.TransitionValues dest) {
         if (source == null) {
             return;
@@ -55,6 +55,43 @@
         }
     }
 
+    static void wrapCaptureStartValues(TransitionInterface transition,
+            android.transition.TransitionValues transitionValues) {
+        android.support.transition.TransitionValues externalValues =
+                new android.support.transition.TransitionValues();
+        copyValues(transitionValues, externalValues);
+        transition.captureStartValues(externalValues);
+        copyValues(externalValues, transitionValues);
+    }
+
+    static void wrapCaptureEndValues(TransitionInterface transition,
+            android.transition.TransitionValues transitionValues) {
+        android.support.transition.TransitionValues externalValues =
+                new android.support.transition.TransitionValues();
+        copyValues(transitionValues, externalValues);
+        transition.captureEndValues(externalValues);
+        copyValues(externalValues, transitionValues);
+    }
+
+    static TransitionValues convertToSupport(android.transition.TransitionValues values) {
+        if (values == null) {
+            return null;
+        }
+        TransitionValues supportValues = new TransitionValues();
+        copyValues(values, supportValues);
+        return supportValues;
+    }
+
+    static android.transition.TransitionValues convertToPlatform(TransitionValues values) {
+        if (values == null) {
+            return null;
+        }
+        android.transition.TransitionValues platformValues
+                = new android.transition.TransitionValues();
+        copyValues(values, platformValues);
+        return platformValues;
+    }
+
     @Override
     public void init(TransitionInterface external, Object internal) {
         mExternalTransition = external;
@@ -265,42 +302,20 @@
 
         @Override
         public void captureStartValues(android.transition.TransitionValues transitionValues) {
-            android.support.transition.TransitionValues externalValues =
-                    new android.support.transition.TransitionValues();
-            copyValues(transitionValues, externalValues);
-            mTransition.captureStartValues(externalValues);
-            copyValues(externalValues, transitionValues);
+            wrapCaptureStartValues(mTransition, transitionValues);
         }
 
         @Override
         public void captureEndValues(android.transition.TransitionValues transitionValues) {
-            android.support.transition.TransitionValues externalValues =
-                    new android.support.transition.TransitionValues();
-            copyValues(transitionValues, externalValues);
-            mTransition.captureEndValues(externalValues);
-            copyValues(externalValues, transitionValues);
+            wrapCaptureEndValues(mTransition, transitionValues);
         }
 
         @Override
         public Animator createAnimator(ViewGroup sceneRoot,
                 android.transition.TransitionValues startValues,
                 android.transition.TransitionValues endValues) {
-            android.support.transition.TransitionValues externalStartValues;
-            android.support.transition.TransitionValues externalEndValues;
-            if (startValues != null) {
-                externalStartValues = new android.support.transition.TransitionValues();
-                copyValues(startValues, externalStartValues);
-            } else {
-                externalStartValues = null;
-            }
-            if (endValues != null) {
-                externalEndValues = new android.support.transition.TransitionValues();
-                copyValues(endValues, externalEndValues);
-            } else {
-                externalEndValues = null;
-            }
-            return mTransition.createAnimator(sceneRoot, externalStartValues,
-                    externalEndValues);
+            return mTransition.createAnimator(sceneRoot, convertToSupport(startValues),
+                    convertToSupport(endValues));
         }
 
     }
diff --git a/transition/kitkat/android/support/transition/VisibilityKitKat.java b/transition/kitkat/android/support/transition/VisibilityKitKat.java
new file mode 100644
index 0000000..8437a76
--- /dev/null
+++ b/transition/kitkat/android/support/transition/VisibilityKitKat.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 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.support.transition;
+
+import android.animation.Animator;
+import android.view.ViewGroup;
+
+class VisibilityKitKat extends TransitionKitKat implements VisibilityImpl {
+
+    @Override
+    public void init(TransitionInterface external, Object internal) {
+        mExternalTransition = external;
+        if (internal == null) {
+            mTransition = new VisibilityWrapper((VisibilityInterface) external);
+        } else {
+            mTransition = (android.transition.Visibility) internal;
+        }
+    }
+
+    @Override
+    public boolean isVisible(TransitionValues values) {
+        return ((android.transition.Visibility) mTransition).isVisible(convertToPlatform(values));
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        return ((android.transition.Visibility) mTransition).onAppear(sceneRoot,
+                convertToPlatform(startValues), startVisibility,
+                convertToPlatform(endValues), endVisibility);
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+            int startVisibility, TransitionValues endValues, int endVisibility) {
+        return ((android.transition.Visibility) mTransition).onDisappear(sceneRoot,
+                convertToPlatform(startValues), startVisibility,
+                convertToPlatform(endValues), endVisibility);
+    }
+
+    private static class VisibilityWrapper extends android.transition.Visibility {
+
+        private final VisibilityInterface mVisibility;
+
+        VisibilityWrapper(VisibilityInterface visibility) {
+            mVisibility = visibility;
+        }
+
+        @Override
+        public void captureStartValues(android.transition.TransitionValues transitionValues) {
+            wrapCaptureStartValues(mVisibility, transitionValues);
+        }
+
+        @Override
+        public void captureEndValues(android.transition.TransitionValues transitionValues) {
+            wrapCaptureEndValues(mVisibility, transitionValues);
+        }
+
+        @Override
+        public Animator createAnimator(ViewGroup sceneRoot,
+                android.transition.TransitionValues startValues,
+                android.transition.TransitionValues endValues) {
+            return mVisibility.createAnimator(sceneRoot, convertToSupport(startValues),
+                    convertToSupport(endValues));
+        }
+
+        @Override
+        public boolean isVisible(android.transition.TransitionValues values) {
+            if (values == null) {
+                return false;
+            }
+            TransitionValues externalValues = new TransitionValues();
+            copyValues(values, externalValues);
+            return mVisibility.isVisible(externalValues);
+        }
+
+        @Override
+        public Animator onAppear(ViewGroup sceneRoot,
+                android.transition.TransitionValues startValues, int startVisibility,
+                android.transition.TransitionValues endValues, int endVisibility) {
+            return mVisibility.onAppear(sceneRoot, convertToSupport(startValues), startVisibility,
+                    convertToSupport(endValues), endVisibility);
+        }
+
+        @Override
+        public Animator onDisappear(ViewGroup sceneRoot,
+                android.transition.TransitionValues startValues, int startVisibility,
+                android.transition.TransitionValues endValues, int endVisibility) {
+            return mVisibility.onDisappear(sceneRoot, convertToSupport(startValues),
+                    startVisibility,
+                    convertToSupport(endValues), endVisibility);
+        }
+
+    }
+
+}
diff --git a/transition/src/android/support/transition/ChangeBounds.java b/transition/src/android/support/transition/ChangeBounds.java
index abed1c1..f29f056 100644
--- a/transition/src/android/support/transition/ChangeBounds.java
+++ b/transition/src/android/support/transition/ChangeBounds.java
@@ -56,4 +56,21 @@
         return mImpl.createAnimator(sceneRoot, startValues, endValues);
     }
 
+    /**
+     * When <code>resizeClip</code> is true, ChangeBounds resizes the view using the clipBounds
+     * instead of changing the dimensions of the view during the animation. When
+     * <code>resizeClip</code> is false, ChangeBounds resizes the View by changing its dimensions.
+     *
+     * <p>When resizeClip is set to true, the clip bounds is modified by ChangeBounds. Therefore,
+     * {@link android.transition.ChangeClipBounds} is not compatible with ChangeBounds
+     * in this mode.</p>
+     *
+     * @param resizeClip Used to indicate whether the view bounds should be modified or the
+     *                   clip bounds should be modified by ChangeBounds.
+     * @see android.view.View#setClipBounds(android.graphics.Rect)
+     */
+    public void setResizeClip(boolean resizeClip) {
+        ((ChangeBoundsInterface) mImpl).setResizeClip(resizeClip);
+    }
+
 }
diff --git a/transition/src/android/support/transition/Fade.java b/transition/src/android/support/transition/Fade.java
index efc71ea..1aaa1ec 100644
--- a/transition/src/android/support/transition/Fade.java
+++ b/transition/src/android/support/transition/Fade.java
@@ -50,7 +50,7 @@
  *
  * <p>Unlike the platform version, this does not support use in XML resources.</p>
  */
-public class Fade extends Transition {
+public class Fade extends Visibility {
 
     /**
      * Fading mode used in {@link #Fade(int)} to make the transition
diff --git a/transition/src/android/support/transition/Transition.java b/transition/src/android/support/transition/Transition.java
index 42e1e19..f4b904c 100644
--- a/transition/src/android/support/transition/Transition.java
+++ b/transition/src/android/support/transition/Transition.java
@@ -69,7 +69,7 @@
     }
 
     // Hidden constructor for built-in transitions
-    protected Transition(boolean deferred) {
+    Transition(boolean deferred) {
         if (!deferred) {
             if (Build.VERSION.SDK_INT >= 23) {
                 mImpl = new TransitionApi23();
@@ -137,7 +137,7 @@
      * Views with different IDs, or no IDs whatsoever, will be ignored.
      *
      * <p>Note that using ids to specify targets implies that ids should be unique
-     * within the view hierarchy underneat the scene root.</p>
+     * within the view hierarchy underneath the scene root.</p>
      *
      * @param targetId The id of a target view, must be a positive number.
      * @return The Transition to which the targetId is added.
diff --git a/transition/src/android/support/transition/Visibility.java b/transition/src/android/support/transition/Visibility.java
new file mode 100644
index 0000000..54b26e4
--- /dev/null
+++ b/transition/src/android/support/transition/Visibility.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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.support.transition;
+
+import android.animation.Animator;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * This transition tracks changes to the visibility of target views in the
+ * start and end scenes. Visibility is determined not just by the
+ * {@link View#setVisibility(int)} state of views, but also whether
+ * views exist in the current view hierarchy. The class is intended to be a
+ * utility for subclasses such as {@link FadePort}, which use this visibility
+ * information to determine the specific animations to run when visibility
+ * changes occur. Subclasses should implement one or both of the methods
+ * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)},
+ * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)},
+ */
+public abstract class Visibility extends Transition implements VisibilityInterface {
+
+    public Visibility() {
+        this(false);
+    }
+
+    Visibility(boolean deferred) {
+        super(true);
+        if (!deferred) {
+            if (Build.VERSION.SDK_INT >= 19) {
+                mImpl = new VisibilityKitKat();
+            } else {
+                mImpl = new VisibilityIcs();
+            }
+            mImpl.init(this);
+        }
+    }
+
+    @Override
+    public void captureEndValues(@NonNull TransitionValues transitionValues) {
+        mImpl.captureEndValues(transitionValues);
+    }
+
+    @Override
+    public void captureStartValues(@NonNull TransitionValues transitionValues) {
+        mImpl.captureStartValues(transitionValues);
+    }
+
+    /**
+     * Returns whether the view is 'visible' according to the given values
+     * object. This is determined by testing the same properties in the values
+     * object that are used to determine whether the object is appearing or
+     * disappearing in the {@link
+     * Transition#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
+     * method. This method can be called by, for example, subclasses that want
+     * to know whether the object is visible in the same way that Visibility
+     * determines it for the actual animation.
+     *
+     * @param values The TransitionValues object that holds the information by
+     *               which visibility is determined.
+     * @return True if the view reference by <code>values</code> is visible,
+     * false otherwise.
+     */
+    @Override
+    public boolean isVisible(TransitionValues values) {
+        return ((VisibilityImpl) mImpl).isVisible(values);
+    }
+
+    /**
+     * The default implementation of this method does nothing. Subclasses
+     * should override if they need to create an Animator when targets appear.
+     * The method should only be called by the Visibility class; it is
+     * not intended to be called from external classes.
+     *
+     * @param sceneRoot       The root of the transition hierarchy
+     * @param startValues     The target values in the start scene
+     * @param startVisibility The target visibility in the start scene
+     * @param endValues       The target values in the end scene
+     * @param endVisibility   The target visibility in the end scene
+     * @return An Animator to be started at the appropriate time in the
+     * overall transition for this scene change. A null value means no animation
+     * should be run.
+     */
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
+            TransitionValues endValues, int endVisibility) {
+        return ((VisibilityImpl) mImpl).onAppear(sceneRoot, startValues, startVisibility,
+                endValues, endVisibility);
+    }
+
+    /**
+     * The default implementation of this method does nothing. Subclasses
+     * should override if they need to create an Animator when targets disappear.
+     * The method should only be called by the Visibility class; it is
+     * not intended to be called from external classes.
+     *
+     * @param sceneRoot       The root of the transition hierarchy
+     * @param startValues     The target values in the start scene
+     * @param startVisibility The target visibility in the start scene
+     * @param endValues       The target values in the end scene
+     * @param endVisibility   The target visibility in the end scene
+     * @return An Animator to be started at the appropriate time in the
+     * overall transition for this scene change. A null value means no animation
+     * should be run.
+     */
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+            int startVisibility, TransitionValues endValues, int endVisibility) {
+        return ((VisibilityImpl) mImpl).onDisappear(sceneRoot, startValues, startVisibility,
+                endValues, endVisibility);
+    }
+
+    // TODO: Implement API 21; onAppear (4 params), onDisappear (4 params), getMode, setMode
+    // TODO: Implement API 23; isTransitionRequired
+
+}