Merge "Cleanup AccessibilityEventCompat and AccessibilityRecordCompat after minSdk 14 bump."
diff --git a/annotations/src/android/support/annotation/GuardedBy.java b/annotations/src/android/support/annotation/GuardedBy.java
new file mode 100644
index 0000000..ee7d77c
--- /dev/null
+++ b/annotations/src/android/support/annotation/GuardedBy.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated method or field can only be accessed when holding the referenced lock.
+ * <p>
+ * Example:
+ * <pre>
+ * final Object objectLock = new Object();
+ *
+ * {@literal @}GuardedBy("objectLock")
+ * volatile Object object;
+ *
+ * Object getObject() {
+ *     synchronized (objectLock) {
+ *         if (object == null) {
+ *             object = new Object();
+ *         }
+ *     }
+ *     return object;
+ * }</pre>
+ */
+@Target({ ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.CLASS)
+public @interface GuardedBy {
+    String value();
+}
diff --git a/api/25.3.0.txt b/api/25.3.0.txt
index ac4bf65..a1ff8b4 100644
--- a/api/25.3.0.txt
+++ b/api/25.3.0.txt
@@ -1,3 +1,75 @@
+package android.support.animation {
+
+  public abstract class DynamicAnimation<T extends android.support.animation.DynamicAnimation<T>> {
+    method public T addEndListener(android.support.animation.DynamicAnimation.OnAnimationEndListener);
+    method public T addUpdateListener(android.support.animation.DynamicAnimation.OnAnimationUpdateListener);
+    method public void cancel();
+    method public boolean isRunning();
+    method public void removeEndListener(android.support.animation.DynamicAnimation.OnAnimationEndListener);
+    method public void removeUpdateListener(android.support.animation.DynamicAnimation.OnAnimationUpdateListener);
+    method public T setMaxValue(float);
+    method public T setMinValue(float);
+    method public T setStartValue(float);
+    method public T setStartVelocity(float);
+    method public void start();
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ALPHA;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCALE_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCALE_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCROLL_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCROLL_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_Z;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty Z;
+  }
+
+  public static abstract interface DynamicAnimation.OnAnimationEndListener {
+    method public abstract void onAnimationEnd(android.support.animation.DynamicAnimation, boolean, float, float);
+  }
+
+  public static abstract interface DynamicAnimation.OnAnimationUpdateListener {
+    method public abstract void onAnimationUpdate(android.support.animation.DynamicAnimation, float, float);
+  }
+
+  public static abstract class DynamicAnimation.ViewProperty {
+  }
+
+  public final class SpringAnimation extends android.support.animation.DynamicAnimation {
+    ctor public SpringAnimation(android.view.View, android.support.animation.DynamicAnimation.ViewProperty);
+    ctor public SpringAnimation(android.view.View, android.support.animation.DynamicAnimation.ViewProperty, float);
+    method public void animateToFinalPosition(float);
+    method public boolean canSkipToEnd();
+    method public android.support.animation.SpringForce getSpring();
+    method public android.support.animation.SpringAnimation setSpring(android.support.animation.SpringForce);
+    method public void skipToEnd();
+  }
+
+  public final class SpringForce {
+    ctor public SpringForce();
+    ctor public SpringForce(float);
+    method public float getDampingRatio();
+    method public float getFinalPosition();
+    method public float getStiffness();
+    method public android.support.animation.SpringForce setDampingRatio(float);
+    method public android.support.animation.SpringForce setFinalPosition(float);
+    method public android.support.animation.SpringForce setStiffness(float);
+    field public static final float DAMPING_RATIO_HIGH_BOUNCY = 0.2f;
+    field public static final float DAMPING_RATIO_LOW_BOUNCY = 0.75f;
+    field public static final float DAMPING_RATIO_MEDIUM_BOUNCY = 0.5f;
+    field public static final float DAMPING_RATIO_NO_BOUNCY = 1.0f;
+    field public static final float STIFFNESS_HIGH = 10000.0f;
+    field public static final float STIFFNESS_LOW = 200.0f;
+    field public static final float STIFFNESS_MEDIUM = 1500.0f;
+    field public static final float STIFFNESS_VERY_LOW = 50.0f;
+  }
+
+}
+
 package android.support.app.recommendation {
 
   public final class ContentRecommendation {
@@ -870,16 +942,34 @@
 
 package android.support.graphics.drawable {
 
-  public class AnimatedVectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon {
+  public abstract interface Animatable2Compat {
+    method public abstract void clearAnimationCallbacks();
+    method public abstract void registerAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public abstract boolean unregisterAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+  }
+
+  public static abstract class Animatable2Compat.AnimationCallback {
+    ctor public Animatable2Compat.AnimationCallback();
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
+  }
+
+  public class AnimatedVectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon implements android.support.graphics.drawable.Animatable2Compat {
+    method public void clearAnimationCallbacks();
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable);
     method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat create(android.content.Context, int);
     method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
+    method public void registerAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable, android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void start();
     method public void stop();
+    method public boolean unregisterAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable, android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
   }
 
    abstract class VectorDrawableCommon extends android.graphics.drawable.Drawable {
@@ -2414,10 +2504,7 @@
   public class BoundsRule {
     ctor public BoundsRule();
     ctor public BoundsRule(android.support.v17.leanback.graphics.BoundsRule);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
     method public void calculateBounds(android.graphics.Rect, android.graphics.Rect);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule bottom;
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule left;
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule right;
@@ -2425,8 +2512,11 @@
   }
 
   public static final class BoundsRule.ValueRule {
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
     method public int getAbsoluteValue();
     method public float getFraction();
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
     method public void setAbsoluteValue(int);
     method public void setFraction(float);
   }
@@ -3532,111 +3622,79 @@
 
   public abstract class Parallax<PropertyT extends android.util.Property> {
     ctor public Parallax();
-    method public void addEffect(android.support.v17.leanback.widget.ParallaxEffect);
-    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue...);
-    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue...);
-    method public abstract PropertyT addProperty(java.lang.String);
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
+    method public final PropertyT addProperty(java.lang.String);
     method public abstract PropertyT createProperty(java.lang.String, int);
     method public java.util.List<android.support.v17.leanback.widget.ParallaxEffect> getEffects();
+    method public abstract float getMaxValue();
     method public final java.util.List<PropertyT> getProperties();
     method public void removeAllEffects();
     method public void removeEffect(android.support.v17.leanback.widget.ParallaxEffect);
     method public void updateValues();
-    method public abstract void verifyProperties() throws java.lang.IllegalStateException;
-  }
-
-  public static abstract class Parallax.FloatParallax<FloatPropertyT extends android.support.v17.leanback.widget.Parallax.FloatProperty> extends android.support.v17.leanback.widget.Parallax {
-    ctor public Parallax.FloatParallax();
-    method public final FloatPropertyT addProperty(java.lang.String);
-    method public abstract float getMaxValue();
-    method public final float getPropertyValue(int);
-    method public final void setPropertyValue(int, float);
-    method public final void verifyProperties() throws java.lang.IllegalStateException;
   }
 
   public static class Parallax.FloatProperty extends android.util.Property {
     ctor public Parallax.FloatProperty(java.lang.String, int);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue at(float, float);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atAbsolute(float);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atFraction(float);
-    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax.FloatParallax);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(float, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax);
     method public final int getIndex();
-    method public final void set(android.support.v17.leanback.widget.Parallax.FloatParallax, java.lang.Float);
+    method public final float getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Float);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, float);
     field public static final float UNKNOWN_AFTER = 3.4028235E38f;
     field public static final float UNKNOWN_BEFORE = -3.4028235E38f;
   }
 
-  public static class Parallax.FloatPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
-    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float);
-    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float, float);
-    method public final float getMarkerValue(android.support.v17.leanback.widget.Parallax.FloatParallax);
-  }
-
-  public static abstract class Parallax.IntParallax<IntPropertyT extends android.support.v17.leanback.widget.Parallax.IntProperty> extends android.support.v17.leanback.widget.Parallax {
-    ctor public Parallax.IntParallax();
-    method public final IntPropertyT addProperty(java.lang.String);
-    method public abstract int getMaxValue();
-    method public final int getPropertyValue(int);
-    method public final void setPropertyValue(int, int);
-    method public final void verifyProperties() throws java.lang.IllegalStateException;
-  }
-
   public static class Parallax.IntProperty extends android.util.Property {
     ctor public Parallax.IntProperty(java.lang.String, int);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue at(int, float);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atAbsolute(int);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atFraction(float);
-    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax.IntParallax);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(int, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(int);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax);
     method public final int getIndex();
-    method public final void set(android.support.v17.leanback.widget.Parallax.IntParallax, java.lang.Integer);
+    method public final int getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Integer);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, int);
     field public static final int UNKNOWN_AFTER = 2147483647; // 0x7fffffff
     field public static final int UNKNOWN_BEFORE = -2147483648; // 0x80000000
   }
 
-  public static class Parallax.IntPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
-    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int);
-    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int, float);
-    method public final int getMarkerValue(android.support.v17.leanback.widget.Parallax.IntParallax);
-  }
-
   public static class Parallax.PropertyMarkerValue<PropertyT> {
     ctor public Parallax.PropertyMarkerValue(PropertyT);
     method public PropertyT getProperty();
   }
 
-  public abstract class ParallaxEffect<ParallaxEffectT extends android.support.v17.leanback.widget.ParallaxEffect, PropertyMarkerValueT extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> {
-    ctor public ParallaxEffect();
+  public abstract class ParallaxEffect {
     method public final void addTarget(android.support.v17.leanback.widget.ParallaxTarget);
-    method protected abstract float calculateFraction(android.support.v17.leanback.widget.Parallax);
-    method public final java.util.List<PropertyMarkerValueT> getPropertyRanges();
+    method public final java.util.List<android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> getPropertyRanges();
     method public final java.util.List<android.support.v17.leanback.widget.ParallaxTarget> getTargets();
     method public final void performMapping(android.support.v17.leanback.widget.Parallax);
     method public final void removeTarget(android.support.v17.leanback.widget.ParallaxTarget);
-    method public final void setPropertyRanges(PropertyMarkerValueT...);
+    method public final void setPropertyRanges(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
     method public final android.support.v17.leanback.widget.ParallaxEffect target(android.support.v17.leanback.widget.ParallaxTarget);
     method public final android.support.v17.leanback.widget.ParallaxEffect target(java.lang.Object, android.animation.PropertyValuesHolder);
-  }
-
-  public static final class ParallaxEffect.FloatEffect extends android.support.v17.leanback.widget.ParallaxEffect {
-    ctor public ParallaxEffect.FloatEffect();
-    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
-  }
-
-  public static final class ParallaxEffect.IntEffect extends android.support.v17.leanback.widget.ParallaxEffect {
-    ctor public ParallaxEffect.IntEffect();
-    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
+    method public final <T, V extends java.lang.Number> android.support.v17.leanback.widget.ParallaxEffect target(T, android.util.Property<T, V>);
   }
 
   public abstract class ParallaxTarget {
     ctor public ParallaxTarget();
-    method public abstract float getFraction();
-    method public abstract void update(float);
+    method public void directUpdate(java.lang.Number);
+    method public boolean isDirectMapping();
+    method public void update(float);
+  }
+
+  public static final class ParallaxTarget.DirectPropertyTarget<T, V extends java.lang.Number> extends android.support.v17.leanback.widget.ParallaxTarget {
+    ctor public ParallaxTarget.DirectPropertyTarget(java.lang.Object, android.util.Property<T, V>);
   }
 
   public static final class ParallaxTarget.PropertyValuesHolderTarget extends android.support.v17.leanback.widget.ParallaxTarget {
     ctor public ParallaxTarget.PropertyValuesHolderTarget(java.lang.Object, android.animation.PropertyValuesHolder);
-    method public float getFraction();
-    method public void update(float);
   }
 
   public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
@@ -3828,10 +3886,10 @@
     method public void unselect();
   }
 
-  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax.IntParallax {
+  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax {
     ctor public RecyclerViewParallax();
     method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty createProperty(java.lang.String, int);
-    method public int getMaxValue();
+    method public float getMaxValue();
     method public android.support.v7.widget.RecyclerView getRecyclerView();
     method public void setRecyclerView(android.support.v7.widget.RecyclerView);
   }
@@ -5909,72 +5967,72 @@
     field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
   }
 
-  public abstract class TransportController {
-    ctor public TransportController();
-    method public abstract int getBufferPercentage();
-    method public abstract long getCurrentPosition();
-    method public abstract long getDuration();
-    method public abstract int getTransportControlFlags();
-    method public abstract boolean isPlaying();
-    method public abstract void pausePlaying();
-    method public abstract void registerStateListener(android.support.v4.media.TransportStateListener);
-    method public abstract void seekTo(long);
-    method public abstract void startPlaying();
-    method public abstract void stopPlaying();
-    method public abstract void unregisterStateListener(android.support.v4.media.TransportStateListener);
+  public abstract deprecated class TransportController {
+    ctor public deprecated TransportController();
+    method public abstract deprecated int getBufferPercentage();
+    method public abstract deprecated long getCurrentPosition();
+    method public abstract deprecated long getDuration();
+    method public abstract deprecated int getTransportControlFlags();
+    method public abstract deprecated boolean isPlaying();
+    method public abstract deprecated void pausePlaying();
+    method public abstract deprecated void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public abstract deprecated void seekTo(long);
+    method public abstract deprecated void startPlaying();
+    method public abstract deprecated void stopPlaying();
+    method public abstract deprecated void unregisterStateListener(android.support.v4.media.TransportStateListener);
   }
 
-  public class TransportMediator extends android.support.v4.media.TransportController {
-    ctor public TransportMediator(android.app.Activity, android.support.v4.media.TransportPerformer);
-    ctor public TransportMediator(android.view.View, android.support.v4.media.TransportPerformer);
-    method public void destroy();
-    method public boolean dispatchKeyEvent(android.view.KeyEvent);
-    method public int getBufferPercentage();
-    method public long getCurrentPosition();
-    method public long getDuration();
-    method public java.lang.Object getRemoteControlClient();
-    method public int getTransportControlFlags();
-    method public boolean isPlaying();
-    method public void pausePlaying();
-    method public void refreshState();
-    method public void registerStateListener(android.support.v4.media.TransportStateListener);
-    method public void seekTo(long);
-    method public void startPlaying();
-    method public void stopPlaying();
-    method public void unregisterStateListener(android.support.v4.media.TransportStateListener);
-    field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
-    field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
-    field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
-    field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
-    field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
-    field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
-    field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
-    field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
-    field public static final int KEYCODE_MEDIA_PAUSE = 127; // 0x7f
-    field public static final int KEYCODE_MEDIA_PLAY = 126; // 0x7e
-    field public static final int KEYCODE_MEDIA_RECORD = 130; // 0x82
+  public deprecated class TransportMediator extends android.support.v4.media.TransportController {
+    ctor public deprecated TransportMediator(android.app.Activity, android.support.v4.media.TransportPerformer);
+    ctor public deprecated TransportMediator(android.view.View, android.support.v4.media.TransportPerformer);
+    method public deprecated void destroy();
+    method public deprecated boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public deprecated int getBufferPercentage();
+    method public deprecated long getCurrentPosition();
+    method public deprecated long getDuration();
+    method public deprecated java.lang.Object getRemoteControlClient();
+    method public deprecated int getTransportControlFlags();
+    method public deprecated boolean isPlaying();
+    method public deprecated void pausePlaying();
+    method public deprecated void refreshState();
+    method public deprecated void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public deprecated void seekTo(long);
+    method public deprecated void startPlaying();
+    method public deprecated void stopPlaying();
+    method public deprecated void unregisterStateListener(android.support.v4.media.TransportStateListener);
+    field public static final deprecated int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+    field public static final deprecated int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+    field public static final deprecated int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+    field public static final deprecated int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+    field public static final deprecated int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+    field public static final deprecated int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+    field public static final deprecated int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+    field public static final deprecated int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+    field public static final deprecated int KEYCODE_MEDIA_PAUSE = 127; // 0x7f
+    field public static final deprecated int KEYCODE_MEDIA_PLAY = 126; // 0x7e
+    field public static final deprecated int KEYCODE_MEDIA_RECORD = 130; // 0x82
   }
 
-  public abstract class TransportPerformer {
-    ctor public TransportPerformer();
-    method public void onAudioFocusChange(int);
-    method public int onGetBufferPercentage();
-    method public abstract long onGetCurrentPosition();
-    method public abstract long onGetDuration();
-    method public int onGetTransportControlFlags();
-    method public abstract boolean onIsPlaying();
-    method public boolean onMediaButtonDown(int, android.view.KeyEvent);
-    method public boolean onMediaButtonUp(int, android.view.KeyEvent);
-    method public abstract void onPause();
-    method public abstract void onSeekTo(long);
-    method public abstract void onStart();
-    method public abstract void onStop();
+  public abstract deprecated class TransportPerformer {
+    ctor public deprecated TransportPerformer();
+    method public deprecated void onAudioFocusChange(int);
+    method public deprecated int onGetBufferPercentage();
+    method public abstract deprecated long onGetCurrentPosition();
+    method public abstract deprecated long onGetDuration();
+    method public deprecated int onGetTransportControlFlags();
+    method public abstract deprecated boolean onIsPlaying();
+    method public deprecated boolean onMediaButtonDown(int, android.view.KeyEvent);
+    method public deprecated boolean onMediaButtonUp(int, android.view.KeyEvent);
+    method public abstract deprecated void onPause();
+    method public abstract deprecated void onSeekTo(long);
+    method public abstract deprecated void onStart();
+    method public abstract deprecated void onStop();
   }
 
-  public class TransportStateListener {
-    ctor public TransportStateListener();
-    method public void onPlayingChanged(android.support.v4.media.TransportController);
-    method public void onTransportControlsChanged(android.support.v4.media.TransportController);
+  public deprecated class TransportStateListener {
+    ctor public deprecated TransportStateListener();
+    method public deprecated void onPlayingChanged(android.support.v4.media.TransportController);
+    method public deprecated void onTransportControlsChanged(android.support.v4.media.TransportController);
   }
 
   public abstract class VolumeProviderCompat {
@@ -6012,6 +6070,8 @@
   public final class MediaControllerCompat {
     ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
     ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
     method public void adjustVolume(int, int);
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public android.os.Bundle getExtras();
@@ -6032,6 +6092,8 @@
     method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
     method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
+    method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void removeQueueItemAt(int);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat);
     method public void setVolumeTo(int, int);
@@ -6118,11 +6180,14 @@
     method public void setSessionActivity(android.app.PendingIntent);
     method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
   public static abstract class MediaSessionCompat.Callback {
     ctor public MediaSessionCompat.Callback();
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
     method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void onCustomAction(java.lang.String, android.os.Bundle);
     method public void onFastForward();
@@ -6136,6 +6201,8 @@
     method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
     method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
     method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+    method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat);
+    method public void onRemoveQueueItemAt(int);
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.support.v4.media.RatingCompat);
@@ -8463,6 +8530,7 @@
     method public android.support.v7.graphics.drawable.DrawerArrowDrawable getDrawerArrowDrawable();
     method public android.view.View.OnClickListener getToolbarNavigationClickListener();
     method public boolean isDrawerIndicatorEnabled();
+    method public boolean isDrawerSlideAnimationEnabled();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDrawerClosed(android.view.View);
     method public void onDrawerOpened(android.view.View);
@@ -8471,6 +8539,7 @@
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable);
     method public void setDrawerIndicatorEnabled(boolean);
+    method public void setDrawerSlideAnimationEnabled(boolean);
     method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
     method public void setHomeAsUpIndicator(int);
     method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
diff --git a/api/26.0.0-alpha1.txt b/api/26.0.0-alpha1.txt
new file mode 100644
index 0000000..920c508
--- /dev/null
+++ b/api/26.0.0-alpha1.txt
@@ -0,0 +1,11757 @@
+package android.support.app.recommendation {
+
+  public final class ContentRecommendation {
+    method public java.lang.String getBackgroundImageUri();
+    method public int getBadgeImageResourceId();
+    method public int getColor();
+    method public android.graphics.Bitmap getContentImage();
+    method public android.support.app.recommendation.ContentRecommendation.IntentData getContentIntent();
+    method public java.lang.String[] getContentTypes();
+    method public android.support.app.recommendation.ContentRecommendation.IntentData getDismissIntent();
+    method public java.lang.String[] getGenres();
+    method public java.lang.String getGroup();
+    method public java.lang.String getIdTag();
+    method public java.lang.String getMaturityRating();
+    method public android.app.Notification getNotificationObject(android.content.Context);
+    method public java.lang.String getPricingType();
+    method public java.lang.String getPricingValue();
+    method public java.lang.String getPrimaryContentType();
+    method public int getProgressMax();
+    method public int getProgressValue();
+    method public long getRunningTime();
+    method public java.lang.String getSortKey();
+    method public java.lang.String getSourceName();
+    method public int getStatus();
+    method public java.lang.String getText();
+    method public java.lang.String getTitle();
+    method public boolean hasProgressInfo();
+    method public boolean isAutoDismiss();
+    method public void setAutoDismiss(boolean);
+    method public void setGroup(java.lang.String);
+    method public void setProgress(int, int);
+    method public void setSortKey(java.lang.String);
+    method public void setStatus(int);
+    field public static final java.lang.String CONTENT_MATURITY_ALL = "android.contentMaturity.all";
+    field public static final java.lang.String CONTENT_MATURITY_HIGH = "android.contentMaturity.high";
+    field public static final java.lang.String CONTENT_MATURITY_LOW = "android.contentMaturity.low";
+    field public static final java.lang.String CONTENT_MATURITY_MEDIUM = "android.contentMaturity.medium";
+    field public static final java.lang.String CONTENT_PRICING_FREE = "android.contentPrice.free";
+    field public static final java.lang.String CONTENT_PRICING_PREORDER = "android.contentPrice.preorder";
+    field public static final java.lang.String CONTENT_PRICING_PURCHASE = "android.contentPrice.purchase";
+    field public static final java.lang.String CONTENT_PRICING_RENTAL = "android.contentPrice.rental";
+    field public static final java.lang.String CONTENT_PRICING_SUBSCRIPTION = "android.contentPrice.subscription";
+    field public static final int CONTENT_STATUS_AVAILABLE = 2; // 0x2
+    field public static final int CONTENT_STATUS_PENDING = 1; // 0x1
+    field public static final int CONTENT_STATUS_READY = 0; // 0x0
+    field public static final int CONTENT_STATUS_UNAVAILABLE = 3; // 0x3
+    field public static final java.lang.String CONTENT_TYPE_APP = "android.contentType.app";
+    field public static final java.lang.String CONTENT_TYPE_BOOK = "android.contentType.book";
+    field public static final java.lang.String CONTENT_TYPE_COMIC = "android.contentType.comic";
+    field public static final java.lang.String CONTENT_TYPE_GAME = "android.contentType.game";
+    field public static final java.lang.String CONTENT_TYPE_MAGAZINE = "android.contentType.magazine";
+    field public static final java.lang.String CONTENT_TYPE_MOVIE = "android.contentType.movie";
+    field public static final java.lang.String CONTENT_TYPE_MUSIC = "android.contentType.music";
+    field public static final java.lang.String CONTENT_TYPE_NEWS = "android.contentType.news";
+    field public static final java.lang.String CONTENT_TYPE_PODCAST = "android.contentType.podcast";
+    field public static final java.lang.String CONTENT_TYPE_RADIO = "android.contentType.radio";
+    field public static final java.lang.String CONTENT_TYPE_SERIAL = "android.contentType.serial";
+    field public static final java.lang.String CONTENT_TYPE_SPORTS = "android.contentType.sports";
+    field public static final java.lang.String CONTENT_TYPE_TRAILER = "android.contentType.trailer";
+    field public static final java.lang.String CONTENT_TYPE_VIDEO = "android.contentType.video";
+    field public static final java.lang.String CONTENT_TYPE_WEBSITE = "android.contentType.website";
+    field public static final int INTENT_TYPE_ACTIVITY = 1; // 0x1
+    field public static final int INTENT_TYPE_BROADCAST = 2; // 0x2
+    field public static final int INTENT_TYPE_SERVICE = 3; // 0x3
+  }
+
+  public static final class ContentRecommendation.Builder {
+    ctor public ContentRecommendation.Builder();
+    method public android.support.app.recommendation.ContentRecommendation build();
+    method public android.support.app.recommendation.ContentRecommendation.Builder setAutoDismiss(boolean);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setBackgroundImageUri(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setBadgeIcon(int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setColor(int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setContentImage(android.graphics.Bitmap);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setContentIntentData(int, android.content.Intent, int, android.os.Bundle);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setContentTypes(java.lang.String[]);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setDismissIntentData(int, android.content.Intent, int, android.os.Bundle);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setGenres(java.lang.String[]);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setGroup(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setIdTag(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setMaturityRating(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setPricingInformation(java.lang.String, java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setProgress(int, int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setRunningTime(long);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setSortKey(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setSourceName(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setStatus(int);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setText(java.lang.String);
+    method public android.support.app.recommendation.ContentRecommendation.Builder setTitle(java.lang.String);
+  }
+
+  public static abstract class ContentRecommendation.ContentMaturity implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ContentRecommendation.ContentPricing implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ContentRecommendation.ContentStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ContentRecommendation.ContentType implements java.lang.annotation.Annotation {
+  }
+
+  public static class ContentRecommendation.IntentData {
+    ctor public ContentRecommendation.IntentData();
+  }
+
+  public static abstract class ContentRecommendation.IntentType implements java.lang.annotation.Annotation {
+  }
+
+  public final class RecommendationExtender implements android.app.Notification.Extender {
+    ctor public RecommendationExtender();
+    ctor public RecommendationExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public java.lang.String[] getContentTypes();
+    method public java.lang.String[] getGenres();
+    method public java.lang.String getMaturityRating();
+    method public java.lang.String getPricingType();
+    method public java.lang.String getPricingValue();
+    method public java.lang.String getPrimaryContentType();
+    method public long getRunningTime();
+    method public int getStatus();
+    method public android.support.app.recommendation.RecommendationExtender setContentTypes(java.lang.String[]);
+    method public android.support.app.recommendation.RecommendationExtender setGenres(java.lang.String[]);
+    method public android.support.app.recommendation.RecommendationExtender setMaturityRating(java.lang.String);
+    method public android.support.app.recommendation.RecommendationExtender setPricingInformation(java.lang.String, java.lang.String);
+    method public android.support.app.recommendation.RecommendationExtender setRunningTime(long);
+    method public android.support.app.recommendation.RecommendationExtender setStatus(int);
+  }
+
+}
+
+package android.support.customtabs {
+
+  public class CustomTabsCallback {
+    ctor public CustomTabsCallback();
+    method public void extraCallback(java.lang.String, android.os.Bundle);
+    method public void onMessageChannelReady(android.os.Bundle);
+    method public void onNavigationEvent(int, android.os.Bundle);
+    method public void onPostMessage(java.lang.String, android.os.Bundle);
+    field public static final int NAVIGATION_ABORTED = 4; // 0x4
+    field public static final int NAVIGATION_FAILED = 3; // 0x3
+    field public static final int NAVIGATION_FINISHED = 2; // 0x2
+    field public static final int NAVIGATION_STARTED = 1; // 0x1
+    field public static final int TAB_HIDDEN = 6; // 0x6
+    field public static final int TAB_SHOWN = 5; // 0x5
+  }
+
+  public class CustomTabsClient {
+    method public static boolean bindCustomTabsService(android.content.Context, java.lang.String, android.support.customtabs.CustomTabsServiceConnection);
+    method public static boolean connectAndInitialize(android.content.Context, java.lang.String);
+    method public android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+    method public static java.lang.String getPackageName(android.content.Context, java.util.List<java.lang.String>);
+    method public static java.lang.String getPackageName(android.content.Context, java.util.List<java.lang.String>, boolean);
+    method public android.support.customtabs.CustomTabsSession newSession(android.support.customtabs.CustomTabsCallback);
+    method public boolean warmup(long);
+  }
+
+  public final class CustomTabsIntent {
+    method public static int getMaxToolbarItems();
+    method public void launchUrl(android.content.Context, android.net.Uri);
+    method public static android.content.Intent setAlwaysUseBrowserUI(android.content.Intent);
+    method public static boolean shouldAlwaysUseBrowserUI(android.content.Intent);
+    field public static final java.lang.String EXTRA_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
+    field public static final java.lang.String EXTRA_CLOSE_BUTTON_ICON = "android.support.customtabs.extra.CLOSE_BUTTON_ICON";
+    field public static final java.lang.String EXTRA_DEFAULT_SHARE_MENU_ITEM = "android.support.customtabs.extra.SHARE_MENU_ITEM";
+    field public static final java.lang.String EXTRA_ENABLE_INSTANT_APPS = "android.support.customtabs.extra.EXTRA_ENABLE_INSTANT_APPS";
+    field public static final java.lang.String EXTRA_ENABLE_URLBAR_HIDING = "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
+    field public static final java.lang.String EXTRA_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
+    field public static final java.lang.String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS_CLICKED_ID = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS_CLICKED_ID";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS_PENDINGINTENT = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS_PENDINGINTENT";
+    field public static final java.lang.String EXTRA_REMOTEVIEWS_VIEW_IDS = "android.support.customtabs.extra.EXTRA_REMOTEVIEWS_VIEW_IDS";
+    field public static final java.lang.String EXTRA_SECONDARY_TOOLBAR_COLOR = "android.support.customtabs.extra.SECONDARY_TOOLBAR_COLOR";
+    field public static final java.lang.String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
+    field public static final java.lang.String EXTRA_TINT_ACTION_BUTTON = "android.support.customtabs.extra.TINT_ACTION_BUTTON";
+    field public static final java.lang.String EXTRA_TITLE_VISIBILITY_STATE = "android.support.customtabs.extra.TITLE_VISIBILITY";
+    field public static final java.lang.String EXTRA_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR";
+    field public static final java.lang.String EXTRA_TOOLBAR_ITEMS = "android.support.customtabs.extra.TOOLBAR_ITEMS";
+    field public static final java.lang.String KEY_DESCRIPTION = "android.support.customtabs.customaction.DESCRIPTION";
+    field public static final java.lang.String KEY_ICON = "android.support.customtabs.customaction.ICON";
+    field public static final java.lang.String KEY_ID = "android.support.customtabs.customaction.ID";
+    field public static final java.lang.String KEY_MENU_ITEM_TITLE = "android.support.customtabs.customaction.MENU_ITEM_TITLE";
+    field public static final java.lang.String KEY_PENDING_INTENT = "android.support.customtabs.customaction.PENDING_INTENT";
+    field public static final int NO_TITLE = 0; // 0x0
+    field public static final int SHOW_PAGE_TITLE = 1; // 0x1
+    field public static final int TOOLBAR_ACTION_BUTTON_ID = 0; // 0x0
+    field public final android.content.Intent intent;
+    field public final android.os.Bundle startAnimationBundle;
+  }
+
+  public static final class CustomTabsIntent.Builder {
+    ctor public CustomTabsIntent.Builder();
+    ctor public CustomTabsIntent.Builder(android.support.customtabs.CustomTabsSession);
+    method public android.support.customtabs.CustomTabsIntent.Builder addDefaultShareMenuItem();
+    method public android.support.customtabs.CustomTabsIntent.Builder addMenuItem(java.lang.String, android.app.PendingIntent);
+    method public deprecated android.support.customtabs.CustomTabsIntent.Builder addToolbarItem(int, android.graphics.Bitmap, java.lang.String, android.app.PendingIntent) throws java.lang.IllegalStateException;
+    method public android.support.customtabs.CustomTabsIntent build();
+    method public android.support.customtabs.CustomTabsIntent.Builder enableUrlBarHiding();
+    method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent, boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent);
+    method public android.support.customtabs.CustomTabsIntent.Builder setCloseButtonIcon(android.graphics.Bitmap);
+    method public android.support.customtabs.CustomTabsIntent.Builder setExitAnimations(android.content.Context, int, int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setInstantAppsEnabled(boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setSecondaryToolbarColor(int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent);
+    method public android.support.customtabs.CustomTabsIntent.Builder setShowTitle(boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setStartAnimations(android.content.Context, int, int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setToolbarColor(int);
+  }
+
+  public abstract class CustomTabsService extends android.app.Service {
+    ctor public CustomTabsService();
+    method protected boolean cleanUpSession(android.support.customtabs.CustomTabsSessionToken);
+    method protected abstract android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+    method protected abstract boolean mayLaunchUrl(android.support.customtabs.CustomTabsSessionToken, android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+    method protected abstract boolean newSession(android.support.customtabs.CustomTabsSessionToken);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method protected abstract int postMessage(android.support.customtabs.CustomTabsSessionToken, java.lang.String, android.os.Bundle);
+    method protected abstract boolean requestPostMessageChannel(android.support.customtabs.CustomTabsSessionToken, android.net.Uri);
+    method protected abstract boolean updateVisuals(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle);
+    method protected abstract boolean warmup(long);
+    field public static final java.lang.String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
+    field public static final java.lang.String KEY_URL = "android.support.customtabs.otherurls.URL";
+    field public static final int RESULT_FAILURE_DISALLOWED = -1; // 0xffffffff
+    field public static final int RESULT_FAILURE_MESSAGING_ERROR = -3; // 0xfffffffd
+    field public static final int RESULT_FAILURE_REMOTE_ERROR = -2; // 0xfffffffe
+    field public static final int RESULT_SUCCESS = 0; // 0x0
+  }
+
+  public static abstract class CustomTabsService.Result implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class CustomTabsServiceConnection implements android.content.ServiceConnection {
+    ctor public CustomTabsServiceConnection();
+    method public abstract void onCustomTabsServiceConnected(android.content.ComponentName, android.support.customtabs.CustomTabsClient);
+    method public final void onServiceConnected(android.content.ComponentName, android.os.IBinder);
+  }
+
+  public final class CustomTabsSession {
+    method public boolean mayLaunchUrl(android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+    method public int postMessage(java.lang.String, android.os.Bundle);
+    method public boolean requestPostMessageChannel(android.net.Uri);
+    method public boolean setActionButton(android.graphics.Bitmap, java.lang.String);
+    method public boolean setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent);
+    method public deprecated boolean setToolbarItem(int, android.graphics.Bitmap, java.lang.String);
+  }
+
+  public class CustomTabsSessionToken {
+    method public android.support.customtabs.CustomTabsCallback getCallback();
+    method public static android.support.customtabs.CustomTabsSessionToken getSessionTokenFromIntent(android.content.Intent);
+    method public boolean isAssociatedWith(android.support.customtabs.CustomTabsSession);
+  }
+
+  public class PostMessageService extends android.app.Service {
+    ctor public PostMessageService();
+    method public android.os.IBinder onBind(android.content.Intent);
+  }
+
+  public abstract class PostMessageServiceConnection implements android.content.ServiceConnection {
+    ctor public PostMessageServiceConnection(android.support.customtabs.CustomTabsSessionToken);
+    method public boolean bindSessionToPostMessageService(android.content.Context, java.lang.String);
+    method public final boolean notifyMessageChannelReady(android.os.Bundle);
+    method public void onPostMessageServiceConnected();
+    method public void onPostMessageServiceDisconnected();
+    method public final void onServiceConnected(android.content.ComponentName, android.os.IBinder);
+    method public final void onServiceDisconnected(android.content.ComponentName);
+    method public final boolean postMessage(java.lang.String, android.os.Bundle);
+    method public void unbindFromContext(android.content.Context);
+  }
+
+}
+
+package android.support.design.widget {
+
+  public class AppBarLayout extends android.widget.LinearLayout {
+    ctor public AppBarLayout(android.content.Context);
+    ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
+    method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+    method public deprecated float getTargetElevation();
+    method public final int getTotalScrollRange();
+    method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+    method public void setExpanded(boolean);
+    method public void setExpanded(boolean, boolean);
+    method public deprecated void setTargetElevation(float);
+  }
+
+  public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
+    ctor public AppBarLayout.Behavior();
+    ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int, int, int, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, float, float, boolean);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int);
+    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
+    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View);
+    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
+  }
+
+  public static abstract class AppBarLayout.Behavior.DragCallback {
+    ctor public AppBarLayout.Behavior.DragCallback();
+    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
+  }
+
+  protected static class AppBarLayout.Behavior.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
+  }
+
+  public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
+    ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public AppBarLayout.LayoutParams(int, int);
+    ctor public AppBarLayout.LayoutParams(int, int, float);
+    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
+    method public int getScrollFlags();
+    method public android.view.animation.Interpolator getScrollInterpolator();
+    method public void setScrollFlags(int);
+    method public void setScrollInterpolator(android.view.animation.Interpolator);
+    field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
+    field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
+    field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
+    field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
+    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
+  }
+
+  public static abstract interface AppBarLayout.OnOffsetChangedListener {
+    method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
+  }
+
+  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
+    ctor public AppBarLayout.ScrollingViewBehavior();
+    ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
+  }
+
+  public abstract class BaseTransientBottomBar<B extends android.support.design.widget.BaseTransientBottomBar<B>> {
+    ctor protected BaseTransientBottomBar(android.view.ViewGroup, android.view.View, android.support.design.widget.BaseTransientBottomBar.ContentViewCallback);
+    method public B addCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
+    method public void dismiss();
+    method public android.content.Context getContext();
+    method public int getDuration();
+    method public android.view.View getView();
+    method public boolean isShown();
+    method public boolean isShownOrQueued();
+    method public B removeCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
+    method public B setDuration(int);
+    method public void show();
+    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
+    field public static final int LENGTH_LONG = 0; // 0x0
+    field public static final int LENGTH_SHORT = -1; // 0xffffffff
+  }
+
+  public static abstract class BaseTransientBottomBar.BaseCallback<B> {
+    ctor public BaseTransientBottomBar.BaseCallback();
+    method public void onDismissed(B, int);
+    method public void onShown(B);
+    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
+    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
+    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
+    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
+    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
+  }
+
+  public static abstract interface BaseTransientBottomBar.ContentViewCallback {
+    method public abstract void animateContentIn(int, int);
+    method public abstract void animateContentOut(int, int);
+  }
+
+  public class BottomNavigationView extends android.widget.FrameLayout {
+    ctor public BottomNavigationView(android.content.Context);
+    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
+    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
+    method public int getItemBackgroundResource();
+    method public android.content.res.ColorStateList getItemIconTintList();
+    method public android.content.res.ColorStateList getItemTextColor();
+    method public int getMaxItemCount();
+    method public android.view.Menu getMenu();
+    method public int getSelectedItemId();
+    method public void inflateMenu(int);
+    method public void setItemBackgroundResource(int);
+    method public void setItemIconTintList(android.content.res.ColorStateList);
+    method public void setItemTextColor(android.content.res.ColorStateList);
+    method public void setOnNavigationItemReselectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemReselectedListener);
+    method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
+    method public void setSelectedItemId(int);
+  }
+
+  public static abstract interface BottomNavigationView.OnNavigationItemReselectedListener {
+    method public abstract void onNavigationItemReselected(android.view.MenuItem);
+  }
+
+  public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
+    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+  }
+
+  public class BottomSheetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public BottomSheetBehavior();
+    ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
+    method public static <V extends android.view.View> android.support.design.widget.BottomSheetBehavior<V> from(V);
+    method public final int getPeekHeight();
+    method public boolean getSkipCollapsed();
+    method public final int getState();
+    method public boolean isHideable();
+    method public void setBottomSheetCallback(android.support.design.widget.BottomSheetBehavior.BottomSheetCallback);
+    method public void setHideable(boolean);
+    method public final void setPeekHeight(int);
+    method public void setSkipCollapsed(boolean);
+    method public final void setState(int);
+    field public static final int PEEK_HEIGHT_AUTO = -1; // 0xffffffff
+    field public static final int STATE_COLLAPSED = 4; // 0x4
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_EXPANDED = 3; // 0x3
+    field public static final int STATE_HIDDEN = 5; // 0x5
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class BottomSheetBehavior.BottomSheetCallback {
+    ctor public BottomSheetBehavior.BottomSheetCallback();
+    method public abstract void onSlide(android.view.View, float);
+    method public abstract void onStateChanged(android.view.View, int);
+  }
+
+  protected static class BottomSheetBehavior.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
+  }
+
+  public class BottomSheetDialog extends android.support.v7.app.AppCompatDialog {
+    ctor public BottomSheetDialog(android.content.Context);
+    ctor public BottomSheetDialog(android.content.Context, int);
+    ctor protected BottomSheetDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+  }
+
+  public class BottomSheetDialogFragment extends android.support.v7.app.AppCompatDialogFragment {
+    ctor public BottomSheetDialogFragment();
+  }
+
+  public class CollapsingToolbarLayout extends android.widget.FrameLayout {
+    ctor public CollapsingToolbarLayout(android.content.Context);
+    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
+    method public int getCollapsedTitleGravity();
+    method public android.graphics.Typeface getCollapsedTitleTypeface();
+    method public android.graphics.drawable.Drawable getContentScrim();
+    method public int getExpandedTitleGravity();
+    method public int getExpandedTitleMarginBottom();
+    method public int getExpandedTitleMarginEnd();
+    method public int getExpandedTitleMarginStart();
+    method public int getExpandedTitleMarginTop();
+    method public android.graphics.Typeface getExpandedTitleTypeface();
+    method public long getScrimAnimationDuration();
+    method public int getScrimVisibleHeightTrigger();
+    method public android.graphics.drawable.Drawable getStatusBarScrim();
+    method public java.lang.CharSequence getTitle();
+    method public boolean isTitleEnabled();
+    method public void setCollapsedTitleGravity(int);
+    method public void setCollapsedTitleTextAppearance(int);
+    method public void setCollapsedTitleTextColor(int);
+    method public void setCollapsedTitleTextColor(android.content.res.ColorStateList);
+    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
+    method public void setContentScrim(android.graphics.drawable.Drawable);
+    method public void setContentScrimColor(int);
+    method public void setContentScrimResource(int);
+    method public void setExpandedTitleColor(int);
+    method public void setExpandedTitleGravity(int);
+    method public void setExpandedTitleMargin(int, int, int, int);
+    method public void setExpandedTitleMarginBottom(int);
+    method public void setExpandedTitleMarginEnd(int);
+    method public void setExpandedTitleMarginStart(int);
+    method public void setExpandedTitleMarginTop(int);
+    method public void setExpandedTitleTextAppearance(int);
+    method public void setExpandedTitleTextColor(android.content.res.ColorStateList);
+    method public void setExpandedTitleTypeface(android.graphics.Typeface);
+    method public void setScrimAnimationDuration(long);
+    method public void setScrimVisibleHeightTrigger(int);
+    method public void setScrimsShown(boolean);
+    method public void setScrimsShown(boolean, boolean);
+    method public void setStatusBarScrim(android.graphics.drawable.Drawable);
+    method public void setStatusBarScrimColor(int);
+    method public void setStatusBarScrimResource(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleEnabled(boolean);
+  }
+
+  public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public CollapsingToolbarLayout.LayoutParams(int, int);
+    ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    method public int getCollapseMode();
+    method public float getParallaxMultiplier();
+    method public void setCollapseMode(int);
+    method public void setParallaxMultiplier(float);
+    field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
+    field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
+    field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
+  }
+
+  public class CoordinatorLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingParent {
+    ctor public CoordinatorLayout(android.content.Context);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void dispatchDependentViewsChanged(android.view.View);
+    method public boolean doViewsOverlap(android.view.View, android.view.View);
+    method public java.util.List<android.view.View> getDependencies(android.view.View);
+    method public java.util.List<android.view.View> getDependents(android.view.View);
+    method public android.graphics.drawable.Drawable getStatusBarBackground();
+    method public boolean isPointInChildBounds(android.view.View, int, int);
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onLayoutChild(android.view.View, int);
+    method public void onMeasureChild(android.view.View, int, int, int, int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackgroundColor(int);
+    method public void setStatusBarBackgroundResource(int);
+  }
+
+  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
+    ctor public CoordinatorLayout.Behavior();
+    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
+    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
+    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
+    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
+    method public static java.lang.Object getTag(android.view.View);
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
+    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDetachedFromLayoutParams();
+    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
+    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
+    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public static void setTag(android.view.View, java.lang.Object);
+  }
+
+  public static abstract class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
+  }
+
+  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public CoordinatorLayout.LayoutParams(int, int);
+    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    method public int getAnchorId();
+    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+    method public void setAnchorId(int);
+    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
+    field public int anchorGravity;
+    field public int dodgeInsetEdges;
+    field public int gravity;
+    field public int insetEdge;
+    field public int keyline;
+  }
+
+  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
+  }
+
+  public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
+    ctor public FloatingActionButton(android.content.Context);
+    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
+    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
+    method public float getCompatElevation();
+    method public android.graphics.drawable.Drawable getContentBackground();
+    method public boolean getContentRect(android.graphics.Rect);
+    method public int getRippleColor();
+    method public int getSize();
+    method public boolean getUseCompatPadding();
+    method public void hide();
+    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+    method public void setCompatElevation(float);
+    method public void setRippleColor(int);
+    method public void setSize(int);
+    method public void setUseCompatPadding(boolean);
+    method public void show();
+    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+    field public static final int SIZE_AUTO = -1; // 0xffffffff
+    field public static final int SIZE_MINI = 1; // 0x1
+    field public static final int SIZE_NORMAL = 0; // 0x0
+  }
+
+  public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public FloatingActionButton.Behavior();
+    ctor public FloatingActionButton.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect);
+    method public boolean isAutoHideEnabled();
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
+    method public void setAutoHideEnabled(boolean);
+  }
+
+  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
+    ctor public FloatingActionButton.OnVisibilityChangedListener();
+    method public void onHidden(android.support.design.widget.FloatingActionButton);
+    method public void onShown(android.support.design.widget.FloatingActionButton);
+  }
+
+   abstract class HeaderBehavior<V extends android.view.View> extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderBehavior();
+    ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
+  }
+
+   abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderScrollingViewBehavior();
+    ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+    method public final int getOverlayTop();
+    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+    method public final void setOverlayTop(int);
+  }
+
+  public class NavigationView extends android.widget.FrameLayout {
+    ctor public NavigationView(android.content.Context);
+    ctor public NavigationView(android.content.Context, android.util.AttributeSet);
+    ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
+    method public void addHeaderView(android.view.View);
+    method public int getHeaderCount();
+    method public android.view.View getHeaderView(int);
+    method public android.graphics.drawable.Drawable getItemBackground();
+    method public android.content.res.ColorStateList getItemIconTintList();
+    method public android.content.res.ColorStateList getItemTextColor();
+    method public android.view.Menu getMenu();
+    method public android.view.View inflateHeaderView(int);
+    method public void inflateMenu(int);
+    method public void removeHeaderView(android.view.View);
+    method public void setCheckedItem(int);
+    method public void setItemBackground(android.graphics.drawable.Drawable);
+    method public void setItemBackgroundResource(int);
+    method public void setItemIconTintList(android.content.res.ColorStateList);
+    method public void setItemTextAppearance(int);
+    method public void setItemTextColor(android.content.res.ColorStateList);
+    method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
+  }
+
+  public static abstract interface NavigationView.OnNavigationItemSelectedListener {
+    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+  }
+
+  public static class NavigationView.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public NavigationView.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
+    field public android.os.Bundle menuState;
+  }
+
+  public final class Snackbar extends android.support.design.widget.BaseTransientBottomBar {
+    method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
+    method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
+    method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
+    method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
+    method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
+    method public android.support.design.widget.Snackbar setActionTextColor(int);
+    method public deprecated android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
+    method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
+    method public android.support.design.widget.Snackbar setText(int);
+    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
+    field public static final int LENGTH_LONG = 0; // 0x0
+    field public static final int LENGTH_SHORT = -1; // 0xffffffff
+  }
+
+  public static class Snackbar.Callback extends android.support.design.widget.BaseTransientBottomBar.BaseCallback {
+    ctor public Snackbar.Callback();
+    method public void onDismissed(android.support.design.widget.Snackbar, int);
+    method public void onShown(android.support.design.widget.Snackbar);
+    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
+    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
+    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
+    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
+    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
+  }
+
+  public class SwipeDismissBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public SwipeDismissBehavior();
+    method public boolean canSwipeDismissView(android.view.View);
+    method public int getDragState();
+    method public void setDragDismissDistance(float);
+    method public void setEndAlphaSwipeDistance(float);
+    method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
+    method public void setSensitivity(float);
+    method public void setStartAlphaSwipeDistance(float);
+    method public void setSwipeDirection(int);
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+    field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
+    field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
+    field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
+  }
+
+  public static abstract interface SwipeDismissBehavior.OnDismissListener {
+    method public abstract void onDismiss(android.view.View);
+    method public abstract void onDragStateChanged(int);
+  }
+
+  public final class TabItem extends android.view.View {
+    ctor public TabItem(android.content.Context);
+    ctor public TabItem(android.content.Context, android.util.AttributeSet);
+  }
+
+  public class TabLayout extends android.widget.HorizontalScrollView {
+    ctor public TabLayout(android.content.Context);
+    ctor public TabLayout(android.content.Context, android.util.AttributeSet);
+    ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void addOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+    method public void addTab(android.support.design.widget.TabLayout.Tab);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, int);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
+    method public void clearOnTabSelectedListeners();
+    method public int getSelectedTabPosition();
+    method public android.support.design.widget.TabLayout.Tab getTabAt(int);
+    method public int getTabCount();
+    method public int getTabGravity();
+    method public int getTabMode();
+    method public android.content.res.ColorStateList getTabTextColors();
+    method public android.support.design.widget.TabLayout.Tab newTab();
+    method public void removeAllTabs();
+    method public void removeOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+    method public void removeTab(android.support.design.widget.TabLayout.Tab);
+    method public void removeTabAt(int);
+    method public deprecated void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+    method public void setScrollPosition(int, float, boolean);
+    method public void setSelectedTabIndicatorColor(int);
+    method public void setSelectedTabIndicatorHeight(int);
+    method public void setTabGravity(int);
+    method public void setTabMode(int);
+    method public void setTabTextColors(android.content.res.ColorStateList);
+    method public void setTabTextColors(int, int);
+    method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
+    method public void setupWithViewPager(android.support.v4.view.ViewPager);
+    method public void setupWithViewPager(android.support.v4.view.ViewPager, boolean);
+    field public static final int GRAVITY_CENTER = 1; // 0x1
+    field public static final int GRAVITY_FILL = 0; // 0x0
+    field public static final int MODE_FIXED = 1; // 0x1
+    field public static final int MODE_SCROLLABLE = 0; // 0x0
+  }
+
+  public static abstract interface TabLayout.OnTabSelectedListener {
+    method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
+    method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
+    method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+  }
+
+  public static final class TabLayout.Tab {
+    method public java.lang.CharSequence getContentDescription();
+    method public android.view.View getCustomView();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public int getPosition();
+    method public java.lang.Object getTag();
+    method public java.lang.CharSequence getText();
+    method public boolean isSelected();
+    method public void select();
+    method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
+    method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
+    method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
+    method public android.support.design.widget.TabLayout.Tab setCustomView(int);
+    method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
+    method public android.support.design.widget.TabLayout.Tab setIcon(int);
+    method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
+    method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
+    method public android.support.design.widget.TabLayout.Tab setText(int);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+    ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
+    method public void onPageScrollStateChanged(int);
+    method public void onPageScrolled(int, float, int);
+    method public void onPageSelected(int);
+  }
+
+  public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
+    ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
+    method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
+    method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
+    method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+  }
+
+  public class TextInputEditText extends android.support.v7.widget.AppCompatEditText {
+    ctor public TextInputEditText(android.content.Context);
+    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet);
+    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class TextInputLayout extends android.widget.LinearLayout {
+    ctor public TextInputLayout(android.content.Context);
+    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
+    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
+    method public int getCounterMaxLength();
+    method public android.widget.EditText getEditText();
+    method public java.lang.CharSequence getError();
+    method public java.lang.CharSequence getHint();
+    method public java.lang.CharSequence getPasswordVisibilityToggleContentDescription();
+    method public android.graphics.drawable.Drawable getPasswordVisibilityToggleDrawable();
+    method public android.graphics.Typeface getTypeface();
+    method public boolean isCounterEnabled();
+    method public boolean isErrorEnabled();
+    method public boolean isHintAnimationEnabled();
+    method public boolean isHintEnabled();
+    method public boolean isPasswordVisibilityToggleEnabled();
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void setCounterEnabled(boolean);
+    method public void setCounterMaxLength(int);
+    method public void setError(java.lang.CharSequence);
+    method public void setErrorEnabled(boolean);
+    method public void setErrorTextAppearance(int);
+    method public void setHint(java.lang.CharSequence);
+    method public void setHintAnimationEnabled(boolean);
+    method public void setHintEnabled(boolean);
+    method public void setHintTextAppearance(int);
+    method public void setPasswordVisibilityToggleContentDescription(int);
+    method public void setPasswordVisibilityToggleContentDescription(java.lang.CharSequence);
+    method public void setPasswordVisibilityToggleDrawable(int);
+    method public void setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable);
+    method public void setPasswordVisibilityToggleEnabled(boolean);
+    method public void setPasswordVisibilityToggleTintList(android.content.res.ColorStateList);
+    method public void setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTypeface(android.graphics.Typeface);
+  }
+
+   class ViewOffsetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public ViewOffsetBehavior();
+    ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
+    method public int getLeftAndRightOffset();
+    method public int getTopAndBottomOffset();
+    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+    method public boolean setLeftAndRightOffset(int);
+    method public boolean setTopAndBottomOffset(int);
+  }
+
+   class VisibilityAwareImageButton extends android.widget.ImageButton {
+    ctor public VisibilityAwareImageButton(android.content.Context);
+    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+}
+
+package android.support.graphics.drawable {
+
+  public class AnimatedVectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon {
+    method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat create(android.content.Context, int);
+    method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
+    method public int getOpacity();
+    method public boolean isRunning();
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void start();
+    method public void stop();
+  }
+
+   abstract class VectorDrawableCommon extends android.graphics.drawable.Drawable {
+  }
+
+  public class VectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon {
+    method public static android.support.graphics.drawable.VectorDrawableCompat create(android.content.res.Resources, int, android.content.res.Resources.Theme);
+    method public static android.support.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
+    method public int getOpacity();
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+  }
+
+}
+
+package android.support.media {
+
+  public class ExifInterface {
+    ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    method public double getAltitude(double);
+    method public java.lang.String getAttribute(java.lang.String);
+    method public double getAttributeDouble(java.lang.String, double);
+    method public int getAttributeInt(java.lang.String, int);
+    method public deprecated boolean getLatLong(float[]);
+    method public double[] getLatLong();
+    method public byte[] getThumbnail();
+    method public android.graphics.Bitmap getThumbnailBitmap();
+    method public byte[] getThumbnailBytes();
+    method public long[] getThumbnailRange();
+    method public boolean hasThumbnail();
+    method public boolean isThumbnailCompressed();
+    method public void saveAttributes() throws java.io.IOException;
+    method public void setAttribute(java.lang.String, java.lang.String);
+    method public void setLatLong(double, double);
+    field public static final int ORIENTATION_FLIP_HORIZONTAL = 2; // 0x2
+    field public static final int ORIENTATION_FLIP_VERTICAL = 4; // 0x4
+    field public static final int ORIENTATION_NORMAL = 1; // 0x1
+    field public static final int ORIENTATION_ROTATE_180 = 3; // 0x3
+    field public static final int ORIENTATION_ROTATE_270 = 8; // 0x8
+    field public static final int ORIENTATION_ROTATE_90 = 6; // 0x6
+    field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
+    field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
+    field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
+    field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+    field public static final java.lang.String TAG_ARTIST = "Artist";
+    field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+    field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+    field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+    field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+    field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+    field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+    field public static final java.lang.String TAG_COMPRESSION = "Compression";
+    field public static final java.lang.String TAG_CONTRAST = "Contrast";
+    field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+    field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
+    field public static final java.lang.String TAG_DATETIME = "DateTime";
+    field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+    field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+    field public static final java.lang.String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize";
+    field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+    field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+    field public static final java.lang.String TAG_DNG_VERSION = "DNGVersion";
+    field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
+    field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+    field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
+    field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+    field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
+    field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+    field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
+    field public static final java.lang.String TAG_FLASH = "Flash";
+    field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+    field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
+    field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+    field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+    field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+    field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+    field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+    field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+    field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
+    field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
+    field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+    field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
+    field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+    field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+    field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
+    field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
+    field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
+    field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
+    field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+    field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
+    field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+    field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+    field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+    field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+    field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
+    field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+    field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+    field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+    field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
+    field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+    field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
+    field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
+    field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
+    field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+    field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
+    field public static final java.lang.String TAG_MAKE = "Make";
+    field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+    field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+    field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
+    field public static final java.lang.String TAG_MODEL = "Model";
+    field public static final java.lang.String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
+    field public static final java.lang.String TAG_OECF = "OECF";
+    field public static final java.lang.String TAG_ORF_ASPECT_FRAME = "AspectFrame";
+    field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
+    field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
+    field public static final java.lang.String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
+    field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+    field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+    field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+    field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+    field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+    field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+    field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+    field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+    field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+    field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+    field public static final java.lang.String TAG_RW2_ISO = "ISO";
+    field public static final java.lang.String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
+    field public static final java.lang.String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
+    field public static final java.lang.String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
+    field public static final java.lang.String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
+    field public static final java.lang.String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
+    field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+    field public static final java.lang.String TAG_SATURATION = "Saturation";
+    field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+    field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+    field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+    field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+    field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+    field public static final java.lang.String TAG_SOFTWARE = "Software";
+    field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+    field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+    field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+    field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+    field public static final java.lang.String TAG_SUBFILE_TYPE = "SubfileType";
+    field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+    field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
+    field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
+    field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
+    field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+    field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+    field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
+    field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+    field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+    field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+    field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+    field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+    field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+    field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
+    field public static final int WHITEBALANCE_AUTO = 0; // 0x0
+    field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
+  }
+
+}
+
+package android.support.media.instantvideo.preload {
+
+  public class InstantVideoPreloadManager {
+    method public void clearCache();
+    method public static synchronized android.support.media.instantvideo.preload.InstantVideoPreloadManager getInstance(android.content.Context);
+    method public void preload(android.net.Uri);
+    method public void setMaxCacheSize(int);
+    method public void setMaxPreloadVideoCount(int);
+  }
+
+}
+
+package android.support.media.instantvideo.widget {
+
+  public class InstantVideoView extends android.widget.FrameLayout {
+    ctor public InstantVideoView(android.content.Context);
+    ctor public InstantVideoView(android.content.Context, android.util.AttributeSet);
+    ctor public InstantVideoView(android.content.Context, android.util.AttributeSet, int);
+    method public int getCurrentPosition();
+    method public void seekTo(int);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setVideoUri(android.net.Uri);
+    method public void start();
+    method public void stop();
+  }
+
+}
+
+package android.support.media.tv {
+
+  public final class Channel {
+    method public static android.support.media.tv.Channel fromCursor(android.database.Cursor);
+    method public int getAppLinkColor();
+    method public android.net.Uri getAppLinkIconUri();
+    method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+    method public android.net.Uri getAppLinkIntentUri();
+    method public android.net.Uri getAppLinkPosterArtUri();
+    method public java.lang.String getAppLinkText();
+    method public java.lang.String getChannelLogo();
+    method public java.lang.String getDescription();
+    method public java.lang.String getDisplayName();
+    method public java.lang.String getDisplayNumber();
+    method public long getId();
+    method public java.lang.String getInputId();
+    method public byte[] getInternalProviderDataByteArray();
+    method public java.lang.Long getInternalProviderFlag1();
+    method public java.lang.Long getInternalProviderFlag2();
+    method public java.lang.Long getInternalProviderFlag3();
+    method public java.lang.Long getInternalProviderFlag4();
+    method public java.lang.String getNetworkAffiliation();
+    method public int getOriginalNetworkId();
+    method public java.lang.String getPackageName();
+    method public int getServiceId();
+    method public java.lang.String getServiceType();
+    method public int getTransportStreamId();
+    method public java.lang.String getType();
+    method public java.lang.String getVideoFormat();
+    method public boolean isSearchable();
+    method public android.content.ContentValues toContentValues();
+  }
+
+  public static final class Channel.Builder {
+    ctor public Channel.Builder();
+    ctor public Channel.Builder(android.support.media.tv.Channel);
+    method public android.support.media.tv.Channel build();
+    method public android.support.media.tv.Channel.Builder setAppLinkColor(int);
+    method public android.support.media.tv.Channel.Builder setAppLinkIconUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkIntent(android.content.Intent);
+    method public android.support.media.tv.Channel.Builder setAppLinkIntentUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkPosterArtUri(android.net.Uri);
+    method public android.support.media.tv.Channel.Builder setAppLinkText(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setChannelLogo(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDescription(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDisplayName(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setDisplayNumber(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInputId(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInternalProviderData(byte[]);
+    method public android.support.media.tv.Channel.Builder setInternalProviderData(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag1(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag2(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag3(long);
+    method public android.support.media.tv.Channel.Builder setInternalProviderFlag4(long);
+    method public android.support.media.tv.Channel.Builder setNetworkAffiliation(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setOriginalNetworkId(int);
+    method public android.support.media.tv.Channel.Builder setPackageName(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setSearchable(boolean);
+    method public android.support.media.tv.Channel.Builder setServiceId(int);
+    method public android.support.media.tv.Channel.Builder setServiceType(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setTransportStreamId(int);
+    method public android.support.media.tv.Channel.Builder setType(java.lang.String);
+    method public android.support.media.tv.Channel.Builder setVideoFormat(java.lang.String);
+  }
+
+  public final class Program implements java.lang.Comparable {
+    method public int compareTo(android.support.media.tv.Program);
+    method public static android.support.media.tv.Program fromCursor(android.database.Cursor);
+    method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+    method public android.net.Uri getAppLinkIntentUri();
+    method public java.lang.String[] getAudioLanguages();
+    method public java.lang.String getAuthor();
+    method public java.lang.String getAvailability();
+    method public java.lang.String[] getBroadcastGenres();
+    method public java.lang.String[] getCanonicalGenres();
+    method public long getChannelId();
+    method public android.media.tv.TvContentRating[] getContentRatings();
+    method public java.lang.String getDescription();
+    method public int getDurationMillis();
+    method public long getEndTimeUtcMillis();
+    method public java.lang.String getEpisodeNumber();
+    method public java.lang.String getEpisodeTitle();
+    method public long getId();
+    method public int getInteractionCount();
+    method public java.lang.String getInteractionType();
+    method public byte[] getInternalProviderDataByteArray();
+    method public java.lang.Long getInternalProviderFlag1();
+    method public java.lang.Long getInternalProviderFlag2();
+    method public java.lang.Long getInternalProviderFlag3();
+    method public java.lang.Long getInternalProviderFlag4();
+    method public java.lang.String getInternalProviderId();
+    method public int getItemCount();
+    method public int getLastPlaybackPositionMillis();
+    method public android.net.Uri getLogoUri();
+    method public java.lang.String getLongDescription();
+    method public java.lang.String getOfferPrice();
+    method public java.lang.String getPosterArtAspectRatio();
+    method public android.net.Uri getPosterArtUri();
+    method public android.net.Uri getPreviewVideoUri();
+    method public java.lang.String getReleaseDate();
+    method public java.lang.String getReviewRating();
+    method public java.lang.String getReviewRatingStyle();
+    method public java.lang.String getSeasonNumber();
+    method public java.lang.String getSeasonTitle();
+    method public long getStartTimeUtcMillis();
+    method public java.lang.String getStartingPrice();
+    method public java.lang.String getThumbnailAspectRatio();
+    method public android.net.Uri getThumbnailUri();
+    method public java.lang.String getTitle();
+    method public java.lang.String getType();
+    method public int getVideoHeight();
+    method public int getVideoWidth();
+    method public java.lang.String getWatchNextType();
+    method public int getWeight();
+    method public boolean isLive();
+    method public boolean isRecordingProhibited();
+    method public boolean isSearchable();
+    method public android.content.ContentValues toContentValues();
+  }
+
+  public static final class Program.Builder {
+    ctor public Program.Builder();
+    ctor public Program.Builder(android.support.media.tv.Program);
+    method public android.support.media.tv.Program build();
+    method public android.support.media.tv.Program.Builder setAppLinkIntent(android.content.Intent);
+    method public android.support.media.tv.Program.Builder setAppLinkIntentUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setAudioLanguages(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setAuthor(java.lang.String);
+    method public android.support.media.tv.Program.Builder setAvailability(java.lang.String);
+    method public android.support.media.tv.Program.Builder setBroadcastGenres(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setCanonicalGenres(java.lang.String[]);
+    method public android.support.media.tv.Program.Builder setChannelId(long);
+    method public android.support.media.tv.Program.Builder setContentRatings(android.media.tv.TvContentRating[]);
+    method public android.support.media.tv.Program.Builder setDescription(java.lang.String);
+    method public android.support.media.tv.Program.Builder setDurationMillis(int);
+    method public android.support.media.tv.Program.Builder setEndTimeUtcMillis(long);
+    method public android.support.media.tv.Program.Builder setEpisodeNumber(int);
+    method public android.support.media.tv.Program.Builder setEpisodeNumber(java.lang.String, int);
+    method public android.support.media.tv.Program.Builder setEpisodeTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setId(long);
+    method public android.support.media.tv.Program.Builder setInteractionCount(int);
+    method public android.support.media.tv.Program.Builder setInteractionType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setInternalProviderData(byte[]);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag1(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag2(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag3(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderFlag4(long);
+    method public android.support.media.tv.Program.Builder setInternalProviderId(java.lang.String);
+    method public android.support.media.tv.Program.Builder setItemCount(int);
+    method public android.support.media.tv.Program.Builder setLastPlaybackPositionMillis(int);
+    method public android.support.media.tv.Program.Builder setLive(boolean);
+    method public android.support.media.tv.Program.Builder setLogoUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setLongDescription(java.lang.String);
+    method public android.support.media.tv.Program.Builder setOfferPrice(java.lang.String);
+    method public android.support.media.tv.Program.Builder setPosterArtAspectRatio(java.lang.String);
+    method public android.support.media.tv.Program.Builder setPosterArtUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setPreviewVideoUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setRecordingProhibited(boolean);
+    method public android.support.media.tv.Program.Builder setReleaseDate(java.lang.String);
+    method public android.support.media.tv.Program.Builder setReleaseDate(java.util.Date);
+    method public android.support.media.tv.Program.Builder setReviewRating(java.lang.String);
+    method public android.support.media.tv.Program.Builder setReviewRatingStyle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setSearchable(boolean);
+    method public android.support.media.tv.Program.Builder setSeasonNumber(int);
+    method public android.support.media.tv.Program.Builder setSeasonNumber(java.lang.String, int);
+    method public android.support.media.tv.Program.Builder setSeasonTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setStartTimeUtcMillis(long);
+    method public android.support.media.tv.Program.Builder setStartingPrice(java.lang.String);
+    method public android.support.media.tv.Program.Builder setThumbnailAspectRatio(java.lang.String);
+    method public android.support.media.tv.Program.Builder setThumbnailUri(android.net.Uri);
+    method public android.support.media.tv.Program.Builder setTitle(java.lang.String);
+    method public android.support.media.tv.Program.Builder setType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setVideoHeight(int);
+    method public android.support.media.tv.Program.Builder setVideoWidth(int);
+    method public android.support.media.tv.Program.Builder setWatchNextType(java.lang.String);
+    method public android.support.media.tv.Program.Builder setWeight(int);
+  }
+
+  public final class TvContractCompat {
+    method public static android.net.Uri buildChannelLogoUri(long);
+    method public static android.net.Uri buildChannelLogoUri(android.net.Uri);
+    method public static android.net.Uri buildChannelUri(long);
+    method public static android.net.Uri buildChannelUriForPassthroughInput(java.lang.String);
+    method public static android.net.Uri buildChannelsUriForInput(java.lang.String);
+    method public static java.lang.String buildInputId(android.content.ComponentName);
+    method public static android.net.Uri buildProgramUri(long);
+    method public static android.net.Uri buildProgramsUriForChannel(long);
+    method public static android.net.Uri buildProgramsUriForChannel(android.net.Uri);
+    method public static android.net.Uri buildProgramsUriForChannel(long, long, long);
+    method public static android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
+    method public static android.net.Uri buildRecordedProgramUri(long);
+    method public static boolean isChannelUri(android.net.Uri);
+    method public static boolean isChannelUriForPassthroughInput(android.net.Uri);
+    method public static boolean isChannelUriForTunerInput(android.net.Uri);
+    method public static boolean isProgramUri(android.net.Uri);
+    field public static final java.lang.String AUTHORITY = "android.media.tv";
+  }
+
+  public static abstract interface TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
+  }
+
+  public static final class TvContractCompat.Channels implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    method public static java.lang.String getVideoResolution(java.lang.String);
+    field public static final java.lang.String COLUMN_APP_LINK_COLOR = "app_link_color";
+    field public static final java.lang.String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
+    field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
+    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+    field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
+    field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
+    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
+    field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
+    field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_FORMAT = "video_format";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
+    field public static final java.lang.String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
+    field public static final java.lang.String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
+    field public static final java.lang.String TYPE_1SEG = "TYPE_1SEG";
+    field public static final java.lang.String TYPE_ATSC_C = "TYPE_ATSC_C";
+    field public static final java.lang.String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
+    field public static final java.lang.String TYPE_ATSC_T = "TYPE_ATSC_T";
+    field public static final java.lang.String TYPE_CMMB = "TYPE_CMMB";
+    field public static final java.lang.String TYPE_DTMB = "TYPE_DTMB";
+    field public static final java.lang.String TYPE_DVB_C = "TYPE_DVB_C";
+    field public static final java.lang.String TYPE_DVB_C2 = "TYPE_DVB_C2";
+    field public static final java.lang.String TYPE_DVB_H = "TYPE_DVB_H";
+    field public static final java.lang.String TYPE_DVB_S = "TYPE_DVB_S";
+    field public static final java.lang.String TYPE_DVB_S2 = "TYPE_DVB_S2";
+    field public static final java.lang.String TYPE_DVB_SH = "TYPE_DVB_SH";
+    field public static final java.lang.String TYPE_DVB_T = "TYPE_DVB_T";
+    field public static final java.lang.String TYPE_DVB_T2 = "TYPE_DVB_T2";
+    field public static final java.lang.String TYPE_ISDB_C = "TYPE_ISDB_C";
+    field public static final java.lang.String TYPE_ISDB_S = "TYPE_ISDB_S";
+    field public static final java.lang.String TYPE_ISDB_T = "TYPE_ISDB_T";
+    field public static final java.lang.String TYPE_ISDB_TB = "TYPE_ISDB_TB";
+    field public static final java.lang.String TYPE_NTSC = "TYPE_NTSC";
+    field public static final java.lang.String TYPE_OTHER = "TYPE_OTHER";
+    field public static final java.lang.String TYPE_PAL = "TYPE_PAL";
+    field public static final java.lang.String TYPE_PREVIEW = "TYPE_PREVIEW";
+    field public static final java.lang.String TYPE_SECAM = "TYPE_SECAM";
+    field public static final java.lang.String TYPE_S_DMB = "TYPE_S_DMB";
+    field public static final java.lang.String TYPE_T_DMB = "TYPE_T_DMB";
+    field public static final java.lang.String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
+    field public static final java.lang.String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
+    field public static final java.lang.String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
+    field public static final java.lang.String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
+    field public static final java.lang.String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
+    field public static final java.lang.String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
+    field public static final java.lang.String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
+    field public static final java.lang.String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
+    field public static final java.lang.String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
+    field public static final java.lang.String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
+    field public static final java.lang.String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
+    field public static final java.lang.String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
+    field public static final java.lang.String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
+    field public static final java.lang.String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
+    field public static final java.lang.String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
+    field public static final java.lang.String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
+  }
+
+  public static final class TvContractCompat.Channels.Logo {
+    field public static final java.lang.String CONTENT_DIRECTORY = "logo";
+  }
+
+  public static final class TvContractCompat.Programs implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+    field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+    field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+    field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+    field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+    field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+    field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_AUTHOR = "author";
+    field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+    field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+    field public static final java.lang.String COLUMN_WEIGHT = "weight";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+    field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+    field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+    field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+    field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+    field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+    field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+    field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+    field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+    field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+    field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+    field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+    field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+    field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+    field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+    field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+    field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+    field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+    field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+    field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+    field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+    field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+    field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+    field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+    field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+  }
+
+  public static final class TvContractCompat.Programs.Genres {
+    method public static java.lang.String[] decode(java.lang.String);
+    method public static java.lang.String encode(java.lang.String...);
+    method public static boolean isCanonical(java.lang.String);
+    field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
+    field public static final java.lang.String ARTS = "ARTS";
+    field public static final java.lang.String COMEDY = "COMEDY";
+    field public static final java.lang.String DRAMA = "DRAMA";
+    field public static final java.lang.String EDUCATION = "EDUCATION";
+    field public static final java.lang.String ENTERTAINMENT = "ENTERTAINMENT";
+    field public static final java.lang.String FAMILY_KIDS = "FAMILY_KIDS";
+    field public static final java.lang.String GAMING = "GAMING";
+    field public static final java.lang.String LIFE_STYLE = "LIFE_STYLE";
+    field public static final java.lang.String MOVIES = "MOVIES";
+    field public static final java.lang.String MUSIC = "MUSIC";
+    field public static final java.lang.String NEWS = "NEWS";
+    field public static final java.lang.String PREMIER = "PREMIER";
+    field public static final java.lang.String SHOPPING = "SHOPPING";
+    field public static final java.lang.String SPORTS = "SPORTS";
+    field public static final java.lang.String TECH_SCIENCE = "TECH_SCIENCE";
+    field public static final java.lang.String TRAVEL = "TRAVEL";
+  }
+
+  public static final class TvContractCompat.RecordedPrograms implements android.support.media.tv.TvContractCompat.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+    field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
+    field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+    field public static final android.net.Uri CONTENT_URI;
+  }
+
+}
+
+package android.support.percent {
+
+  public class PercentFrameLayout extends android.widget.FrameLayout {
+    ctor public PercentFrameLayout(android.content.Context);
+    ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public static class PercentFrameLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+    ctor public PercentFrameLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public PercentFrameLayout.LayoutParams(int, int);
+    ctor public PercentFrameLayout.LayoutParams(int, int, int);
+    ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.support.percent.PercentFrameLayout.LayoutParams);
+    method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+  public class PercentLayoutHelper {
+    ctor public PercentLayoutHelper(android.view.ViewGroup);
+    method public void adjustChildren(int, int);
+    method public static void fetchWidthAndHeight(android.view.ViewGroup.LayoutParams, android.content.res.TypedArray, int, int);
+    method public static android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo(android.content.Context, android.util.AttributeSet);
+    method public boolean handleMeasuredStateTooSmall();
+    method public void restoreOriginalParams();
+  }
+
+  public static class PercentLayoutHelper.PercentLayoutInfo {
+    ctor public PercentLayoutHelper.PercentLayoutInfo();
+    method public void fillLayoutParams(android.view.ViewGroup.LayoutParams, int, int);
+    method public deprecated void fillMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams, int, int);
+    method public void fillMarginLayoutParams(android.view.View, android.view.ViewGroup.MarginLayoutParams, int, int);
+    method public void restoreLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public void restoreMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    field public float aspectRatio;
+    field public float bottomMarginPercent;
+    field public float endMarginPercent;
+    field public float heightPercent;
+    field public float leftMarginPercent;
+    field public float rightMarginPercent;
+    field public float startMarginPercent;
+    field public float topMarginPercent;
+    field public float widthPercent;
+  }
+
+  public static abstract interface PercentLayoutHelper.PercentLayoutParams {
+    method public abstract android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+  public class PercentRelativeLayout extends android.widget.RelativeLayout {
+    ctor public PercentRelativeLayout(android.content.Context);
+    ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet);
+    ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public static class PercentRelativeLayout.LayoutParams extends android.widget.RelativeLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+    ctor public PercentRelativeLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public PercentRelativeLayout.LayoutParams(int, int);
+    ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+}
+
+package android.support.transition {
+
+  public class AutoTransition extends android.support.transition.TransitionSet {
+    ctor public AutoTransition();
+  }
+
+  public class ChangeBounds extends android.support.transition.Transition {
+    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.Visibility {
+    ctor public Fade(int);
+    ctor public Fade();
+    field public static final int IN = 1; // 0x1
+    field public static final int OUT = 2; // 0x2
+  }
+
+  public class Scene {
+    ctor public Scene(android.view.ViewGroup);
+    ctor public Scene(android.view.ViewGroup, android.view.View);
+    method public void enter();
+    method public void exit();
+    method public static android.support.transition.Scene getSceneForLayout(android.view.ViewGroup, int, android.content.Context);
+    method public android.view.ViewGroup getSceneRoot();
+    method public void setEnterAction(java.lang.Runnable);
+    method public void setExitAction(java.lang.Runnable);
+  }
+
+  public abstract class Transition {
+    ctor public Transition();
+    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);
+    method public android.support.transition.Transition addTarget(java.lang.String);
+    method public android.support.transition.Transition addTarget(java.lang.Class);
+    method public abstract void captureEndValues(android.support.transition.TransitionValues);
+    method public abstract void captureStartValues(android.support.transition.TransitionValues);
+    method public android.support.transition.Transition clone();
+    method public android.animation.Animator createAnimator(android.view.ViewGroup, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
+    method public android.support.transition.Transition excludeChildren(android.view.View, boolean);
+    method public android.support.transition.Transition excludeChildren(int, boolean);
+    method public android.support.transition.Transition excludeChildren(java.lang.Class, boolean);
+    method public android.support.transition.Transition excludeTarget(android.view.View, boolean);
+    method public android.support.transition.Transition excludeTarget(int, boolean);
+    method public android.support.transition.Transition excludeTarget(java.lang.String, boolean);
+    method public android.support.transition.Transition excludeTarget(java.lang.Class, boolean);
+    method public long getDuration();
+    method public android.animation.TimeInterpolator getInterpolator();
+    method public java.lang.String getName();
+    method public long getStartDelay();
+    method public java.util.List<java.lang.Integer> getTargetIds();
+    method public java.util.List<java.lang.String> getTargetNames();
+    method public java.util.List<java.lang.Class> getTargetTypes();
+    method public java.util.List<android.view.View> getTargets();
+    method public java.lang.String[] getTransitionProperties();
+    method public android.support.transition.TransitionValues getTransitionValues(android.view.View, boolean);
+    method public android.support.transition.Transition removeListener(android.support.transition.Transition.TransitionListener);
+    method public android.support.transition.Transition removeTarget(android.view.View);
+    method public android.support.transition.Transition removeTarget(int);
+    method public android.support.transition.Transition removeTarget(java.lang.String);
+    method public android.support.transition.Transition removeTarget(java.lang.Class);
+    method public android.support.transition.Transition setDuration(long);
+    method public android.support.transition.Transition setInterpolator(android.animation.TimeInterpolator);
+    method public void setMatchOrder(int...);
+    method public android.support.transition.Transition setStartDelay(long);
+    field public static final int MATCH_ID = 3; // 0x3
+    field public static final int MATCH_INSTANCE = 1; // 0x1
+    field public static final int MATCH_ITEM_ID = 4; // 0x4
+    field public static final int MATCH_NAME = 2; // 0x2
+  }
+
+  public static abstract interface Transition.TransitionListener {
+    method public abstract void onTransitionCancel(android.support.transition.Transition);
+    method public abstract void onTransitionEnd(android.support.transition.Transition);
+    method public abstract void onTransitionPause(android.support.transition.Transition);
+    method public abstract void onTransitionResume(android.support.transition.Transition);
+    method public abstract void onTransitionStart(android.support.transition.Transition);
+  }
+
+  public class TransitionManager {
+    ctor public TransitionManager();
+    method public static void beginDelayedTransition(android.view.ViewGroup);
+    method public static void beginDelayedTransition(android.view.ViewGroup, android.support.transition.Transition);
+    method public static void go(android.support.transition.Scene);
+    method public static void go(android.support.transition.Scene, android.support.transition.Transition);
+    method public void setTransition(android.support.transition.Scene, android.support.transition.Transition);
+    method public void setTransition(android.support.transition.Scene, android.support.transition.Scene, android.support.transition.Transition);
+    method public void transitionTo(android.support.transition.Scene);
+  }
+
+  public class TransitionSet extends android.support.transition.Transition {
+    ctor public TransitionSet();
+    method public android.support.transition.TransitionSet addTransition(android.support.transition.Transition);
+    method public void captureEndValues(android.support.transition.TransitionValues);
+    method public void captureStartValues(android.support.transition.TransitionValues);
+    method public int getOrdering();
+    method public android.support.transition.Transition getTransitionAt(int);
+    method public int getTransitionCount();
+    method public android.support.transition.TransitionSet removeTransition(android.support.transition.Transition);
+    method public android.support.transition.TransitionSet setOrdering(int);
+    field public static final int ORDERING_SEQUENTIAL = 1; // 0x1
+    field public static final int ORDERING_TOGETHER = 0; // 0x0
+  }
+
+  public class TransitionValues {
+    ctor public TransitionValues();
+    field public final java.util.Map<java.lang.String, java.lang.Object> values;
+    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 {
+
+  public class ActivityCompat extends android.support.v4.app.ActivityCompat {
+    ctor protected ActivityCompat();
+    method public static android.support.v13.view.DragAndDropPermissionsCompat requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
+  }
+
+  public class FragmentCompat {
+    ctor public FragmentCompat();
+    method public static void requestPermissions(android.app.Fragment, java.lang.String[], int);
+    method public static void setMenuVisibility(android.app.Fragment, boolean);
+    method public static void setUserVisibleHint(android.app.Fragment, boolean);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Fragment, java.lang.String);
+  }
+
+  public static abstract interface FragmentCompat.OnRequestPermissionsResultCallback {
+    method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+  }
+
+  public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentPagerAdapter(android.app.FragmentManager);
+    method public abstract android.app.Fragment getItem(int);
+    method public long getItemId(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public abstract class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentStatePagerAdapter(android.app.FragmentManager);
+    method public abstract android.app.Fragment getItem(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor public FragmentTabHost(android.content.Context);
+    ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
+    method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
+    method public void onTabChanged(java.lang.String);
+    method public void setup(android.content.Context, android.app.FragmentManager);
+    method public void setup(android.content.Context, android.app.FragmentManager, int);
+  }
+
+}
+
+package android.support.v13.view {
+
+  public final class DragAndDropPermissionsCompat {
+    method public void release();
+  }
+
+  public class DragStartHelper {
+    ctor public DragStartHelper(android.view.View, android.support.v13.view.DragStartHelper.OnDragStartListener);
+    method public void attach();
+    method public void detach();
+    method public void getTouchPosition(android.graphics.Point);
+    method public boolean onLongClick(android.view.View);
+    method public boolean onTouch(android.view.View, android.view.MotionEvent);
+  }
+
+  public static abstract interface DragStartHelper.OnDragStartListener {
+    method public abstract boolean onDragStart(android.view.View, android.support.v13.view.DragStartHelper);
+  }
+
+  public class ViewCompat extends android.support.v4.view.ViewCompat {
+    method public static void cancelDragAndDrop(android.view.View);
+    method public static boolean startDragAndDrop(android.view.View, android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
+    method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+  }
+
+}
+
+package android.support.v13.view.inputmethod {
+
+  public final class EditorInfoCompat {
+    ctor public EditorInfoCompat();
+    method public static java.lang.String[] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+    method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, java.lang.String[]);
+    field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+  }
+
+  public final class InputConnectionCompat {
+    ctor public InputConnectionCompat();
+    method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
+    method public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+    field public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
+  }
+
+  public static abstract interface InputConnectionCompat.OnCommitContentListener {
+    method public abstract boolean onCommitContent(android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
+  }
+
+  public final class InputContentInfoCompat {
+    ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri getLinkUri();
+    method public void releasePermission();
+    method public void requestPermission();
+    method public java.lang.Object unwrap();
+    method public static android.support.v13.view.inputmethod.InputContentInfoCompat wrap(java.lang.Object);
+  }
+
+}
+
+package android.support.v14.preference {
+
+  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public EditTextPreferenceDialogFragment();
+    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public ListPreferenceDialogFragment();
+    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class MultiSelectListPreference extends android.support.v7.preference.DialogPreference {
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
+    ctor public MultiSelectListPreference(android.content.Context);
+    method public int findIndexOfValue(java.lang.String);
+    method public java.lang.CharSequence[] getEntries();
+    method public java.lang.CharSequence[] getEntryValues();
+    method protected boolean[] getSelectedItems();
+    method public java.util.Set<java.lang.String> getValues();
+    method public void setEntries(java.lang.CharSequence[]);
+    method public void setEntries(int);
+    method public void setEntryValues(java.lang.CharSequence[]);
+    method public void setEntryValues(int);
+    method public void setValues(java.util.Set<java.lang.String>);
+  }
+
+  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public MultiSelectListPreferenceDialogFragment();
+    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+    ctor public PreferenceDialogFragment();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    method protected void onBindDialogView(android.view.View);
+    method public void onClick(android.content.DialogInterface, int);
+    method protected android.view.View onCreateDialogView(android.content.Context);
+    method public abstract void onDialogClosed(boolean);
+    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
+    field protected static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+    ctor public PreferenceFragment();
+    method public void addPreferencesFromResource(int);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public final android.support.v7.widget.RecyclerView getListView();
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void scrollToPreference(java.lang.String);
+    method public void scrollToPreference(android.support.v7.preference.Preference);
+    method public void setDivider(android.graphics.drawable.Drawable);
+    method public void setDividerHeight(int);
+    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+    method public void setPreferencesFromResource(int, java.lang.String);
+    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
+    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
+    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
+  }
+
+  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchPreference(android.content.Context);
+    method public java.lang.CharSequence getSwitchTextOff();
+    method public java.lang.CharSequence getSwitchTextOn();
+    method public void setSwitchTextOff(java.lang.CharSequence);
+    method public void setSwitchTextOff(int);
+    method public void setSwitchTextOn(java.lang.CharSequence);
+    method public void setSwitchTextOn(int);
+  }
+
+}
+
+package android.support.v17.leanback.app {
+
+  public final class BackgroundManager {
+    method public void attach(android.view.Window);
+    method public void attachToView(android.view.View);
+    method public void clearDrawable();
+    method public final int getColor();
+    method public deprecated android.graphics.drawable.Drawable getDefaultDimLayer();
+    method public deprecated android.graphics.drawable.Drawable getDimLayer();
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public static android.support.v17.leanback.app.BackgroundManager getInstance(android.app.Activity);
+    method public boolean isAttached();
+    method public boolean isAutoReleaseOnStop();
+    method public void release();
+    method public void setAutoReleaseOnStop(boolean);
+    method public void setBitmap(android.graphics.Bitmap);
+    method public void setColor(int);
+    method public deprecated void setDimLayer(android.graphics.drawable.Drawable);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setThemeDrawableResourceId(int);
+  }
+
+   abstract class BaseRowFragment extends android.app.Fragment {
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public int getSelectedPosition();
+    method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setAlignment(int);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+   abstract class BaseRowSupportFragment extends android.support.v4.app.Fragment {
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public int getSelectedPosition();
+    method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setAlignment(int);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+  public class BrandedFragment extends android.app.Fragment {
+    ctor public BrandedFragment();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public int getSearchAffordanceColor();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public java.lang.CharSequence getTitle();
+    method public android.view.View getTitleView();
+    method public android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void installTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public final boolean isShowingTitle();
+    method public android.view.View onInflateTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColor(int);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleView(android.view.View);
+    method public void showTitle(boolean);
+    method public void showTitle(int);
+  }
+
+  public class BrandedSupportFragment extends android.support.v4.app.Fragment {
+    ctor public BrandedSupportFragment();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public int getSearchAffordanceColor();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public java.lang.CharSequence getTitle();
+    method public android.view.View getTitleView();
+    method public android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void installTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public final boolean isShowingTitle();
+    method public android.view.View onInflateTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColor(int);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleView(android.view.View);
+    method public void showTitle(boolean);
+    method public void showTitle(int);
+  }
+
+  public class BrowseFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public BrowseFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
+    method public void enableMainFragmentScaling(boolean);
+    method public deprecated void enableRowScaling(boolean);
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBrandColor();
+    method public android.support.v17.leanback.app.HeadersFragment getHeadersFragment();
+    method public int getHeadersState();
+    method public android.app.Fragment getMainFragment();
+    method public final android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
+    method public int getSelectedPosition();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getSelectedRowViewHolder();
+    method public final boolean isHeadersTransitionOnBackEnabled();
+    method public boolean isInHeadersTransition();
+    method public boolean isShowingHeaders();
+    method public android.support.v17.leanback.app.HeadersFragment onCreateHeadersFragment();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBrandColor(int);
+    method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseFragment.BrowseTransitionListener);
+    method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setHeadersState(int);
+    method public final void setHeadersTransitionOnBackEnabled(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void startHeadersTransition(boolean);
+    field public static final int HEADERS_DISABLED = 3; // 0x3
+    field public static final int HEADERS_ENABLED = 1; // 0x1
+    field public static final int HEADERS_HIDDEN = 2; // 0x2
+  }
+
+  public static class BrowseFragment.BrowseTransitionListener {
+    ctor public BrowseFragment.BrowseTransitionListener();
+    method public void onHeadersTransitionStart(boolean);
+    method public void onHeadersTransitionStop(boolean);
+  }
+
+  public static abstract class BrowseFragment.FragmentFactory<T extends android.app.Fragment> {
+    ctor public BrowseFragment.FragmentFactory();
+    method public abstract T createFragment(java.lang.Object);
+  }
+
+  public static abstract interface BrowseFragment.FragmentHost {
+    method public abstract void notifyDataReady(android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter);
+    method public abstract void notifyViewCreated(android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter);
+    method public abstract void showTitleView(boolean);
+  }
+
+  public static class BrowseFragment.ListRowFragmentFactory extends android.support.v17.leanback.app.BrowseFragment.FragmentFactory {
+    ctor public BrowseFragment.ListRowFragmentFactory();
+    method public android.support.v17.leanback.app.RowsFragment createFragment(java.lang.Object);
+  }
+
+  public static class BrowseFragment.MainFragmentAdapter<T extends android.app.Fragment> {
+    ctor public BrowseFragment.MainFragmentAdapter(T);
+    method public final T getFragment();
+    method public final android.support.v17.leanback.app.BrowseFragment.FragmentHost getFragmentHost();
+    method public boolean isScalingEnabled();
+    method public boolean isScrolling();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public void setAlignment(int);
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setScalingEnabled(boolean);
+  }
+
+  public static abstract interface BrowseFragment.MainFragmentAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter getMainFragmentAdapter();
+  }
+
+  public static final class BrowseFragment.MainFragmentAdapterRegistry {
+    ctor public BrowseFragment.MainFragmentAdapterRegistry();
+    method public android.app.Fragment createFragment(java.lang.Object);
+    method public void registerFragment(java.lang.Class, android.support.v17.leanback.app.BrowseFragment.FragmentFactory);
+  }
+
+  public static class BrowseFragment.MainFragmentRowsAdapter<T extends android.app.Fragment> {
+    ctor public BrowseFragment.MainFragmentRowsAdapter(T);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public final T getFragment();
+    method public int getSelectedPosition();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+  public static abstract interface BrowseFragment.MainFragmentRowsAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+  }
+
+  public class BrowseSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public BrowseSupportFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
+    method public void enableMainFragmentScaling(boolean);
+    method public deprecated void enableRowScaling(boolean);
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBrandColor();
+    method public int getHeadersState();
+    method public android.support.v17.leanback.app.HeadersSupportFragment getHeadersSupportFragment();
+    method public android.support.v4.app.Fragment getMainFragment();
+    method public final android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
+    method public int getSelectedPosition();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getSelectedRowViewHolder();
+    method public final boolean isHeadersTransitionOnBackEnabled();
+    method public boolean isInHeadersTransition();
+    method public boolean isShowingHeaders();
+    method public android.support.v17.leanback.app.HeadersSupportFragment onCreateHeadersSupportFragment();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBrandColor(int);
+    method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseSupportFragment.BrowseTransitionListener);
+    method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setHeadersState(int);
+    method public final void setHeadersTransitionOnBackEnabled(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void startHeadersTransition(boolean);
+    field public static final int HEADERS_DISABLED = 3; // 0x3
+    field public static final int HEADERS_ENABLED = 1; // 0x1
+    field public static final int HEADERS_HIDDEN = 2; // 0x2
+  }
+
+  public static class BrowseSupportFragment.BrowseTransitionListener {
+    ctor public BrowseSupportFragment.BrowseTransitionListener();
+    method public void onHeadersTransitionStart(boolean);
+    method public void onHeadersTransitionStop(boolean);
+  }
+
+  public static abstract class BrowseSupportFragment.FragmentFactory<T extends android.support.v4.app.Fragment> {
+    ctor public BrowseSupportFragment.FragmentFactory();
+    method public abstract T createFragment(java.lang.Object);
+  }
+
+  public static abstract interface BrowseSupportFragment.FragmentHost {
+    method public abstract void notifyDataReady(android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter);
+    method public abstract void notifyViewCreated(android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter);
+    method public abstract void showTitleView(boolean);
+  }
+
+  public static class BrowseSupportFragment.ListRowFragmentFactory extends android.support.v17.leanback.app.BrowseSupportFragment.FragmentFactory {
+    ctor public BrowseSupportFragment.ListRowFragmentFactory();
+    method public android.support.v17.leanback.app.RowsSupportFragment createFragment(java.lang.Object);
+  }
+
+  public static class BrowseSupportFragment.MainFragmentAdapter<T extends android.support.v4.app.Fragment> {
+    ctor public BrowseSupportFragment.MainFragmentAdapter(T);
+    method public final T getFragment();
+    method public final android.support.v17.leanback.app.BrowseSupportFragment.FragmentHost getFragmentHost();
+    method public boolean isScalingEnabled();
+    method public boolean isScrolling();
+    method public void onTransitionEnd();
+    method public boolean onTransitionPrepare();
+    method public void onTransitionStart();
+    method public void setAlignment(int);
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setScalingEnabled(boolean);
+  }
+
+  public static abstract interface BrowseSupportFragment.MainFragmentAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter getMainFragmentAdapter();
+  }
+
+  public static final class BrowseSupportFragment.MainFragmentAdapterRegistry {
+    ctor public BrowseSupportFragment.MainFragmentAdapterRegistry();
+    method public android.support.v4.app.Fragment createFragment(java.lang.Object);
+    method public void registerFragment(java.lang.Class, android.support.v17.leanback.app.BrowseSupportFragment.FragmentFactory);
+  }
+
+  public static class BrowseSupportFragment.MainFragmentRowsAdapter<T extends android.support.v4.app.Fragment> {
+    ctor public BrowseSupportFragment.MainFragmentRowsAdapter(T);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public final T getFragment();
+    method public int getSelectedPosition();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+  public static abstract interface BrowseSupportFragment.MainFragmentRowsAdapterProvider {
+    method public abstract android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+  }
+
+  public class DetailsFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public DetailsFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.DetailsParallax getParallax();
+    method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
+    method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+    method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+    method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+  }
+
+  public class DetailsFragmentBackgroundController {
+    ctor public DetailsFragmentBackgroundController(android.support.v17.leanback.app.DetailsFragment);
+    method public void enableParallax();
+    method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.support.v17.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
+    method public final android.app.Fragment findOrCreateVideoFragment();
+    method public final android.graphics.drawable.Drawable getBottomDrawable();
+    method public final android.graphics.Bitmap getCoverBitmap();
+    method public final android.graphics.drawable.Drawable getCoverDrawable();
+    method public final int getParallaxDrawableMaxOffset();
+    method public final int getSolidColor();
+    method public android.support.v17.leanback.media.PlaybackGlueHost onCreateGlueHost();
+    method public android.app.Fragment onCreateVideoFragment();
+    method public final void setCoverBitmap(android.graphics.Bitmap);
+    method public final void setParallaxDrawableMaxOffset(int);
+    method public final void setSolidColor(int);
+    method public void setupVideoPlayback(android.support.v17.leanback.media.PlaybackGlue);
+  }
+
+  public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public DetailsSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.DetailsParallax getParallax();
+    method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
+    method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+    method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+    method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+  }
+
+  public class DetailsSupportFragmentBackgroundController {
+    ctor public DetailsSupportFragmentBackgroundController(android.support.v17.leanback.app.DetailsSupportFragment);
+    method public void enableParallax();
+    method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.support.v17.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
+    method public final android.support.v4.app.Fragment findOrCreateVideoSupportFragment();
+    method public final android.graphics.drawable.Drawable getBottomDrawable();
+    method public final android.graphics.Bitmap getCoverBitmap();
+    method public final android.graphics.drawable.Drawable getCoverDrawable();
+    method public final int getParallaxDrawableMaxOffset();
+    method public final int getSolidColor();
+    method public android.support.v17.leanback.media.PlaybackGlueHost onCreateGlueHost();
+    method public android.support.v4.app.Fragment onCreateVideoSupportFragment();
+    method public final void setCoverBitmap(android.graphics.Bitmap);
+    method public final void setParallaxDrawableMaxOffset(int);
+    method public final void setSolidColor(int);
+    method public void setupVideoPlayback(android.support.v17.leanback.media.PlaybackGlue);
+  }
+
+  public class ErrorFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public ErrorFragment();
+    method public android.graphics.drawable.Drawable getBackgroundDrawable();
+    method public android.view.View.OnClickListener getButtonClickListener();
+    method public java.lang.String getButtonText();
+    method public android.graphics.drawable.Drawable getImageDrawable();
+    method public java.lang.CharSequence getMessage();
+    method public boolean isBackgroundTranslucent();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonClickListener(android.view.View.OnClickListener);
+    method public void setButtonText(java.lang.String);
+    method public void setDefaultBackground(boolean);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setMessage(java.lang.CharSequence);
+  }
+
+  public class ErrorSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public ErrorSupportFragment();
+    method public android.graphics.drawable.Drawable getBackgroundDrawable();
+    method public android.view.View.OnClickListener getButtonClickListener();
+    method public java.lang.String getButtonText();
+    method public android.graphics.drawable.Drawable getImageDrawable();
+    method public java.lang.CharSequence getMessage();
+    method public boolean isBackgroundTranslucent();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonClickListener(android.view.View.OnClickListener);
+    method public void setButtonText(java.lang.String);
+    method public void setDefaultBackground(boolean);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setMessage(java.lang.CharSequence);
+  }
+
+  public class GuidedStepFragment extends android.app.Fragment {
+    ctor public GuidedStepFragment();
+    method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment);
+    method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public static int addAsRoot(android.app.Activity, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public void collapseAction(boolean);
+    method public void collapseSubActions();
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public void expandSubActions(android.support.v17.leanback.widget.GuidedAction);
+    method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+    method public int findActionPositionById(long);
+    method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+    method public int findButtonActionPositionById(long);
+    method public void finishGuidedStepFragments();
+    method public android.view.View getActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method public android.view.View getButtonActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
+    method public static android.support.v17.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
+    method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+    method public int getSelectedActionPosition();
+    method public int getSelectedButtonActionPosition();
+    method public int getUiStyle();
+    method public boolean isExpanded();
+    method public boolean isFocusOutEndAllowed();
+    method public boolean isFocusOutStartAllowed();
+    method public boolean isSubActionsExpanded();
+    method public void notifyActionChanged(int);
+    method public void notifyButtonActionChanged(int);
+    method protected void onAddSharedElementTransition(android.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepFragment);
+    method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
+    method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+    method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEditCanceled(android.support.v17.leanback.widget.GuidedAction);
+    method public deprecated void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected void onProvideFragmentTransitions();
+    method public int onProvideTheme();
+    method public boolean onSubGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void popBackStackToGuidedStepFragment(java.lang.Class, int);
+    method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setSelectedActionPosition(int);
+    method public void setSelectedButtonActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final deprecated int UI_STYLE_DEFAULT = 0; // 0x0
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+    field public static final int UI_STYLE_REPLACE = 0; // 0x0
+  }
+
+  public class GuidedStepSupportFragment extends android.support.v4.app.Fragment {
+    ctor public GuidedStepSupportFragment();
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment);
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public static int addAsRoot(android.support.v4.app.FragmentActivity, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public void collapseAction(boolean);
+    method public void collapseSubActions();
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public void expandSubActions(android.support.v17.leanback.widget.GuidedAction);
+    method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+    method public int findActionPositionById(long);
+    method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+    method public int findButtonActionPositionById(long);
+    method public void finishGuidedStepSupportFragments();
+    method public android.view.View getActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method public android.view.View getButtonActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
+    method public static android.support.v17.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(android.support.v4.app.FragmentManager);
+    method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+    method public int getSelectedActionPosition();
+    method public int getSelectedButtonActionPosition();
+    method public int getUiStyle();
+    method public boolean isExpanded();
+    method public boolean isFocusOutEndAllowed();
+    method public boolean isFocusOutStartAllowed();
+    method public boolean isSubActionsExpanded();
+    method public void notifyActionChanged(int);
+    method public void notifyButtonActionChanged(int);
+    method protected void onAddSharedElementTransition(android.support.v4.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepSupportFragment);
+    method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
+    method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+    method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEditCanceled(android.support.v17.leanback.widget.GuidedAction);
+    method public deprecated void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected void onProvideFragmentTransitions();
+    method public int onProvideTheme();
+    method public boolean onSubGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void popBackStackToGuidedStepSupportFragment(java.lang.Class, int);
+    method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setSelectedActionPosition(int);
+    method public void setSelectedButtonActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final deprecated int UI_STYLE_DEFAULT = 0; // 0x0
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+    field public static final int UI_STYLE_REPLACE = 0; // 0x0
+  }
+
+  public class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
+    ctor public HeadersFragment();
+    method public boolean isScrolling();
+    method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener);
+    method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener);
+  }
+
+  public static abstract interface HeadersFragment.OnHeaderClickedListener {
+    method public abstract void onHeaderClicked(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public static abstract interface HeadersFragment.OnHeaderViewSelectedListener {
+    method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public class HeadersSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment {
+    ctor public HeadersSupportFragment();
+    method public boolean isScrolling();
+    method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener);
+    method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener);
+  }
+
+  public static abstract interface HeadersSupportFragment.OnHeaderClickedListener {
+    method public abstract void onHeaderClicked(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public static abstract interface HeadersSupportFragment.OnHeaderViewSelectedListener {
+    method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public abstract deprecated class MediaControllerGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
+    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
+    method public void detach();
+    method public int getCurrentPosition();
+    method public int getCurrentSpeedId();
+    method public android.graphics.drawable.Drawable getMediaArt();
+    method public final android.support.v4.media.session.MediaControllerCompat getMediaController();
+    method public int getMediaDuration();
+    method public java.lang.CharSequence getMediaSubtitle();
+    method public java.lang.CharSequence getMediaTitle();
+    method public long getSupportedActions();
+    method public boolean hasValidMedia();
+    method public boolean isMediaPlaying();
+  }
+
+  public abstract class OnboardingFragment extends android.app.Fragment {
+    ctor public OnboardingFragment();
+    method protected final int getCurrentPageIndex();
+    method public final int getIconResourceId();
+    method public final int getLogoResourceId();
+    method protected abstract int getPageCount();
+    method protected abstract java.lang.CharSequence getPageDescription(int);
+    method protected abstract java.lang.CharSequence getPageTitle(int);
+    method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateDescriptionAnimator();
+    method protected android.animation.Animator onCreateEnterAnimation();
+    method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateLogoAnimation();
+    method protected android.animation.Animator onCreateTitleAnimator();
+    method protected void onFinishFragment();
+    method protected void onPageChanged(int, int);
+    method public int onProvideTheme();
+    method public final void setIconResouceId(int);
+    method public final void setLogoResourceId(int);
+  }
+
+  public abstract class OnboardingSupportFragment extends android.support.v4.app.Fragment {
+    ctor public OnboardingSupportFragment();
+    method protected final int getCurrentPageIndex();
+    method public final int getIconResourceId();
+    method public final int getLogoResourceId();
+    method protected abstract int getPageCount();
+    method protected abstract java.lang.CharSequence getPageDescription(int);
+    method protected abstract java.lang.CharSequence getPageTitle(int);
+    method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateDescriptionAnimator();
+    method protected android.animation.Animator onCreateEnterAnimation();
+    method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
+    method protected android.animation.Animator onCreateLogoAnimation();
+    method protected android.animation.Animator onCreateTitleAnimator();
+    method protected void onFinishFragment();
+    method protected void onPageChanged(int, int);
+    method public int onProvideTheme();
+    method public final void setIconResouceId(int);
+    method public final void setLogoResourceId(int);
+  }
+
+  public abstract deprecated class PlaybackControlGlue extends android.support.v17.leanback.media.PlaybackControlGlue {
+    ctor public PlaybackControlGlue(android.content.Context, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
+    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+    method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    method public android.support.v17.leanback.app.PlaybackOverlayFragment getFragment();
+    method public deprecated android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public final void next();
+    method protected void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method public final void pause();
+    method protected deprecated void pausePlayback();
+    method public final void play(int);
+    method public final void previous();
+    method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method protected deprecated void skipToNext();
+    method protected deprecated void skipToPrevious();
+    method protected deprecated void startPlayback(int);
+  }
+
+  public static abstract deprecated interface PlaybackControlGlue.InputEventHandler {
+    method public abstract boolean handleInputEvent(android.view.InputEvent);
+  }
+
+  public abstract deprecated class PlaybackControlSupportGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[], int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[], int[]);
+    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+    field public static final int ACTION_REWIND = 32; // 0x20
+    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+  }
+
+  public class PlaybackFragment extends android.app.Fragment {
+    ctor public PlaybackFragment();
+    method public void fadeOut();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBackgroundType();
+    method public boolean isFadingEnabled();
+    method public void notifyPlaybackRowChanged();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBackgroundType(int);
+    method public void setFadingEnabled(boolean);
+    method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
+    method public void setPlaybackRowPresenter(android.support.v17.leanback.widget.PlaybackRowPresenter);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public class PlaybackFragmentGlueHost extends android.support.v17.leanback.media.PlaybackGlueHost {
+    ctor public PlaybackFragmentGlueHost(android.support.v17.leanback.app.PlaybackFragment);
+  }
+
+  public deprecated class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
+    ctor public PlaybackOverlayFragment();
+    method public void fadeOut();
+    method public int getBackgroundType();
+    method public final android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler getEventHandler();
+    method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public final deprecated android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
+    method public boolean isFadingEnabled();
+    method public void setBackgroundType(int);
+    method public final void setEventHandler(android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public final deprecated void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static abstract deprecated interface PlaybackOverlayFragment.InputEventHandler implements android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler {
+  }
+
+  public static class PlaybackOverlayFragment.OnFadeCompleteListener {
+    ctor public PlaybackOverlayFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public deprecated class PlaybackOverlaySupportFragment extends android.support.v17.leanback.app.DetailsSupportFragment {
+    ctor public PlaybackOverlaySupportFragment();
+    method public void fadeOut();
+    method public int getBackgroundType();
+    method public final android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler getEventHandler();
+    method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public final deprecated android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
+    method public boolean isFadingEnabled();
+    method public void setBackgroundType(int);
+    method public final void setEventHandler(android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public final deprecated void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static abstract deprecated interface PlaybackOverlaySupportFragment.InputEventHandler implements android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler {
+  }
+
+  public static class PlaybackOverlaySupportFragment.OnFadeCompleteListener {
+    ctor public PlaybackOverlaySupportFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public class PlaybackSupportFragment extends android.support.v4.app.Fragment {
+    ctor public PlaybackSupportFragment();
+    method public void fadeOut();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBackgroundType();
+    method public boolean isFadingEnabled();
+    method public void notifyPlaybackRowChanged();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBackgroundType(int);
+    method public void setFadingEnabled(boolean);
+    method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
+    method public void setPlaybackRowPresenter(android.support.v17.leanback.widget.PlaybackRowPresenter);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public class PlaybackSupportFragmentGlueHost extends android.support.v17.leanback.media.PlaybackGlueHost {
+    ctor public PlaybackSupportFragmentGlueHost(android.support.v17.leanback.app.PlaybackSupportFragment);
+  }
+
+  public final class ProgressBarManager {
+    ctor public ProgressBarManager();
+    method public void disableProgressBar();
+    method public void enableProgressBar();
+    method public long getInitialDelay();
+    method public void hide();
+    method public void setInitialDelay(long);
+    method public void setProgressBarView(android.view.View);
+    method public void setRootView(android.view.ViewGroup);
+    method public void show();
+  }
+
+  public class RowsFragment extends android.support.v17.leanback.app.BaseRowFragment implements android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapterProvider {
+    ctor public RowsFragment();
+    method public deprecated void enableRowScaling(boolean);
+    method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter getMainFragmentAdapter();
+    method public android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
+    method public boolean isScrolling();
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+  }
+
+  public static class RowsFragment.MainFragmentAdapter extends android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapter {
+    ctor public RowsFragment.MainFragmentAdapter(android.support.v17.leanback.app.RowsFragment);
+  }
+
+  public static class RowsFragment.MainFragmentRowsAdapter extends android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapter {
+    ctor public RowsFragment.MainFragmentRowsAdapter(android.support.v17.leanback.app.RowsFragment);
+  }
+
+  public class RowsSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment implements android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapterProvider {
+    ctor public RowsSupportFragment();
+    method public deprecated void enableRowScaling(boolean);
+    method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
+    method public android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter getMainFragmentAdapter();
+    method public android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+    method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
+    method public boolean isScrolling();
+    method public void setEntranceTransitionState(boolean);
+    method public void setExpand(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setSelectedPosition(int, boolean, android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+  }
+
+  public static class RowsSupportFragment.MainFragmentAdapter extends android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapter {
+    ctor public RowsSupportFragment.MainFragmentAdapter(android.support.v17.leanback.app.RowsSupportFragment);
+  }
+
+  public static class RowsSupportFragment.MainFragmentRowsAdapter extends android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter {
+    ctor public RowsSupportFragment.MainFragmentRowsAdapter(android.support.v17.leanback.app.RowsSupportFragment);
+  }
+
+  public class SearchFragment extends android.app.Fragment {
+    ctor public SearchFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.content.Intent getRecognizerIntent();
+    method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
+    method public java.lang.String getTitle();
+    method public static android.support.v17.leanback.app.SearchFragment newInstance(java.lang.String);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchQuery(java.lang.String, boolean);
+    method public void setSearchQuery(android.content.Intent, boolean);
+    method public void setSearchResultProvider(android.support.v17.leanback.app.SearchFragment.SearchResultProvider);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+  }
+
+  public static abstract interface SearchFragment.SearchResultProvider {
+    method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class SearchSupportFragment extends android.support.v4.app.Fragment {
+    ctor public SearchSupportFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.content.Intent getRecognizerIntent();
+    method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
+    method public java.lang.String getTitle();
+    method public static android.support.v17.leanback.app.SearchSupportFragment newInstance(java.lang.String);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchQuery(java.lang.String, boolean);
+    method public void setSearchQuery(android.content.Intent, boolean);
+    method public void setSearchResultProvider(android.support.v17.leanback.app.SearchSupportFragment.SearchResultProvider);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+  }
+
+  public static abstract interface SearchSupportFragment.SearchResultProvider {
+    method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class VerticalGridFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public VerticalGridFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+  }
+
+  public class VerticalGridSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public VerticalGridSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+  }
+
+  public class VideoFragment extends android.support.v17.leanback.app.PlaybackFragment {
+    ctor public VideoFragment();
+    method public android.view.SurfaceView getSurfaceView();
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+  public class VideoFragmentGlueHost extends android.support.v17.leanback.app.PlaybackFragmentGlueHost implements android.support.v17.leanback.media.SurfaceHolderGlueHost {
+    ctor public VideoFragmentGlueHost(android.support.v17.leanback.app.VideoFragment);
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+  public class VideoSupportFragment extends android.support.v17.leanback.app.PlaybackSupportFragment {
+    ctor public VideoSupportFragment();
+    method public android.view.SurfaceView getSurfaceView();
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+  public class VideoSupportFragmentGlueHost extends android.support.v17.leanback.app.PlaybackSupportFragmentGlueHost implements android.support.v17.leanback.media.SurfaceHolderGlueHost {
+    ctor public VideoSupportFragmentGlueHost(android.support.v17.leanback.app.VideoSupportFragment);
+    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+}
+
+package android.support.v17.leanback.database {
+
+  public abstract class CursorMapper {
+    ctor public CursorMapper();
+    method protected abstract java.lang.Object bind(android.database.Cursor);
+    method protected abstract void bindColumns(android.database.Cursor);
+    method public java.lang.Object convert(android.database.Cursor);
+  }
+
+}
+
+package android.support.v17.leanback.graphics {
+
+  public class BoundsRule {
+    ctor public BoundsRule();
+    ctor public BoundsRule(android.support.v17.leanback.graphics.BoundsRule);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
+    method public void calculateBounds(android.graphics.Rect, android.graphics.Rect);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule bottom;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule left;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule right;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule top;
+  }
+
+  public static final class BoundsRule.ValueRule {
+    method public int getAbsoluteValue();
+    method public float getFraction();
+    method public void setAbsoluteValue(int);
+    method public void setFraction(float);
+  }
+
+  public final class ColorFilterCache {
+    method public static android.support.v17.leanback.graphics.ColorFilterCache getColorFilterCache(int);
+    method public android.graphics.ColorFilter getFilterForLevel(float);
+  }
+
+  public final class ColorFilterDimmer {
+    method public void applyFilterToView(android.view.View);
+    method public static android.support.v17.leanback.graphics.ColorFilterDimmer create(android.support.v17.leanback.graphics.ColorFilterCache, float, float);
+    method public static android.support.v17.leanback.graphics.ColorFilterDimmer createDefault(android.content.Context);
+    method public android.graphics.ColorFilter getColorFilter();
+    method public android.graphics.Paint getPaint();
+    method public void setActiveLevel(float);
+  }
+
+  public final class ColorOverlayDimmer {
+    method public int applyToColor(int);
+    method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createColorOverlayDimmer(int, float, float);
+    method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createDefault(android.content.Context);
+    method public void drawColorOverlay(android.graphics.Canvas, android.view.View, boolean);
+    method public int getAlpha();
+    method public float getAlphaFloat();
+    method public android.graphics.Paint getPaint();
+    method public boolean needsDraw();
+    method public void setActiveLevel(float);
+  }
+
+  public class CompositeDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+    ctor public CompositeDrawable();
+    method public void addChildDrawable(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable getChildAt(int);
+    method public int getChildCount();
+    method public android.graphics.drawable.Drawable getDrawable(int);
+    method public int getOpacity();
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    method public void removeChild(int);
+    method public void removeDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void setAlpha(int);
+    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  }
+
+  public static final class CompositeDrawable.ChildDrawable {
+    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable, android.support.v17.leanback.graphics.CompositeDrawable);
+    method public android.support.v17.leanback.graphics.BoundsRule getBoundsRule();
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public void recomputeBounds();
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> BOTTOM_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> BOTTOM_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> LEFT_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> LEFT_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> RIGHT_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> RIGHT_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> TOP_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> TOP_FRACTION;
+  }
+
+  public class FitWidthBitmapDrawable extends android.graphics.drawable.Drawable {
+    ctor public FitWidthBitmapDrawable();
+    method public void draw(android.graphics.Canvas);
+    method public android.graphics.Bitmap getBitmap();
+    method public int getOpacity();
+    method public android.graphics.Rect getSource();
+    method public int getVerticalOffset();
+    method public void setAlpha(int);
+    method public void setBitmap(android.graphics.Bitmap);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setSource(android.graphics.Rect);
+    method public void setVerticalOffset(int);
+    field public static final android.util.Property<android.support.v17.leanback.graphics.FitWidthBitmapDrawable, java.lang.Integer> PROPERTY_VERTICAL_OFFSET;
+  }
+
+}
+
+package android.support.v17.leanback.media {
+
+  public abstract class MediaControllerGlue extends android.support.v17.leanback.media.PlaybackControlGlue {
+    ctor public MediaControllerGlue(android.content.Context, int[], int[]);
+    method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
+    method public void detach();
+    method public int getCurrentPosition();
+    method public int getCurrentSpeedId();
+    method public android.graphics.drawable.Drawable getMediaArt();
+    method public final android.support.v4.media.session.MediaControllerCompat getMediaController();
+    method public int getMediaDuration();
+    method public java.lang.CharSequence getMediaSubtitle();
+    method public java.lang.CharSequence getMediaTitle();
+    method public long getSupportedActions();
+    method public boolean hasValidMedia();
+    method public boolean isMediaPlaying();
+  }
+
+  public abstract class PlaybackControlGlue extends android.support.v17.leanback.media.PlaybackGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+    ctor public PlaybackControlGlue(android.content.Context, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
+    method public void enableProgressUpdating(boolean);
+    method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter getControlsRowPresenter();
+    method public abstract int getCurrentPosition();
+    method public abstract int getCurrentSpeedId();
+    method public int[] getFastForwardSpeeds();
+    method public abstract android.graphics.drawable.Drawable getMediaArt();
+    method public abstract int getMediaDuration();
+    method public abstract java.lang.CharSequence getMediaSubtitle();
+    method public abstract java.lang.CharSequence getMediaTitle();
+    method public int[] getRewindSpeeds();
+    method public abstract long getSupportedActions();
+    method public int getUpdatePeriod();
+    method public abstract boolean hasValidMedia();
+    method public boolean isFadingEnabled();
+    method public abstract boolean isMediaPlaying();
+    method public void onActionClicked(android.support.v17.leanback.widget.Action);
+    method protected void onCreateControlsRowAndPresenter();
+    method protected void onCreatePrimaryActions(android.support.v17.leanback.widget.SparseArrayObjectAdapter);
+    method protected void onCreateSecondaryActions(android.support.v17.leanback.widget.ArrayObjectAdapter);
+    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+    method protected void onMetadataChanged();
+    method protected void onStateChanged();
+    method public void play(int);
+    method public final void play();
+    method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method public void setControlsRowPresenter(android.support.v17.leanback.widget.PlaybackControlsRowPresenter);
+    method public void setFadingEnabled(boolean);
+    method public void updateProgress();
+    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+    field public static final int ACTION_REWIND = 32; // 0x20
+    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+  }
+
+  public abstract class PlaybackGlue {
+    ctor public PlaybackGlue(android.content.Context);
+    method public android.content.Context getContext();
+    method public android.support.v17.leanback.media.PlaybackGlueHost getHost();
+    method public boolean isReadyForPlayback();
+    method public void next();
+    method protected void onAttachedToHost(android.support.v17.leanback.media.PlaybackGlueHost);
+    method protected void onDetachedFromHost();
+    method protected void onHostPause();
+    method protected void onHostResume();
+    method protected void onHostStart();
+    method protected void onHostStop();
+    method public void pause();
+    method public void play();
+    method public void previous();
+    method public final void setHost(android.support.v17.leanback.media.PlaybackGlueHost);
+    method public void setPlayerCallback(android.support.v17.leanback.media.PlaybackGlue.PlayerCallback);
+  }
+
+  public static abstract class PlaybackGlue.PlayerCallback {
+    ctor public PlaybackGlue.PlayerCallback();
+    method public abstract void onReadyForPlayback();
+  }
+
+  public abstract class PlaybackGlueHost {
+    ctor public PlaybackGlueHost();
+    method public void fadeOut();
+    method public void notifyPlaybackRowChanged();
+    method public void setFadingEnabled(boolean);
+    method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
+    method public void setPlaybackRowPresenter(android.support.v17.leanback.widget.PlaybackRowPresenter);
+  }
+
+  public static abstract class PlaybackGlueHost.HostCallback {
+    ctor public PlaybackGlueHost.HostCallback();
+    method public void onHostDestroy();
+    method public void onHostPause();
+    method public void onHostResume();
+    method public void onHostStart();
+    method public void onHostStop();
+  }
+
+  public abstract interface SurfaceHolderGlueHost {
+    method public abstract void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
+  }
+
+}
+
+package android.support.v17.leanback.system {
+
+  public class Settings {
+    method public boolean getBoolean(java.lang.String);
+    method public static android.support.v17.leanback.system.Settings getInstance(android.content.Context);
+    method public void setBoolean(java.lang.String, boolean);
+    field public static final java.lang.String PREFER_STATIC_SHADOWS = "PREFER_STATIC_SHADOWS";
+  }
+
+}
+
+package android.support.v17.leanback.widget {
+
+  public abstract class AbstractDetailsDescriptionPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public AbstractDetailsDescriptionPresenter();
+    method protected abstract void onBindDescription(android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, java.lang.Object);
+    method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+  }
+
+  public static class AbstractDetailsDescriptionPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getBody();
+    method public android.widget.TextView getSubtitle();
+    method public android.widget.TextView getTitle();
+  }
+
+  public abstract class AbstractMediaItemPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public AbstractMediaItemPresenter();
+    ctor public AbstractMediaItemPresenter(int);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.Presenter getActionPresenter();
+    method protected int getMediaPlayState(java.lang.Object);
+    method public int getThemeId();
+    method public boolean hasMediaRowSeparator();
+    method protected abstract void onBindMediaDetails(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder, java.lang.Object);
+    method public void onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method protected void onBindRowActions(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method protected void onUnbindMediaDetails(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method public void onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
+    method public void setActionPresenter(android.support.v17.leanback.widget.Presenter);
+    method public void setBackgroundColor(int);
+    method public void setHasMediaRowSeparator(boolean);
+    method public void setThemeId(int);
+    field public static final int PLAY_STATE_INITIAL = 0; // 0x0
+    field public static final int PLAY_STATE_PAUSED = 1; // 0x1
+    field public static final int PLAY_STATE_PLAYING = 2; // 0x2
+  }
+
+  public static class AbstractMediaItemPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public AbstractMediaItemPresenter.ViewHolder(android.view.View);
+    method public android.view.ViewGroup getMediaItemActionsContainer();
+    method public android.view.View getMediaItemDetailsView();
+    method public android.widget.TextView getMediaItemDurationView();
+    method public android.widget.TextView getMediaItemNameView();
+    method public android.widget.TextView getMediaItemNumberView();
+    method public android.widget.ViewFlipper getMediaItemNumberViewFlipper();
+    method public android.view.View getMediaItemPausedView();
+    method public android.view.View getMediaItemPlayingView();
+    method public android.support.v17.leanback.widget.MultiActionsProvider.MultiAction[] getMediaItemRowActions();
+    method public android.view.View getMediaItemRowSeparator();
+    method public android.view.View getSelectorView();
+    method public void notifyActionChanged(android.support.v17.leanback.widget.MultiActionsProvider.MultiAction);
+    method public void notifyDetailsChanged();
+    method public void notifyPlayStateChanged();
+    method public void onBindRowActions();
+    method public void setSelectedMediaItemNumberView(int);
+  }
+
+  public abstract class AbstractMediaListHeaderPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public AbstractMediaListHeaderPresenter(android.content.Context, int);
+    ctor public AbstractMediaListHeaderPresenter();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected abstract void onBindMediaListHeaderViewHolder(android.support.v17.leanback.widget.AbstractMediaListHeaderPresenter.ViewHolder, java.lang.Object);
+    method public void setBackgroundColor(int);
+  }
+
+  public static class AbstractMediaListHeaderPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public AbstractMediaListHeaderPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getHeaderView();
+  }
+
+  public class Action {
+    ctor public Action(long);
+    ctor public Action(long, java.lang.CharSequence);
+    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence);
+    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence, android.graphics.drawable.Drawable);
+    method public final void addKeyCode(int);
+    method public final android.graphics.drawable.Drawable getIcon();
+    method public final long getId();
+    method public final java.lang.CharSequence getLabel1();
+    method public final java.lang.CharSequence getLabel2();
+    method public final void removeKeyCode(int);
+    method public final boolean respondsToKeyCode(int);
+    method public final void setIcon(android.graphics.drawable.Drawable);
+    method public final void setId(long);
+    method public final void setLabel1(java.lang.CharSequence);
+    method public final void setLabel2(java.lang.CharSequence);
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+  }
+
+  public class ArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public ArrayObjectAdapter();
+    method public void add(java.lang.Object);
+    method public void add(int, java.lang.Object);
+    method public void addAll(int, java.util.Collection);
+    method public void clear();
+    method public java.lang.Object get(int);
+    method public int indexOf(java.lang.Object);
+    method public void notifyArrayItemRangeChanged(int, int);
+    method public boolean remove(java.lang.Object);
+    method public int removeItems(int, int);
+    method public void replace(int, java.lang.Object);
+    method public int size();
+    method public <E> java.util.List<E> unmodifiableList();
+  }
+
+  public class BaseCardView extends android.widget.FrameLayout {
+    ctor public BaseCardView(android.content.Context);
+    ctor public BaseCardView(android.content.Context, android.util.AttributeSet);
+    ctor public BaseCardView(android.content.Context, android.util.AttributeSet, int);
+    method public int getCardType();
+    method public deprecated int getExtraVisibility();
+    method public int getInfoVisibility();
+    method public boolean isSelectedAnimationDelayed();
+    method public void setCardType(int);
+    method public deprecated void setExtraVisibility(int);
+    method public void setInfoVisibility(int);
+    method public void setSelectedAnimationDelayed(boolean);
+    field public static final int CARD_REGION_VISIBLE_ACTIVATED = 1; // 0x1
+    field public static final int CARD_REGION_VISIBLE_ALWAYS = 0; // 0x0
+    field public static final int CARD_REGION_VISIBLE_SELECTED = 2; // 0x2
+    field public static final int CARD_TYPE_INFO_OVER = 1; // 0x1
+    field public static final int CARD_TYPE_INFO_UNDER = 2; // 0x2
+    field public static final int CARD_TYPE_INFO_UNDER_WITH_EXTRA = 3; // 0x3
+    field public static final int CARD_TYPE_MAIN_ONLY = 0; // 0x0
+  }
+
+  public static class BaseCardView.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public BaseCardView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public BaseCardView.LayoutParams(int, int);
+    ctor public BaseCardView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public BaseCardView.LayoutParams(android.support.v17.leanback.widget.BaseCardView.LayoutParams);
+    field public static final int VIEW_TYPE_EXTRA = 2; // 0x2
+    field public static final int VIEW_TYPE_INFO = 1; // 0x1
+    field public static final int VIEW_TYPE_MAIN = 0; // 0x0
+    field public int viewType;
+  }
+
+  public abstract interface BaseOnItemViewClickedListener<T> {
+    method public abstract void onItemClicked(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, T);
+  }
+
+  public abstract interface BaseOnItemViewSelectedListener<T> {
+    method public abstract void onItemSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, T);
+  }
+
+  public class BrowseFrameLayout extends android.widget.FrameLayout {
+    ctor public BrowseFrameLayout(android.content.Context);
+    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener getOnChildFocusListener();
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+    method public void setOnChildFocusListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener);
+    method public void setOnDispatchKeyListener(android.view.View.OnKeyListener);
+    method public void setOnFocusSearchListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener);
+  }
+
+  public static abstract interface BrowseFrameLayout.OnChildFocusListener {
+    method public abstract void onRequestChildFocus(android.view.View, android.view.View);
+    method public abstract boolean onRequestFocusInDescendants(int, android.graphics.Rect);
+  }
+
+  public static abstract interface BrowseFrameLayout.OnFocusSearchListener {
+    method public abstract android.view.View onFocusSearch(android.view.View, int);
+  }
+
+  public final class ClassPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public ClassPresenterSelector();
+    method public android.support.v17.leanback.widget.ClassPresenterSelector addClassPresenter(java.lang.Class<?>, android.support.v17.leanback.widget.Presenter);
+    method public android.support.v17.leanback.widget.ClassPresenterSelector addClassPresenterSelector(java.lang.Class<?>, android.support.v17.leanback.widget.PresenterSelector);
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+  }
+
+  public class ControlButtonPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public ControlButtonPresenterSelector();
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter getPrimaryPresenter();
+    method public android.support.v17.leanback.widget.Presenter getSecondaryPresenter();
+  }
+
+  public class CursorObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public CursorObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public CursorObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public CursorObjectAdapter();
+    method public void changeCursor(android.database.Cursor);
+    method public void close();
+    method public java.lang.Object get(int);
+    method public final android.database.Cursor getCursor();
+    method public final android.support.v17.leanback.database.CursorMapper getMapper();
+    method protected final void invalidateCache(int);
+    method protected final void invalidateCache(int, int);
+    method public boolean isClosed();
+    method protected void onCursorChanged();
+    method protected void onMapperChanged();
+    method public final void setMapper(android.support.v17.leanback.database.CursorMapper);
+    method public int size();
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+  }
+
+  public class DetailsOverviewLogoPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public DetailsOverviewLogoPresenter();
+    method public boolean isBoundToImage(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.view.View onCreateView(android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setContext(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+  }
+
+  public static class DetailsOverviewLogoPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
+    method public android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter getParentPresenter();
+    method public android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder getParentViewHolder();
+    method public boolean isSizeFromDrawableIntrinsic();
+    method public void setSizeFromDrawableIntrinsic(boolean);
+    field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter mParentPresenter;
+    field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder mParentViewHolder;
+  }
+
+  public class DetailsOverviewRow extends android.support.v17.leanback.widget.Row {
+    ctor public DetailsOverviewRow(java.lang.Object);
+    method public final deprecated void addAction(android.support.v17.leanback.widget.Action);
+    method public final deprecated void addAction(int, android.support.v17.leanback.widget.Action);
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+    method public final deprecated java.util.List<android.support.v17.leanback.widget.Action> getActions();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getActionsAdapter();
+    method public final android.graphics.drawable.Drawable getImageDrawable();
+    method public final java.lang.Object getItem();
+    method public boolean isImageScaleUpAllowed();
+    method public final deprecated boolean removeAction(android.support.v17.leanback.widget.Action);
+    method public final void setActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+    method public final void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setImageScaleUpAllowed(boolean);
+    method public final void setItem(java.lang.Object);
+  }
+
+  public static class DetailsOverviewRow.Listener {
+    ctor public DetailsOverviewRow.Listener();
+    method public void onActionsAdapterChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onImageDrawableChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onItemChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+  }
+
+  public deprecated class DetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public DetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public int getBackgroundColor();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public boolean isStyleLarge();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public void setBackgroundColor(int);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+    method public void setStyleLarge(boolean);
+  }
+
+  public final class DetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public DetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter);
+    field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDetailsDescriptionViewHolder;
+  }
+
+  public class DetailsParallax extends android.support.v17.leanback.widget.RecyclerViewParallax {
+    ctor public DetailsParallax();
+    method public android.support.v17.leanback.widget.Parallax.IntProperty getOverviewRowBottom();
+    method public android.support.v17.leanback.widget.Parallax.IntProperty getOverviewRowTop();
+  }
+
+  public class DividerPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public DividerPresenter();
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+  }
+
+  public class DividerRow extends android.support.v17.leanback.widget.Row {
+    ctor public DividerRow();
+    method public final boolean isRenderedAsRowView();
+  }
+
+  public abstract interface FacetProvider {
+    method public abstract java.lang.Object getFacet(java.lang.Class<?>);
+  }
+
+  public abstract interface FacetProviderAdapter {
+    method public abstract android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+  }
+
+  public abstract interface FocusHighlight {
+    field public static final int ZOOM_FACTOR_LARGE = 3; // 0x3
+    field public static final int ZOOM_FACTOR_MEDIUM = 2; // 0x2
+    field public static final int ZOOM_FACTOR_NONE = 0; // 0x0
+    field public static final int ZOOM_FACTOR_SMALL = 1; // 0x1
+    field public static final int ZOOM_FACTOR_XSMALL = 4; // 0x4
+  }
+
+  public class FocusHighlightHelper {
+    ctor public FocusHighlightHelper();
+    method public static void setupBrowseItemFocusHighlight(android.support.v17.leanback.widget.ItemBridgeAdapter, int, boolean);
+    method public static void setupHeaderItemFocusHighlight(android.support.v17.leanback.widget.VerticalGridView);
+    method public static void setupHeaderItemFocusHighlight(android.support.v17.leanback.widget.VerticalGridView, boolean);
+  }
+
+  public abstract interface FragmentAnimationProvider {
+    method public abstract void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public abstract void onImeDisappearing(java.util.List<android.animation.Animator>);
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+    ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public final int getActionsBackgroundColor();
+    method public final int getAlignmentMode();
+    method public final int getBackgroundColor();
+    method public final int getInitialState();
+    method protected int getLayoutResourceId();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public final boolean isParticipatingEntranceTransition();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public final void notifyOnBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+    method protected void onLayoutLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+    method protected void onLayoutOverviewFrame(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+    method protected void onStateChanged(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+    method public final void setActionsBackgroundColor(int);
+    method public final void setAlignmentMode(int);
+    method public final void setBackgroundColor(int);
+    method public final void setInitialState(int);
+    method public final void setListener(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public final void setParticipatingEntranceTransition(boolean);
+    method public final void setState(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+    field public static final int ALIGN_MODE_MIDDLE = 1; // 0x1
+    field public static final int ALIGN_MODE_START = 0; // 0x0
+    field public static final int STATE_FULL = 1; // 0x1
+    field public static final int STATE_HALF = 0; // 0x0
+    field public static final int STATE_SMALL = 2; // 0x2
+    field protected int mInitialState;
+  }
+
+  public static abstract class FullWidthDetailsOverviewRowPresenter.Listener {
+    ctor public FullWidthDetailsOverviewRowPresenter.Listener();
+    method public void onBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+    method protected android.support.v17.leanback.widget.DetailsOverviewRow.Listener createRowListener();
+    method public final android.view.ViewGroup getActionsRow();
+    method public final android.view.ViewGroup getDetailsDescriptionFrame();
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder getDetailsDescriptionViewHolder();
+    method public final android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder getLogoViewHolder();
+    method public final android.view.ViewGroup getOverviewView();
+    method public final int getState();
+    field protected final android.support.v17.leanback.widget.DetailsOverviewRow.Listener mRowListener;
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener extends android.support.v17.leanback.widget.DetailsOverviewRow.Listener {
+    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener();
+  }
+
+  public class FullWidthDetailsOverviewSharedElementHelper extends android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener {
+    ctor public FullWidthDetailsOverviewSharedElementHelper();
+    method public boolean getAutoStartSharedElementTransition();
+    method public void setAutoStartSharedElementTransition(boolean);
+    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+    method public void startPostponedEnterTransition();
+  }
+
+  public class GuidanceStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+    ctor public GuidanceStylist();
+    method public android.widget.TextView getBreadcrumbView();
+    method public android.widget.TextView getDescriptionView();
+    method public android.widget.ImageView getIconView();
+    method public android.widget.TextView getTitleView();
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.support.v17.leanback.widget.GuidanceStylist.Guidance);
+    method public void onDestroyView();
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+    method public int onProvideLayoutId();
+  }
+
+  public static class GuidanceStylist.Guidance {
+    ctor public GuidanceStylist.Guidance(java.lang.String, java.lang.String, java.lang.String, android.graphics.drawable.Drawable);
+    method public java.lang.String getBreadcrumb();
+    method public java.lang.String getDescription();
+    method public android.graphics.drawable.Drawable getIconDrawable();
+    method public java.lang.String getTitle();
+  }
+
+  public class GuidedAction extends android.support.v17.leanback.widget.Action {
+    ctor protected GuidedAction();
+    method public int getCheckSetId();
+    method public java.lang.CharSequence getDescription();
+    method public int getDescriptionEditInputType();
+    method public int getDescriptionInputType();
+    method public java.lang.CharSequence getEditDescription();
+    method public int getEditInputType();
+    method public java.lang.CharSequence getEditTitle();
+    method public int getInputType();
+    method public android.content.Intent getIntent();
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getSubActions();
+    method public java.lang.CharSequence getTitle();
+    method public boolean hasEditableActivatorView();
+    method public boolean hasMultilineDescription();
+    method public boolean hasNext();
+    method public boolean hasSubActions();
+    method public boolean hasTextEditable();
+    method public boolean infoOnly();
+    method public final boolean isAutoSaveRestoreEnabled();
+    method public boolean isChecked();
+    method public boolean isDescriptionEditable();
+    method public boolean isEditTitleUsed();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public void onRestoreInstanceState(android.os.Bundle, java.lang.String);
+    method public void onSaveInstanceState(android.os.Bundle, java.lang.String);
+    method public void setChecked(boolean);
+    method public void setDescription(java.lang.CharSequence);
+    method public void setEditDescription(java.lang.CharSequence);
+    method public void setEditTitle(java.lang.CharSequence);
+    method public void setEnabled(boolean);
+    method public void setFocusable(boolean);
+    method public void setIntent(android.content.Intent);
+    method public void setSubActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setTitle(java.lang.CharSequence);
+    field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
+    field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
+    field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
+    field public static final long ACTION_ID_FINISH = -6L; // 0xfffffffffffffffaL
+    field public static final long ACTION_ID_NEXT = -2L; // 0xfffffffffffffffeL
+    field public static final long ACTION_ID_NO = -9L; // 0xfffffffffffffff7L
+    field public static final long ACTION_ID_OK = -4L; // 0xfffffffffffffffcL
+    field public static final long ACTION_ID_YES = -8L; // 0xfffffffffffffff8L
+    field public static final int CHECKBOX_CHECK_SET_ID = -1; // 0xffffffff
+    field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
+    field public static final int NO_CHECK_SET = 0; // 0x0
+  }
+
+  public static class GuidedAction.Builder extends android.support.v17.leanback.widget.GuidedAction.BuilderBase {
+    ctor public deprecated GuidedAction.Builder();
+    ctor public GuidedAction.Builder(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction build();
+  }
+
+  public static abstract class GuidedAction.BuilderBase<B extends android.support.v17.leanback.widget.GuidedAction.BuilderBase> {
+    ctor public GuidedAction.BuilderBase(android.content.Context);
+    method protected final void applyValues(android.support.v17.leanback.widget.GuidedAction);
+    method public B autoSaveRestoreEnabled(boolean);
+    method public B checkSetId(int);
+    method public B checked(boolean);
+    method public B clickAction(long);
+    method public B description(java.lang.CharSequence);
+    method public B description(int);
+    method public B descriptionEditInputType(int);
+    method public B descriptionEditable(boolean);
+    method public B descriptionInputType(int);
+    method public B editDescription(java.lang.CharSequence);
+    method public B editDescription(int);
+    method public B editInputType(int);
+    method public B editTitle(java.lang.CharSequence);
+    method public B editTitle(int);
+    method public B editable(boolean);
+    method public B enabled(boolean);
+    method public B focusable(boolean);
+    method public android.content.Context getContext();
+    method public B hasEditableActivatorView(boolean);
+    method public B hasNext(boolean);
+    method public B icon(android.graphics.drawable.Drawable);
+    method public B icon(int);
+    method public deprecated B iconResourceId(int, android.content.Context);
+    method public B id(long);
+    method public B infoOnly(boolean);
+    method public B inputType(int);
+    method public B intent(android.content.Intent);
+    method public B multilineDescription(boolean);
+    method public B subActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public B title(java.lang.CharSequence);
+    method public B title(int);
+  }
+
+  public class GuidedActionEditText extends android.widget.EditText implements android.support.v17.leanback.widget.ImeKeyMonitor {
+    ctor public GuidedActionEditText(android.content.Context);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet, int);
+    method public void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+  }
+
+  public class GuidedActionsStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+    ctor public GuidedActionsStylist();
+    method public void collapseAction(boolean);
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public android.support.v17.leanback.widget.VerticalGridView getActionsGridView();
+    method public android.support.v17.leanback.widget.GuidedAction getExpandedAction();
+    method public int getItemViewType(android.support.v17.leanback.widget.GuidedAction);
+    method public android.support.v17.leanback.widget.VerticalGridView getSubActionsGridView();
+    method public final boolean isBackKeyToCollapseActivatorView();
+    method public final boolean isBackKeyToCollapseSubActions();
+    method public boolean isButtonActions();
+    method public boolean isExpandTransitionSupported();
+    method public boolean isExpanded();
+    method public boolean isInExpandTransition();
+    method public boolean isSubActionsExpanded();
+    method public void onAnimateItemChecked(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemFocused(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemPressed(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemPressedCancelled(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public void onBindActivatorView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onBindCheckMarkView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onBindChevronView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDestroyView();
+    method protected deprecated void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method protected void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean, boolean);
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+    method public int onProvideItemLayoutId();
+    method public int onProvideItemLayoutId(int);
+    method public int onProvideLayoutId();
+    method public boolean onUpdateActivatorView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onUpdateExpandedViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public void setAsButtonActions();
+    method public final void setBackKeyToCollapseActivatorView(boolean);
+    method public final void setBackKeyToCollapseSubActions(boolean);
+    method public deprecated void setEditingMode(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public deprecated void setExpandedViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method protected void setupImeOptions(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public deprecated void startExpandedTransition(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    field public static final int VIEW_TYPE_DATE_PICKER = 1; // 0x1
+    field public static final int VIEW_TYPE_DEFAULT = 0; // 0x0
+  }
+
+  public static class GuidedActionsStylist.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public GuidedActionsStylist.ViewHolder(android.view.View);
+    ctor public GuidedActionsStylist.ViewHolder(android.view.View, boolean);
+    method public android.support.v17.leanback.widget.GuidedAction getAction();
+    method public android.widget.ImageView getCheckmarkView();
+    method public android.widget.ImageView getChevronView();
+    method public android.view.View getContentView();
+    method public android.widget.TextView getDescriptionView();
+    method public android.widget.EditText getEditableDescriptionView();
+    method public android.widget.EditText getEditableTitleView();
+    method public android.view.View getEditingView();
+    method public java.lang.Object getFacet(java.lang.Class<?>);
+    method public android.widget.ImageView getIconView();
+    method public android.widget.TextView getTitleView();
+    method public boolean isInEditing();
+    method public boolean isInEditingActivatorView();
+    method public boolean isInEditingDescription();
+    method public boolean isInEditingText();
+    method public boolean isInEditingTitle();
+    method public boolean isSubAction();
+  }
+
+  public class GuidedDatePickerAction extends android.support.v17.leanback.widget.GuidedAction {
+    ctor public GuidedDatePickerAction();
+    method public long getDate();
+    method public java.lang.String getDatePickerFormat();
+    method public long getMaxDate();
+    method public long getMinDate();
+    method public void setDate(long);
+  }
+
+  public static final class GuidedDatePickerAction.Builder extends android.support.v17.leanback.widget.GuidedDatePickerAction.BuilderBase {
+    ctor public GuidedDatePickerAction.Builder(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedDatePickerAction build();
+  }
+
+  public static abstract class GuidedDatePickerAction.BuilderBase<B extends android.support.v17.leanback.widget.GuidedDatePickerAction.BuilderBase> extends android.support.v17.leanback.widget.GuidedAction.BuilderBase {
+    ctor public GuidedDatePickerAction.BuilderBase(android.content.Context);
+    method protected final void applyDatePickerValues(android.support.v17.leanback.widget.GuidedDatePickerAction);
+    method public B date(long);
+    method public B datePickerFormat(java.lang.String);
+    method public B maxDate(long);
+    method public B minDate(long);
+  }
+
+  public class HeaderItem {
+    ctor public HeaderItem(long, java.lang.String);
+    ctor public HeaderItem(java.lang.String);
+    method public java.lang.CharSequence getContentDescription();
+    method public java.lang.CharSequence getDescription();
+    method public final long getId();
+    method public final java.lang.String getName();
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setDescription(java.lang.CharSequence);
+  }
+
+  public class HorizontalGridView extends android.support.v7.widget.RecyclerView {
+    ctor public HorizontalGridView(android.content.Context);
+    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet);
+    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet, int);
+    method public final boolean getFadingLeftEdge();
+    method public final int getFadingLeftEdgeLength();
+    method public final int getFadingLeftEdgeOffset();
+    method public final boolean getFadingRightEdge();
+    method public final int getFadingRightEdgeLength();
+    method public final int getFadingRightEdgeOffset();
+    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+    method public final void setFadingLeftEdge(boolean);
+    method public final void setFadingLeftEdgeLength(int);
+    method public final void setFadingLeftEdgeOffset(int);
+    method public final void setFadingRightEdge(boolean);
+    method public final void setFadingRightEdgeLength(int);
+    method public final void setFadingRightEdgeOffset(int);
+    method public void setNumRows(int);
+    method public void setRowHeight(int);
+  }
+
+  public final class HorizontalHoverCardSwitcher extends android.support.v17.leanback.widget.PresenterSwitcher {
+    ctor public HorizontalHoverCardSwitcher();
+    method protected void insertView(android.view.View);
+    method public void select(android.support.v17.leanback.widget.HorizontalGridView, android.view.View, java.lang.Object);
+  }
+
+  public class ImageCardView extends android.support.v17.leanback.widget.BaseCardView {
+    ctor public deprecated ImageCardView(android.content.Context, int);
+    ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
+    ctor public ImageCardView(android.content.Context);
+    ctor public ImageCardView(android.content.Context, android.util.AttributeSet);
+    method public android.graphics.drawable.Drawable getBadgeImage();
+    method public java.lang.CharSequence getContentText();
+    method public android.graphics.drawable.Drawable getInfoAreaBackground();
+    method public android.graphics.drawable.Drawable getMainImage();
+    method public final android.widget.ImageView getMainImageView();
+    method public java.lang.CharSequence getTitleText();
+    method public void setBadgeImage(android.graphics.drawable.Drawable);
+    method public void setContentText(java.lang.CharSequence);
+    method public void setInfoAreaBackground(android.graphics.drawable.Drawable);
+    method public void setInfoAreaBackgroundColor(int);
+    method public void setMainImage(android.graphics.drawable.Drawable);
+    method public void setMainImage(android.graphics.drawable.Drawable, boolean);
+    method public void setMainImageAdjustViewBounds(boolean);
+    method public void setMainImageDimensions(int, int);
+    method public void setMainImageScaleType(android.widget.ImageView.ScaleType);
+    method public void setTitleText(java.lang.CharSequence);
+    field public static final int CARD_TYPE_FLAG_CONTENT = 2; // 0x2
+    field public static final int CARD_TYPE_FLAG_ICON_LEFT = 8; // 0x8
+    field public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4; // 0x4
+    field public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0; // 0x0
+    field public static final int CARD_TYPE_FLAG_TITLE = 1; // 0x1
+  }
+
+  public abstract interface ImeKeyMonitor {
+    method public abstract void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+  }
+
+  public static abstract interface ImeKeyMonitor.ImeKeyListener {
+    method public abstract boolean onKeyPreIme(android.widget.EditText, int, android.view.KeyEvent);
+  }
+
+  public final class ItemAlignmentFacet {
+    ctor public ItemAlignmentFacet();
+    method public android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[] getAlignmentDefs();
+    method public boolean isMultiAlignment();
+    method public void setAlignmentDefs(android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[]);
+    field public static final float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1.0f;
+  }
+
+  public static class ItemAlignmentFacet.ItemAlignmentDef {
+    ctor public ItemAlignmentFacet.ItemAlignmentDef();
+    method public final int getItemAlignmentFocusViewId();
+    method public final int getItemAlignmentOffset();
+    method public final float getItemAlignmentOffsetPercent();
+    method public final int getItemAlignmentViewId();
+    method public boolean isAlignedToTextViewBaseLine();
+    method public final boolean isItemAlignmentOffsetWithPadding();
+    method public final void setAlignedToTextViewBaseline(boolean);
+    method public final void setItemAlignmentFocusViewId(int);
+    method public final void setItemAlignmentOffset(int);
+    method public final void setItemAlignmentOffsetPercent(float);
+    method public final void setItemAlignmentOffsetWithPadding(boolean);
+    method public final void setItemAlignmentViewId(int);
+  }
+
+  public class ItemBridgeAdapter extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.leanback.widget.FacetProviderAdapter {
+    ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter, android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ItemBridgeAdapter();
+    method public void clear();
+    method public android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+    method public int getItemCount();
+    method public java.util.ArrayList<android.support.v17.leanback.widget.Presenter> getPresenterMapper();
+    method public android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper getWrapper();
+    method protected void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+    method protected void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method protected void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final void onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    method protected void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final android.support.v7.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method protected void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method protected void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final void onViewAttachedToWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void onViewDetachedFromWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setAdapterListener(android.support.v17.leanback.widget.ItemBridgeAdapter.AdapterListener);
+    method public void setPresenter(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setPresenterMapper(java.util.ArrayList<android.support.v17.leanback.widget.Presenter>);
+    method public void setWrapper(android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper);
+  }
+
+  public static class ItemBridgeAdapter.AdapterListener {
+    ctor public ItemBridgeAdapter.AdapterListener();
+    method public void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+    method public void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+  }
+
+  public class ItemBridgeAdapter.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    method public final java.lang.Object getExtraObject();
+    method public java.lang.Object getFacet(java.lang.Class<?>);
+    method public final java.lang.Object getItem();
+    method public final android.support.v17.leanback.widget.Presenter getPresenter();
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder getViewHolder();
+    method public void setExtraObject(java.lang.Object);
+  }
+
+  public static abstract class ItemBridgeAdapter.Wrapper {
+    ctor public ItemBridgeAdapter.Wrapper();
+    method public abstract android.view.View createWrapper(android.view.View);
+    method public abstract void wrap(android.view.View, android.view.View);
+  }
+
+  public class ItemBridgeAdapterShadowOverlayWrapper extends android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper {
+    ctor public ItemBridgeAdapterShadowOverlayWrapper(android.support.v17.leanback.widget.ShadowOverlayHelper);
+    method public android.view.View createWrapper(android.view.View);
+    method public void wrap(android.view.View, android.view.View);
+  }
+
+  public class ListRow extends android.support.v17.leanback.widget.Row {
+    ctor public ListRow(android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ListRow(long, android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ListRow(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public java.lang.CharSequence getContentDescription();
+    method public void setContentDescription(java.lang.CharSequence);
+  }
+
+  public final class ListRowHoverCardView extends android.widget.LinearLayout {
+    ctor public ListRowHoverCardView(android.content.Context);
+    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet);
+    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet, int);
+    method public final java.lang.CharSequence getDescription();
+    method public final java.lang.CharSequence getTitle();
+    method public final void setDescription(java.lang.CharSequence);
+    method public final void setTitle(java.lang.CharSequence);
+  }
+
+  public class ListRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public ListRowPresenter();
+    ctor public ListRowPresenter(int);
+    ctor public ListRowPresenter(int, boolean);
+    method public final boolean areChildRoundedCornersEnabled();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+    method public final void enableChildRoundedCorners(boolean);
+    method public int getExpandedRowHeight();
+    method public final int getFocusZoomFactor();
+    method public final android.support.v17.leanback.widget.PresenterSelector getHoverCardPresenterSelector();
+    method public int getRecycledPoolSize(android.support.v17.leanback.widget.Presenter);
+    method public int getRowHeight();
+    method public final boolean getShadowEnabled();
+    method public final deprecated int getZoomFactor();
+    method public final boolean isFocusDimmerUsed();
+    method public final boolean isKeepChildForeground();
+    method public boolean isUsingDefaultListSelectEffect();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public boolean isUsingDefaultShadow();
+    method public boolean isUsingZOrder(android.content.Context);
+    method public void setExpandedRowHeight(int);
+    method public final void setHoverCardPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public final void setKeepChildForeground(boolean);
+    method public void setNumRows(int);
+    method public void setRecycledPoolSize(android.support.v17.leanback.widget.Presenter, int);
+    method public void setRowHeight(int);
+    method public final void setShadowEnabled(boolean);
+  }
+
+  public static class ListRowPresenter.SelectItemViewHolderTask extends android.support.v17.leanback.widget.Presenter.ViewHolderTask {
+    ctor public ListRowPresenter.SelectItemViewHolderTask(int);
+    method public int getItemPosition();
+    method public android.support.v17.leanback.widget.Presenter.ViewHolderTask getItemTask();
+    method public boolean isSmoothScroll();
+    method public void setItemPosition(int);
+    method public void setItemTask(android.support.v17.leanback.widget.Presenter.ViewHolderTask);
+    method public void setSmoothScroll(boolean);
+  }
+
+  public static class ListRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public ListRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.HorizontalGridView, android.support.v17.leanback.widget.ListRowPresenter);
+    method public final android.support.v17.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
+    method public final android.support.v17.leanback.widget.HorizontalGridView getGridView();
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder getItemViewHolder(int);
+    method public final android.support.v17.leanback.widget.ListRowPresenter getListRowPresenter();
+    method public int getSelectedPosition();
+  }
+
+  public final class ListRowView extends android.widget.LinearLayout {
+    ctor public ListRowView(android.content.Context);
+    ctor public ListRowView(android.content.Context, android.util.AttributeSet);
+    ctor public ListRowView(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v17.leanback.widget.HorizontalGridView getGridView();
+  }
+
+  public abstract interface MultiActionsProvider {
+    method public abstract android.support.v17.leanback.widget.MultiActionsProvider.MultiAction[] getActions();
+  }
+
+  public static class MultiActionsProvider.MultiAction {
+    ctor public MultiActionsProvider.MultiAction(long);
+    method public android.graphics.drawable.Drawable getCurrentDrawable();
+    method public android.graphics.drawable.Drawable[] getDrawables();
+    method public long getId();
+    method public int getIndex();
+    method public void incrementIndex();
+    method public void setDrawables(android.graphics.drawable.Drawable[]);
+    method public void setIndex(int);
+  }
+
+  public abstract class ObjectAdapter {
+    ctor public ObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public ObjectAdapter();
+    method public abstract java.lang.Object get(int);
+    method public long getId(int);
+    method public final android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public final boolean hasStableIds();
+    method public boolean isImmediateNotifySupported();
+    method protected final void notifyChanged();
+    method public final void notifyItemRangeChanged(int, int);
+    method protected final void notifyItemRangeInserted(int, int);
+    method protected final void notifyItemRangeRemoved(int, int);
+    method protected void onHasStableIdsChanged();
+    method protected void onPresenterSelectorChanged();
+    method public final void registerObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+    method public final void setHasStableIds(boolean);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public abstract int size();
+    method public final void unregisterAllObservers();
+    method public final void unregisterObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+    field public static final int NO_ID = -1; // 0xffffffff
+  }
+
+  public static abstract class ObjectAdapter.DataObserver {
+    ctor public ObjectAdapter.DataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeRemoved(int, int);
+  }
+
+  public abstract interface OnActionClickedListener {
+    method public abstract void onActionClicked(android.support.v17.leanback.widget.Action);
+  }
+
+  public abstract interface OnChildLaidOutListener {
+    method public abstract void onChildLaidOut(android.view.ViewGroup, android.view.View, int, long);
+  }
+
+  public abstract deprecated interface OnChildSelectedListener {
+    method public abstract void onChildSelected(android.view.ViewGroup, android.view.View, int, long);
+  }
+
+  public abstract class OnChildViewHolderSelectedListener {
+    ctor public OnChildViewHolderSelectedListener();
+    method public void onChildViewHolderSelected(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
+    method public void onChildViewHolderSelectedAndPositioned(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
+  }
+
+  public abstract interface OnItemViewClickedListener implements android.support.v17.leanback.widget.BaseOnItemViewClickedListener {
+  }
+
+  public abstract interface OnItemViewSelectedListener implements android.support.v17.leanback.widget.BaseOnItemViewSelectedListener {
+  }
+
+  public class PageRow extends android.support.v17.leanback.widget.Row {
+    ctor public PageRow(android.support.v17.leanback.widget.HeaderItem);
+    method public final boolean isRenderedAsRowView();
+  }
+
+  public abstract class Parallax<PropertyT extends android.util.Property> {
+    ctor public Parallax();
+    method public void addEffect(android.support.v17.leanback.widget.ParallaxEffect);
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue...);
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue...);
+    method public abstract PropertyT addProperty(java.lang.String);
+    method public abstract PropertyT createProperty(java.lang.String, int);
+    method public java.util.List<android.support.v17.leanback.widget.ParallaxEffect> getEffects();
+    method public final java.util.List<PropertyT> getProperties();
+    method public void removeAllEffects();
+    method public void removeEffect(android.support.v17.leanback.widget.ParallaxEffect);
+    method public void updateValues();
+    method public abstract void verifyProperties() throws java.lang.IllegalStateException;
+  }
+
+  public static abstract class Parallax.FloatParallax<FloatPropertyT extends android.support.v17.leanback.widget.Parallax.FloatProperty> extends android.support.v17.leanback.widget.Parallax {
+    ctor public Parallax.FloatParallax();
+    method public final FloatPropertyT addProperty(java.lang.String);
+    method public abstract float getMaxValue();
+    method public final float getPropertyValue(int);
+    method public final void setPropertyValue(int, float);
+    method public final void verifyProperties() throws java.lang.IllegalStateException;
+  }
+
+  public static class Parallax.FloatProperty extends android.util.Property {
+    ctor public Parallax.FloatProperty(java.lang.String, int);
+    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue at(float, float);
+    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atAbsolute(float);
+    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atFraction(float);
+    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax.FloatParallax);
+    method public final int getIndex();
+    method public final void set(android.support.v17.leanback.widget.Parallax.FloatParallax, java.lang.Float);
+    field public static final float UNKNOWN_AFTER = 3.4028235E38f;
+    field public static final float UNKNOWN_BEFORE = -3.4028235E38f;
+  }
+
+  public static class Parallax.FloatPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
+    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float);
+    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float, float);
+    method public final float getMarkerValue(android.support.v17.leanback.widget.Parallax.FloatParallax);
+  }
+
+  public static abstract class Parallax.IntParallax<IntPropertyT extends android.support.v17.leanback.widget.Parallax.IntProperty> extends android.support.v17.leanback.widget.Parallax {
+    ctor public Parallax.IntParallax();
+    method public final IntPropertyT addProperty(java.lang.String);
+    method public abstract int getMaxValue();
+    method public final int getPropertyValue(int);
+    method public final void setPropertyValue(int, int);
+    method public final void verifyProperties() throws java.lang.IllegalStateException;
+  }
+
+  public static class Parallax.IntProperty extends android.util.Property {
+    ctor public Parallax.IntProperty(java.lang.String, int);
+    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue at(int, float);
+    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atAbsolute(int);
+    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atFraction(float);
+    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax.IntParallax);
+    method public final int getIndex();
+    method public final void set(android.support.v17.leanback.widget.Parallax.IntParallax, java.lang.Integer);
+    field public static final int UNKNOWN_AFTER = 2147483647; // 0x7fffffff
+    field public static final int UNKNOWN_BEFORE = -2147483648; // 0x80000000
+  }
+
+  public static class Parallax.IntPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
+    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int);
+    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int, float);
+    method public final int getMarkerValue(android.support.v17.leanback.widget.Parallax.IntParallax);
+  }
+
+  public static class Parallax.PropertyMarkerValue<PropertyT> {
+    ctor public Parallax.PropertyMarkerValue(PropertyT);
+    method public PropertyT getProperty();
+  }
+
+  public abstract class ParallaxEffect<ParallaxEffectT extends android.support.v17.leanback.widget.ParallaxEffect, PropertyMarkerValueT extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> {
+    ctor public ParallaxEffect();
+    method public final void addTarget(android.support.v17.leanback.widget.ParallaxTarget);
+    method protected abstract float calculateFraction(android.support.v17.leanback.widget.Parallax);
+    method public final java.util.List<PropertyMarkerValueT> getPropertyRanges();
+    method public final java.util.List<android.support.v17.leanback.widget.ParallaxTarget> getTargets();
+    method public final void performMapping(android.support.v17.leanback.widget.Parallax);
+    method public final void removeTarget(android.support.v17.leanback.widget.ParallaxTarget);
+    method public final void setPropertyRanges(PropertyMarkerValueT...);
+    method public final android.support.v17.leanback.widget.ParallaxEffect target(android.support.v17.leanback.widget.ParallaxTarget);
+    method public final android.support.v17.leanback.widget.ParallaxEffect target(java.lang.Object, android.animation.PropertyValuesHolder);
+  }
+
+  public static final class ParallaxEffect.FloatEffect extends android.support.v17.leanback.widget.ParallaxEffect {
+    ctor public ParallaxEffect.FloatEffect();
+    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
+  }
+
+  public static final class ParallaxEffect.IntEffect extends android.support.v17.leanback.widget.ParallaxEffect {
+    ctor public ParallaxEffect.IntEffect();
+    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
+  }
+
+  public abstract class ParallaxTarget {
+    ctor public ParallaxTarget();
+    method public abstract float getFraction();
+    method public abstract void update(float);
+  }
+
+  public static final class ParallaxTarget.PropertyValuesHolderTarget extends android.support.v17.leanback.widget.ParallaxTarget {
+    ctor public ParallaxTarget.PropertyValuesHolderTarget(java.lang.Object, android.animation.PropertyValuesHolder);
+    method public float getFraction();
+    method public void update(float);
+  }
+
+  public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
+    ctor public PlaybackControlsRow(java.lang.Object);
+    ctor public PlaybackControlsRow();
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(android.support.v17.leanback.widget.ObjectAdapter, int);
+    method public int getBufferedProgress();
+    method public long getBufferedProgressLong();
+    method public int getCurrentTime();
+    method public long getCurrentTimeLong();
+    method public final android.graphics.drawable.Drawable getImageDrawable();
+    method public final java.lang.Object getItem();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getPrimaryActionsAdapter();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getSecondaryActionsAdapter();
+    method public int getTotalTime();
+    method public long getTotalTimeLong();
+    method public void setBufferedProgress(int);
+    method public void setBufferedProgressLong(long);
+    method public void setCurrentTime(int);
+    method public void setCurrentTimeLong(long);
+    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+    method public final void setImageDrawable(android.graphics.drawable.Drawable);
+    method public final void setPrimaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setSecondaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setTotalTime(int);
+    method public void setTotalTimeLong(long);
+  }
+
+  public static class PlaybackControlsRow.ClosedCaptioningAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context);
+    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.FastForwardAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context);
+    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context, int);
+  }
+
+  public static class PlaybackControlsRow.HighQualityAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context);
+    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.MoreActions extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.MoreActions(android.content.Context);
+  }
+
+  public static abstract class PlaybackControlsRow.MultiAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.MultiAction(int);
+    method public int getActionCount();
+    method public android.graphics.drawable.Drawable getDrawable(int);
+    method public int getIndex();
+    method public java.lang.String getLabel(int);
+    method public java.lang.String getSecondaryLabel(int);
+    method public void nextIndex();
+    method public void setDrawables(android.graphics.drawable.Drawable[]);
+    method public void setIndex(int);
+    method public void setLabels(java.lang.String[]);
+    method public void setSecondaryLabels(java.lang.String[]);
+  }
+
+  public static class PlaybackControlsRow.PictureInPictureAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.PictureInPictureAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.PlayPauseAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.PlayPauseAction(android.content.Context);
+    field public static int PAUSE;
+    field public static int PLAY;
+  }
+
+  public static class PlaybackControlsRow.RepeatAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context);
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int);
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int, int);
+    field public static int ALL;
+    field public static int NONE;
+    field public static int ONE;
+  }
+
+  public static class PlaybackControlsRow.RewindAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.RewindAction(android.content.Context);
+    ctor public PlaybackControlsRow.RewindAction(android.content.Context, int);
+  }
+
+  public static class PlaybackControlsRow.ShuffleAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context);
+    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.SkipNextAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.SkipNextAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.SkipPreviousAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.SkipPreviousAction(android.content.Context);
+  }
+
+  public static abstract class PlaybackControlsRow.ThumbsAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ThumbsAction(int, android.content.Context, int, int);
+    field public static int OUTLINE;
+    field public static int SOLID;
+  }
+
+  public static class PlaybackControlsRow.ThumbsDownAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+    ctor public PlaybackControlsRow.ThumbsDownAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.ThumbsUpAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+    ctor public PlaybackControlsRow.ThumbsUpAction(android.content.Context);
+  }
+
+  public class PlaybackControlsRowPresenter extends android.support.v17.leanback.widget.PlaybackRowPresenter {
+    ctor public PlaybackControlsRowPresenter(android.support.v17.leanback.widget.Presenter);
+    ctor public PlaybackControlsRowPresenter();
+    method public boolean areSecondaryActionsHidden();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public int getBackgroundColor();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public int getProgressColor();
+    method public void setBackgroundColor(int);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public void setProgressColor(int);
+    method public void setSecondaryActionsHidden(boolean);
+    method public void showBottomSpace(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
+    method public void showPrimaryActions(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
+  }
+
+  public class PlaybackControlsRowPresenter.ViewHolder extends android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder {
+    field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDescriptionViewHolder;
+  }
+
+  public abstract class PlaybackRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public PlaybackRowPresenter();
+    method public void onReappear(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+  }
+
+  public static class PlaybackRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public PlaybackRowPresenter.ViewHolder(android.view.View);
+  }
+
+  public abstract class Presenter implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public Presenter();
+    method protected static void cancelAnimationsRecursive(android.view.View);
+    method public final java.lang.Object getFacet(java.lang.Class<?>);
+    method public abstract void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public abstract android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public abstract void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+    method public void setOnClickListener(android.support.v17.leanback.widget.Presenter.ViewHolder, android.view.View.OnClickListener);
+  }
+
+  public static class Presenter.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public Presenter.ViewHolder(android.view.View);
+    method public final java.lang.Object getFacet(java.lang.Class<?>);
+    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+    field public final android.view.View view;
+  }
+
+  public static abstract class Presenter.ViewHolderTask {
+    ctor public Presenter.ViewHolderTask();
+    method public void run(android.support.v17.leanback.widget.Presenter.ViewHolder);
+  }
+
+  public abstract class PresenterSelector {
+    ctor public PresenterSelector();
+    method public abstract android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter[] getPresenters();
+  }
+
+  public abstract class PresenterSwitcher {
+    ctor public PresenterSwitcher();
+    method public void clear();
+    method public final android.view.ViewGroup getParentViewGroup();
+    method public void init(android.view.ViewGroup, android.support.v17.leanback.widget.PresenterSelector);
+    method protected abstract void insertView(android.view.View);
+    method protected void onViewSelected(android.view.View);
+    method public void select(java.lang.Object);
+    method protected void showView(android.view.View, boolean);
+    method public void unselect();
+  }
+
+  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax.IntParallax {
+    ctor public RecyclerViewParallax();
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty createProperty(java.lang.String, int);
+    method public int getMaxValue();
+    method public android.support.v7.widget.RecyclerView getRecyclerView();
+    method public void setRecyclerView(android.support.v7.widget.RecyclerView);
+  }
+
+  public static final class RecyclerViewParallax.ChildPositionProperty extends android.support.v17.leanback.widget.Parallax.IntProperty {
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty adapterPosition(int);
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty fraction(float);
+    method public int getAdapterPosition();
+    method public float getFraction();
+    method public int getOffset();
+    method public int getViewId();
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty offset(int);
+    method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty viewId(int);
+  }
+
+  public class Row {
+    ctor public Row(long, android.support.v17.leanback.widget.HeaderItem);
+    ctor public Row(android.support.v17.leanback.widget.HeaderItem);
+    ctor public Row();
+    method public final android.support.v17.leanback.widget.HeaderItem getHeaderItem();
+    method public final long getId();
+    method public boolean isRenderedAsRowView();
+    method public final void setHeaderItem(android.support.v17.leanback.widget.HeaderItem);
+    method public final void setId(long);
+  }
+
+  public class RowHeaderPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public RowHeaderPresenter();
+    method protected static float getFontDescent(android.widget.TextView, android.graphics.Paint);
+    method public int getSpaceUnderBaseline(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+    method public boolean isNullItemVisibilityGone();
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setNullItemVisibilityGone(boolean);
+    method public final void setSelectLevel(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, float);
+  }
+
+  public static class RowHeaderPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public RowHeaderPresenter.ViewHolder(android.view.View);
+    method public final float getSelectLevel();
+  }
+
+  public final class RowHeaderView extends android.widget.TextView {
+    ctor public RowHeaderView(android.content.Context);
+    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet);
+    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public abstract class RowPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public RowPresenter();
+    method protected abstract android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected void dispatchItemSelectedListener(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public void freeze(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public final android.support.v17.leanback.widget.RowHeaderPresenter getHeaderPresenter();
+    method public final android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final boolean getSelectEffectEnabled();
+    method public final float getSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final int getSyncActivatePolicy();
+    method protected void initializeRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected boolean isClippingChildren();
+    method public boolean isUsingDefaultSelectEffect();
+    method protected void onBindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder, java.lang.Object);
+    method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method protected void onRowViewAttachedToWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewDetachedFromWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewExpanded(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method protected void onRowViewSelected(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onUnbindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method public final void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setEntranceTransitionState(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public final void setHeaderPresenter(android.support.v17.leanback.widget.RowHeaderPresenter);
+    method public final void setRowViewExpanded(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+    method public final void setRowViewSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+    method public final void setSelectEffectEnabled(boolean);
+    method public final void setSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder, float);
+    method public final void setSyncActivatePolicy(int);
+    field public static final int SYNC_ACTIVATED_CUSTOM = 0; // 0x0
+    field public static final int SYNC_ACTIVATED_TO_EXPANDED = 1; // 0x1
+    field public static final int SYNC_ACTIVATED_TO_EXPANDED_AND_SELECTED = 3; // 0x3
+    field public static final int SYNC_ACTIVATED_TO_SELECTED = 2; // 0x2
+  }
+
+  public static class RowPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public RowPresenter.ViewHolder(android.view.View);
+    method public final android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder getHeaderViewHolder();
+    method public final android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public final android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.view.View.OnKeyListener getOnKeyListener();
+    method public final android.support.v17.leanback.widget.Row getRow();
+    method public final java.lang.Object getRowObject();
+    method public final float getSelectLevel();
+    method public java.lang.Object getSelectedItem();
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder getSelectedItemViewHolder();
+    method public final boolean isExpanded();
+    method public final boolean isSelected();
+    method public final void setActivated(boolean);
+    method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
+    method public void setOnKeyListener(android.view.View.OnKeyListener);
+    method public final void syncActivatedStatus(android.view.View);
+    field protected final android.support.v17.leanback.graphics.ColorOverlayDimmer mColorDimmer;
+  }
+
+  public class SearchBar extends android.widget.RelativeLayout {
+    ctor public SearchBar(android.content.Context);
+    ctor public SearchBar(android.content.Context, android.util.AttributeSet);
+    ctor public SearchBar(android.content.Context, android.util.AttributeSet, int);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public java.lang.CharSequence getHint();
+    method public java.lang.String getTitle();
+    method public boolean isRecognizing();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setPermissionListener(android.support.v17.leanback.widget.SearchBar.SearchBarPermissionListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchBarListener(android.support.v17.leanback.widget.SearchBar.SearchBarListener);
+    method public void setSearchQuery(java.lang.String);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setSpeechRecognizer(android.speech.SpeechRecognizer);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+    method public void stopRecognition();
+  }
+
+  public static abstract interface SearchBar.SearchBarListener {
+    method public abstract void onKeyboardDismiss(java.lang.String);
+    method public abstract void onSearchQueryChange(java.lang.String);
+    method public abstract void onSearchQuerySubmit(java.lang.String);
+  }
+
+  public static abstract interface SearchBar.SearchBarPermissionListener {
+    method public abstract void requestAudioPermission();
+  }
+
+  public class SearchEditText extends android.support.v17.leanback.widget.StreamingTextView {
+    ctor public SearchEditText(android.content.Context);
+    ctor public SearchEditText(android.content.Context, android.util.AttributeSet);
+    ctor public SearchEditText(android.content.Context, android.util.AttributeSet, int);
+    method public void setOnKeyboardDismissListener(android.support.v17.leanback.widget.SearchEditText.OnKeyboardDismissListener);
+  }
+
+  public static abstract interface SearchEditText.OnKeyboardDismissListener {
+    method public abstract void onKeyboardDismiss();
+  }
+
+  public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
+    ctor public SearchOrbView(android.content.Context);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet, int);
+    method public void enableOrbColorAnimation(boolean);
+    method public int getOrbColor();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getOrbColors();
+    method public android.graphics.drawable.Drawable getOrbIcon();
+    method public void onClick(android.view.View);
+    method public void setOnOrbClickedListener(android.view.View.OnClickListener);
+    method public void setOrbColor(int);
+    method public deprecated void setOrbColor(int, int);
+    method public void setOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setOrbIcon(android.graphics.drawable.Drawable);
+  }
+
+  public static class SearchOrbView.Colors {
+    ctor public SearchOrbView.Colors(int);
+    ctor public SearchOrbView.Colors(int, int);
+    ctor public SearchOrbView.Colors(int, int, int);
+    method public static int getBrightColor(int);
+    field public int brightColor;
+    field public int color;
+    field public int iconColor;
+  }
+
+  public class SectionRow extends android.support.v17.leanback.widget.Row {
+    ctor public SectionRow(android.support.v17.leanback.widget.HeaderItem);
+    ctor public SectionRow(long, java.lang.String);
+    ctor public SectionRow(java.lang.String);
+    method public final boolean isRenderedAsRowView();
+  }
+
+  public class ShadowOverlayContainer extends android.widget.FrameLayout {
+    ctor public ShadowOverlayContainer(android.content.Context);
+    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet);
+    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int);
+    method public int getShadowType();
+    method public android.view.View getWrappedView();
+    method public deprecated void initialize(boolean, boolean);
+    method public deprecated void initialize(boolean, boolean, boolean);
+    method public static void prepareParentForShadow(android.view.ViewGroup);
+    method public void setOverlayColor(int);
+    method public void setShadowFocusLevel(float);
+    method public static boolean supportsDynamicShadow();
+    method public static boolean supportsShadow();
+    method public void useDynamicShadow();
+    method public void useDynamicShadow(float, float);
+    method public void useStaticShadow();
+    method public void wrap(android.view.View);
+    field public static final int SHADOW_DYNAMIC = 3; // 0x3
+    field public static final int SHADOW_NONE = 1; // 0x1
+    field public static final int SHADOW_STATIC = 2; // 0x2
+  }
+
+  public final class ShadowOverlayHelper {
+    method public android.support.v17.leanback.widget.ShadowOverlayContainer createShadowOverlayContainer(android.content.Context);
+    method public int getShadowType();
+    method public boolean needsOverlay();
+    method public boolean needsRoundedCorner();
+    method public boolean needsWrapper();
+    method public void onViewCreated(android.view.View);
+    method public void prepareParentForShadow(android.view.ViewGroup);
+    method public static void setNoneWrapperOverlayColor(android.view.View, int);
+    method public static void setNoneWrapperShadowFocusLevel(android.view.View, float);
+    method public void setOverlayColor(android.view.View, int);
+    method public void setShadowFocusLevel(android.view.View, float);
+    method public static boolean supportsDynamicShadow();
+    method public static boolean supportsForeground();
+    method public static boolean supportsRoundedCorner();
+    method public static boolean supportsShadow();
+    field public static final int SHADOW_DYNAMIC = 3; // 0x3
+    field public static final int SHADOW_NONE = 1; // 0x1
+    field public static final int SHADOW_STATIC = 2; // 0x2
+  }
+
+  public static final class ShadowOverlayHelper.Builder {
+    ctor public ShadowOverlayHelper.Builder();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper build(android.content.Context);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder keepForegroundDrawable(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsOverlay(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsRoundedCorner(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsShadow(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder options(android.support.v17.leanback.widget.ShadowOverlayHelper.Options);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder preferZOrder(boolean);
+  }
+
+  public static final class ShadowOverlayHelper.Options {
+    ctor public ShadowOverlayHelper.Options();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options dynamicShadowZ(float, float);
+    method public final float getDynamicShadowFocusedZ();
+    method public final float getDynamicShadowUnfocusedZ();
+    method public final int getRoundedCornerRadius();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options roundedCornerRadius(int);
+    field public static final android.support.v17.leanback.widget.ShadowOverlayHelper.Options DEFAULT;
+  }
+
+  public final class SinglePresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public SinglePresenterSelector(android.support.v17.leanback.widget.Presenter);
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+  }
+
+  public class SparseArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public SparseArrayObjectAdapter();
+    method public void clear(int);
+    method public void clear();
+    method public java.lang.Object get(int);
+    method public int indexOf(java.lang.Object);
+    method public int indexOf(int);
+    method public java.lang.Object lookup(int);
+    method public void notifyArrayItemRangeChanged(int, int);
+    method public void set(int, java.lang.Object);
+    method public int size();
+  }
+
+  public class SpeechOrbView extends android.support.v17.leanback.widget.SearchOrbView {
+    ctor public SpeechOrbView(android.content.Context);
+    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet);
+    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet, int);
+    method public void setListeningOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setNotListeningOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSoundLevel(int);
+    method public void showListening();
+    method public void showNotListening();
+  }
+
+  public abstract interface SpeechRecognitionCallback {
+    method public abstract void recognizeSpeech();
+  }
+
+   class StreamingTextView extends android.widget.EditText {
+    ctor public StreamingTextView(android.content.Context, android.util.AttributeSet);
+    ctor public StreamingTextView(android.content.Context, android.util.AttributeSet, int);
+    method public static boolean isLayoutRtl(android.view.View);
+    method public void reset();
+    method public void setFinalRecognizedText(java.lang.CharSequence);
+    method public void updateRecognizedText(java.lang.String, java.lang.String);
+    method public void updateRecognizedText(java.lang.String, java.util.List<java.lang.Float>);
+  }
+
+  public class TitleHelper {
+    ctor public TitleHelper(android.view.ViewGroup, android.view.View);
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+    method public android.view.ViewGroup getSceneRoot();
+    method public android.view.View getTitleView();
+    method public void showTitle(boolean);
+  }
+
+  public class TitleView extends android.widget.FrameLayout implements android.support.v17.leanback.widget.TitleViewAdapter.Provider {
+    ctor public TitleView(android.content.Context);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet, int);
+    method public void enableAnimation(boolean);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public android.view.View getSearchAffordanceView();
+    method public java.lang.CharSequence getTitle();
+    method public android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void updateComponentsVisibility(int);
+  }
+
+  public abstract class TitleViewAdapter {
+    ctor public TitleViewAdapter();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public abstract android.view.View getSearchAffordanceView();
+    method public java.lang.CharSequence getTitle();
+    method public void setAnimationEnabled(boolean);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.CharSequence);
+    method public void updateComponentsVisibility(int);
+    field public static final int BRANDING_VIEW_VISIBLE = 2; // 0x2
+    field public static final int FULL_VIEW_VISIBLE = 6; // 0x6
+    field public static final int SEARCH_VIEW_VISIBLE = 4; // 0x4
+  }
+
+  public static abstract interface TitleViewAdapter.Provider {
+    method public abstract android.support.v17.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+  }
+
+  public class VerticalGridPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public VerticalGridPresenter();
+    ctor public VerticalGridPresenter(int);
+    ctor public VerticalGridPresenter(int, boolean);
+    method public final boolean areChildRoundedCornersEnabled();
+    method protected android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder createGridViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+    method public final void enableChildRoundedCorners(boolean);
+    method public final int getFocusZoomFactor();
+    method public final boolean getKeepChildForeground();
+    method public int getNumberOfColumns();
+    method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public final boolean getShadowEnabled();
+    method protected void initializeGridViewHolder(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder);
+    method public final boolean isFocusDimmerUsed();
+    method public boolean isUsingDefaultShadow();
+    method public boolean isUsingZOrder(android.content.Context);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setEntranceTransitionState(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder, boolean);
+    method public final void setKeepChildForeground(boolean);
+    method public void setNumberOfColumns(int);
+    method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public final void setShadowEnabled(boolean);
+  }
+
+  public static class VerticalGridPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public VerticalGridPresenter.ViewHolder(android.support.v17.leanback.widget.VerticalGridView);
+    method public android.support.v17.leanback.widget.VerticalGridView getGridView();
+  }
+
+  public class VerticalGridView extends android.support.v7.widget.RecyclerView {
+    ctor public VerticalGridView(android.content.Context);
+    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet);
+    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet, int);
+    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+    method public void setColumnWidth(int);
+    method public void setNumColumns(int);
+  }
+
+  public abstract interface ViewHolderTask {
+    method public abstract void run(android.support.v7.widget.RecyclerView.ViewHolder);
+  }
+
+}
+
+package android.support.v17.leanback.widget.picker {
+
+  public class Picker extends android.widget.FrameLayout {
+    ctor public Picker(android.content.Context, android.util.AttributeSet, int);
+    method public void addOnValueChangedListener(android.support.v17.leanback.widget.picker.Picker.PickerValueListener);
+    method public float getActivatedVisibleItemCount();
+    method public android.support.v17.leanback.widget.picker.PickerColumn getColumnAt(int);
+    method public int getColumnsCount();
+    method protected int getPickerItemHeightPixels();
+    method public final int getPickerItemLayoutId();
+    method public final int getPickerItemTextViewId();
+    method public int getSelectedColumn();
+    method public final java.lang.CharSequence getSeparator();
+    method public float getVisibleItemCount();
+    method public void onColumnValueChanged(int, int);
+    method public void removeOnValueChangedListener(android.support.v17.leanback.widget.picker.Picker.PickerValueListener);
+    method public void setActivatedVisibleItemCount(float);
+    method public void setColumnAt(int, android.support.v17.leanback.widget.picker.PickerColumn);
+    method public void setColumnValue(int, int, boolean);
+    method public void setColumns(java.util.List<android.support.v17.leanback.widget.picker.PickerColumn>);
+    method public final void setPickerItemTextViewId(int);
+    method public void setSelectedColumn(int);
+    method public final void setSeparator(java.lang.CharSequence);
+    method public void setVisibleItemCount(float);
+  }
+
+  public static abstract interface Picker.PickerValueListener {
+    method public abstract void onValueChanged(android.support.v17.leanback.widget.picker.Picker, int);
+  }
+
+  public class PickerColumn {
+    ctor public PickerColumn();
+    method public int getCount();
+    method public int getCurrentValue();
+    method public java.lang.CharSequence getLabelFor(int);
+    method public java.lang.String getLabelFormat();
+    method public int getMaxValue();
+    method public int getMinValue();
+    method public java.lang.CharSequence[] getStaticLabels();
+    method public void setCurrentValue(int);
+    method public void setLabelFormat(java.lang.String);
+    method public void setMaxValue(int);
+    method public void setMinValue(int);
+    method public void setStaticLabels(java.lang.CharSequence[]);
+  }
+
+  public class TimePicker extends android.support.v17.leanback.widget.picker.Picker {
+    ctor public TimePicker(android.content.Context, android.util.AttributeSet);
+    ctor public TimePicker(android.content.Context, android.util.AttributeSet, int);
+    method public int getHour();
+    method public int getMinute();
+    method public boolean is24Hour();
+    method public boolean isPm();
+    method public void setHour(int);
+    method public void setIs24Hour(boolean);
+    method public void setMinute(int);
+  }
+
+}
+
+package android.support.v17.preference {
+
+  public abstract class BaseLeanbackPreferenceFragment extends android.support.v14.preference.PreferenceFragment {
+    ctor public BaseLeanbackPreferenceFragment();
+  }
+
+  public class LeanbackListPreferenceDialogFragment extends android.support.v17.preference.LeanbackPreferenceDialogFragment {
+    ctor public LeanbackListPreferenceDialogFragment();
+    method public static android.support.v17.preference.LeanbackListPreferenceDialogFragment newInstanceMulti(java.lang.String);
+    method public static android.support.v17.preference.LeanbackListPreferenceDialogFragment newInstanceSingle(java.lang.String);
+    method public android.support.v7.widget.RecyclerView.Adapter onCreateAdapter();
+  }
+
+  public class LeanbackListPreferenceDialogFragment.AdapterMulti extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+    ctor public LeanbackListPreferenceDialogFragment.AdapterMulti(java.lang.CharSequence[], java.lang.CharSequence[], java.util.Set<java.lang.String>);
+    method public int getItemCount();
+    method public void onBindViewHolder(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder, int);
+    method public android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+  }
+
+  public class LeanbackListPreferenceDialogFragment.AdapterSingle extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+    ctor public LeanbackListPreferenceDialogFragment.AdapterSingle(java.lang.CharSequence[], java.lang.CharSequence[], java.lang.CharSequence);
+    method public int getItemCount();
+    method public void onBindViewHolder(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder, int);
+    method public android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+  }
+
+  public static class LeanbackListPreferenceDialogFragment.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.view.View.OnClickListener {
+    ctor public LeanbackListPreferenceDialogFragment.ViewHolder(android.view.View, android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener);
+    method public android.view.ViewGroup getContainer();
+    method public android.widget.TextView getTitleView();
+    method public android.widget.Checkable getWidgetView();
+    method public void onClick(android.view.View);
+  }
+
+  public static abstract interface LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+    method public abstract void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+  }
+
+  public class LeanbackPreferenceDialogFragment extends android.app.Fragment {
+    ctor public LeanbackPreferenceDialogFragment();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    field public static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class LeanbackPreferenceFragment extends android.support.v17.preference.BaseLeanbackPreferenceFragment {
+    ctor public LeanbackPreferenceFragment();
+    method public void setTitle(java.lang.CharSequence);
+  }
+
+  public abstract class LeanbackSettingsFragment extends android.app.Fragment implements android.support.v14.preference.PreferenceFragment.OnPreferenceDisplayDialogCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartFragmentCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartScreenCallback {
+    ctor public LeanbackSettingsFragment();
+    method public boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+    method public abstract void onPreferenceStartInitialScreen();
+    method public void startImmersiveFragment(android.app.Fragment);
+    method public void startPreferenceFragment(android.app.Fragment);
+  }
+
+}
+
+package android.support.v4.accessibilityservice {
+
+  public final class AccessibilityServiceInfoCompat {
+    method public static java.lang.String capabilityToString(int);
+    method public static java.lang.String feedbackTypeToString(int);
+    method public static java.lang.String flagToString(int);
+    method public static boolean getCanRetrieveWindowContent(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static deprecated java.lang.String getDescription(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static java.lang.String getId(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static android.content.pm.ResolveInfo getResolveInfo(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static java.lang.String getSettingsActivityName(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static java.lang.String loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+    field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+    field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+    field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+    field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+  }
+
+}
+
+package android.support.v4.app {
+
+  public deprecated class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int, int);
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, boolean, int, int, int);
+    method public boolean isDrawerIndicatorEnabled();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void setDrawerIndicatorEnabled(boolean);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void syncState();
+  }
+
+  public static abstract interface ActionBarDrawerToggle.Delegate {
+    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+    method public abstract void setActionBarDescription(int);
+    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+  }
+
+  public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+    method public abstract android.support.v4.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+  }
+
+  public class ActivityCompat extends android.support.v4.content.ContextCompat {
+    ctor protected ActivityCompat();
+    method public static void finishAffinity(android.app.Activity);
+    method public static void finishAfterTransition(android.app.Activity);
+    method public static android.net.Uri getReferrer(android.app.Activity);
+    method public static boolean invalidateOptionsMenu(android.app.Activity);
+    method public static void postponeEnterTransition(android.app.Activity);
+    method public static void requestPermissions(android.app.Activity, java.lang.String[], int);
+    method public static void setEnterSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+    method public static void setExitSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, java.lang.String);
+    method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle);
+    method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public static void startPostponedEnterTransition(android.app.Activity);
+  }
+
+  public static abstract interface ActivityCompat.OnRequestPermissionsResultCallback {
+    method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+  }
+
+  public final class ActivityManagerCompat {
+    method public static boolean isLowRamDevice(android.app.ActivityManager);
+  }
+
+  public class ActivityOptionsCompat {
+    ctor protected ActivityOptionsCompat();
+    method public android.graphics.Rect getLaunchBounds();
+    method public static android.support.v4.app.ActivityOptionsCompat makeBasic();
+    method public static android.support.v4.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
+    method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.support.v4.util.Pair<android.view.View, java.lang.String>...);
+    method public static android.support.v4.app.ActivityOptionsCompat makeTaskLaunchBehind();
+    method public static android.support.v4.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+    method public void requestUsageTimeReport(android.app.PendingIntent);
+    method public android.support.v4.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect);
+    method public android.os.Bundle toBundle();
+    method public void update(android.support.v4.app.ActivityOptionsCompat);
+    field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+    field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+  }
+
+  public final class AlarmManagerCompat {
+    method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+    method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+  }
+
+  public class AppLaunchChecker {
+    ctor public AppLaunchChecker();
+    method public static boolean hasStartedFromLauncher(android.content.Context);
+    method public static void onActivityCreate(android.app.Activity);
+  }
+
+  public final class AppOpsManagerCompat {
+    method public static int noteOp(android.content.Context, java.lang.String, int, java.lang.String);
+    method public static int noteProxyOp(android.content.Context, java.lang.String, java.lang.String);
+    method public static java.lang.String permissionToOp(java.lang.String);
+    field public static final int MODE_ALLOWED = 0; // 0x0
+    field public static final int MODE_DEFAULT = 3; // 0x3
+    field public static final int MODE_IGNORED = 1; // 0x1
+  }
+
+  public final class BundleCompat {
+    method public static android.os.IBinder getBinder(android.os.Bundle, java.lang.String);
+    method public static void putBinder(android.os.Bundle, java.lang.String, android.os.IBinder);
+  }
+
+  public class DialogFragment extends android.support.v4.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method public android.app.Dialog getDialog();
+    method public boolean getShowsDialog();
+    method public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method public android.app.Dialog onCreateDialog(android.os.Bundle);
+    method public void onDismiss(android.content.DialogInterface);
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, int);
+    method public void show(android.support.v4.app.FragmentManager, java.lang.String);
+    method public int show(android.support.v4.app.FragmentTransaction, java.lang.String);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements android.content.ComponentCallbacks android.view.View.OnCreateContextMenuListener {
+    ctor public Fragment();
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final boolean equals(java.lang.Object);
+    method public final android.support.v4.app.FragmentActivity getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle getArguments();
+    method public final android.support.v4.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context getContext();
+    method public java.lang.Object getEnterTransition();
+    method public java.lang.Object getExitTransition();
+    method public final android.support.v4.app.FragmentManager getFragmentManager();
+    method public final java.lang.Object getHost();
+    method public final int getId();
+    method public android.support.v4.app.LoaderManager getLoaderManager();
+    method public final android.support.v4.app.Fragment getParentFragment();
+    method public java.lang.Object getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method public final boolean getRetainInstance();
+    method public java.lang.Object getReturnTransition();
+    method public java.lang.Object getSharedElementEnterTransition();
+    method public java.lang.Object getSharedElementReturnTransition();
+    method public final java.lang.String getString(int);
+    method public final java.lang.String getString(int, java.lang.Object...);
+    method public final java.lang.String getTag();
+    method public final android.support.v4.app.Fragment getTargetFragment();
+    method public final int getTargetRequestCode();
+    method public final java.lang.CharSequence getText(int);
+    method public boolean getUserVisibleHint();
+    method public android.view.View getView();
+    method public final int hashCode();
+    method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String);
+    method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method public void onActivityCreated(android.os.Bundle);
+    method public void onActivityResult(int, int, android.content.Intent);
+    method public void onAttach(android.content.Context);
+    method public deprecated void onAttach(android.app.Activity);
+    method public void onAttachFragment(android.support.v4.app.Fragment);
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public boolean onContextItemSelected(android.view.MenuItem);
+    method public void onCreate(android.os.Bundle);
+    method public android.view.animation.Animation onCreateAnimation(int, boolean, int);
+    method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
+    method public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDestroy();
+    method public void onDestroyOptionsMenu();
+    method public void onDestroyView();
+    method public void onDetach();
+    method public void onHiddenChanged(boolean);
+    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+    method public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void onOptionsMenuClosed(android.view.Menu);
+    method public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method public void onPrepareOptionsMenu(android.view.Menu);
+    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
+    method public void onResume();
+    method public void onSaveInstanceState(android.os.Bundle);
+    method public void onStart();
+    method public void onStop();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
+    method public void onViewStateRestored(android.os.Bundle);
+    method public void postponeEnterTransition();
+    method public void registerForContextMenu(android.view.View);
+    method public final void requestPermissions(java.lang.String[], int);
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle);
+    method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setEnterTransition(java.lang.Object);
+    method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setExitTransition(java.lang.Object);
+    method public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(android.support.v4.app.Fragment.SavedState);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(java.lang.Object);
+    method public void setRetainInstance(boolean);
+    method public void setReturnTransition(java.lang.Object);
+    method public void setSharedElementEnterTransition(java.lang.Object);
+    method public void setSharedElementReturnTransition(java.lang.Object);
+    method public void setTargetFragment(android.support.v4.app.Fragment, int);
+    method public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(java.lang.String);
+    method public void startActivity(android.content.Intent);
+    method public void startActivity(android.content.Intent, android.os.Bundle);
+    method public void startActivityForResult(android.content.Intent, int);
+    method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.app.Fragment.SavedState> CREATOR;
+  }
+
+  public class FragmentActivity extends android.app.Activity implements android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback {
+    ctor public FragmentActivity();
+    method public java.lang.Object getLastCustomNonConfigurationInstance();
+    method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+    method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+    method public void onAttachFragment(android.support.v4.app.Fragment);
+    method protected void onResumeFragments();
+    method public java.lang.Object onRetainCustomNonConfigurationInstance();
+    method public final java.lang.Object onRetainNonConfigurationInstance();
+    method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+    method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public void startIntentSenderFromFragment(android.support.v4.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method public deprecated void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method public android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
+    method public abstract android.view.View onFindViewById(int);
+    method public abstract boolean onHasView();
+  }
+
+  public class FragmentController {
+    method public void attachHost(android.support.v4.app.Fragment);
+    method public static final android.support.v4.app.FragmentController createController(android.support.v4.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public void dispatchMultiWindowModeChanged(boolean);
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public void dispatchPictureInPictureModeChanged(boolean);
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method public void doLoaderDestroy();
+    method public void doLoaderRetain();
+    method public void doLoaderStart();
+    method public void doLoaderStop(boolean);
+    method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public boolean execPendingActions();
+    method public android.support.v4.app.Fragment findFragmentByWho(java.lang.String);
+    method public java.util.List<android.support.v4.app.Fragment> getActiveFragments(java.util.List<android.support.v4.app.Fragment>);
+    method public int getActiveFragmentsCount();
+    method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+    method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public void reportLoaderStart();
+    method public deprecated void restoreAllState(android.os.Parcelable, java.util.List<android.support.v4.app.Fragment>);
+    method public void restoreAllState(android.os.Parcelable, android.support.v4.app.FragmentManagerNonConfig);
+    method public void restoreLoaderNonConfig(android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager>);
+    method public android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager> retainLoaderNonConfig();
+    method public android.support.v4.app.FragmentManagerNonConfig retainNestedNonConfig();
+    method public deprecated java.util.List<android.support.v4.app.Fragment> retainNonConfig();
+    method public android.os.Parcelable saveAllState();
+  }
+
+  public abstract class FragmentHostCallback<E> extends android.support.v4.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public android.view.View onFindViewById(int);
+    method public abstract E onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method public void onRequestPermissionsFromFragment(android.support.v4.app.Fragment, java.lang.String[], int);
+    method public boolean onShouldSaveFragmentState(android.support.v4.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(java.lang.String);
+    method public void onStartActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+    method public void onStartActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public void onStartIntentSenderFromFragment(android.support.v4.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager {
+    ctor public FragmentManager();
+    method public abstract void addOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+    method public abstract android.support.v4.app.FragmentTransaction beginTransaction();
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public abstract boolean executePendingTransactions();
+    method public abstract android.support.v4.app.Fragment findFragmentById(int);
+    method public abstract android.support.v4.app.Fragment findFragmentByTag(java.lang.String);
+    method public abstract android.support.v4.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public abstract int getBackStackEntryCount();
+    method public abstract android.support.v4.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+    method public abstract android.support.v4.app.Fragment getPrimaryNavigationFragment();
+    method public abstract boolean isDestroyed();
+    method public abstract void popBackStack();
+    method public abstract void popBackStack(java.lang.String, int);
+    method public abstract void popBackStack(int, int);
+    method public abstract boolean popBackStackImmediate();
+    method public abstract boolean popBackStackImmediate(java.lang.String, int);
+    method public abstract boolean popBackStackImmediate(int, int);
+    method public abstract void putFragment(android.os.Bundle, java.lang.String, android.support.v4.app.Fragment);
+    method public abstract void registerFragmentLifecycleCallbacks(android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public abstract void removeOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+    method public abstract android.support.v4.app.Fragment.SavedState saveFragmentInstanceState(android.support.v4.app.Fragment);
+    method public abstract void unregisterFragmentLifecycleCallbacks(android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static abstract interface FragmentManager.BackStackEntry {
+    method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
+    method public abstract int getBreadCrumbShortTitleRes();
+    method public abstract java.lang.CharSequence getBreadCrumbTitle();
+    method public abstract int getBreadCrumbTitleRes();
+    method public abstract int getId();
+    method public abstract java.lang.String getName();
+  }
+
+  public static abstract class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method public void onFragmentActivityCreated(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.os.Bundle);
+    method public void onFragmentAttached(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.os.Bundle);
+    method public void onFragmentDestroyed(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentDetached(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentPaused(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentPreAttached(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.content.Context);
+    method public void onFragmentResumed(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentSaveInstanceState(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentStopped(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+    method public void onFragmentViewCreated(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment, android.view.View, android.os.Bundle);
+    method public void onFragmentViewDestroyed(android.support.v4.app.FragmentManager, android.support.v4.app.Fragment);
+  }
+
+  public static abstract interface FragmentManager.OnBackStackChangedListener {
+    method public abstract void onBackStackChanged();
+  }
+
+  public class FragmentManagerNonConfig {
+  }
+
+  public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentPagerAdapter(android.support.v4.app.FragmentManager);
+    method public abstract android.support.v4.app.Fragment getItem(int);
+    method public long getItemId(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public abstract class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentStatePagerAdapter(android.support.v4.app.FragmentManager);
+    method public abstract android.support.v4.app.Fragment getItem(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor public FragmentTabHost(android.content.Context);
+    ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
+    method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
+    method public void onTabChanged(java.lang.String);
+    method public void setup(android.content.Context, android.support.v4.app.FragmentManager);
+    method public void setup(android.content.Context, android.support.v4.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor public FragmentTransaction();
+    method public abstract android.support.v4.app.FragmentTransaction add(android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction addSharedElement(android.view.View, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction addToBackStack(java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction attach(android.support.v4.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method public abstract void commitNow();
+    method public abstract void commitNowAllowingStateLoss();
+    method public abstract android.support.v4.app.FragmentTransaction detach(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction disallowAddToBackStack();
+    method public abstract android.support.v4.app.FragmentTransaction hide(android.support.v4.app.Fragment);
+    method public abstract boolean isAddToBackStackAllowed();
+    method public abstract boolean isEmpty();
+    method public abstract android.support.v4.app.FragmentTransaction postOnCommit(java.lang.Runnable);
+    method public abstract android.support.v4.app.FragmentTransaction remove(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction setAllowOptimization(boolean);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(int);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(int);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
+    method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int);
+    method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+    method public abstract android.support.v4.app.FragmentTransaction setPrimaryNavigationFragment(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction setTransition(int);
+    method public abstract android.support.v4.app.FragmentTransaction setTransitionStyle(int);
+    method public abstract android.support.v4.app.FragmentTransaction show(android.support.v4.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  public class ListFragment extends android.support.v4.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public void setEmptyText(java.lang.CharSequence);
+    method public void setListAdapter(android.widget.ListAdapter);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+  public abstract class LoaderManager {
+    ctor public LoaderManager();
+    method public abstract void destroyLoader(int);
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public abstract <D> android.support.v4.content.Loader<D> getLoader(int);
+    method public boolean hasRunningLoaders();
+    method public abstract <D> android.support.v4.content.Loader<D> initLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.support.v4.content.Loader<D> restartLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+  }
+
+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
+    method public abstract android.support.v4.content.Loader<D> onCreateLoader(int, android.os.Bundle);
+    method public abstract void onLoadFinished(android.support.v4.content.Loader<D>, D);
+    method public abstract void onLoaderReset(android.support.v4.content.Loader<D>);
+  }
+
+  public final class NavUtils {
+    method public static android.content.Intent getParentActivityIntent(android.app.Activity);
+    method public static android.content.Intent getParentActivityIntent(android.content.Context, java.lang.Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static android.content.Intent getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static java.lang.String getParentActivityName(android.app.Activity);
+    method public static java.lang.String getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void navigateUpFromSameTask(android.app.Activity);
+    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    field public static final java.lang.String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+  }
+
+  public class NotificationCompat {
+    ctor public NotificationCompat();
+    method public static android.support.v4.app.NotificationCompat.Action getAction(android.app.Notification, int);
+    method public static int getActionCount(android.app.Notification);
+    method public static java.lang.String getCategory(android.app.Notification);
+    method public static java.lang.String getChannel(android.app.Notification);
+    method public static android.os.Bundle getExtras(android.app.Notification);
+    method public static java.lang.String getGroup(android.app.Notification);
+    method public static boolean getLocalOnly(android.app.Notification);
+    method public static java.lang.String getSortKey(android.app.Notification);
+    method public static boolean isGroupSummary(android.app.Notification);
+    field public static final java.lang.String CATEGORY_ALARM = "alarm";
+    field public static final java.lang.String CATEGORY_CALL = "call";
+    field public static final java.lang.String CATEGORY_EMAIL = "email";
+    field public static final java.lang.String CATEGORY_ERROR = "err";
+    field public static final java.lang.String CATEGORY_EVENT = "event";
+    field public static final java.lang.String CATEGORY_MESSAGE = "msg";
+    field public static final java.lang.String CATEGORY_PROGRESS = "progress";
+    field public static final java.lang.String CATEGORY_PROMO = "promo";
+    field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final java.lang.String CATEGORY_REMINDER = "reminder";
+    field public static final java.lang.String CATEGORY_SERVICE = "service";
+    field public static final java.lang.String CATEGORY_SOCIAL = "social";
+    field public static final java.lang.String CATEGORY_STATUS = "status";
+    field public static final java.lang.String CATEGORY_SYSTEM = "sys";
+    field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+    field public static final int COLOR_DEFAULT = 0; // 0x0
+    field public static final int DEFAULT_ALL = -1; // 0xffffffff
+    field public static final int DEFAULT_LIGHTS = 4; // 0x4
+    field public static final int DEFAULT_SOUND = 1; // 0x1
+    field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+    field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+    field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+    field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession";
+    field public static final java.lang.String EXTRA_MESSAGES = "android.messages";
+    field public static final java.lang.String EXTRA_PEOPLE = "android.people";
+    field public static final java.lang.String EXTRA_PICTURE = "android.picture";
+    field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
+    field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+    field public static final java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+    field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
+    field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
+    field public static final java.lang.String EXTRA_SUB_TEXT = "android.subText";
+    field public static final java.lang.String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
+    field public static final java.lang.String EXTRA_TEXT = "android.text";
+    field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final java.lang.String EXTRA_TITLE = "android.title";
+    field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
+    field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+    field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+    field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
+    field public static final int FLAG_INSISTENT = 4; // 0x4
+    field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+    field public static final int FLAG_NO_CLEAR = 32; // 0x20
+    field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+    field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+    field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+    field public static final int PRIORITY_DEFAULT = 0; // 0x0
+    field public static final int PRIORITY_HIGH = 1; // 0x1
+    field public static final int PRIORITY_LOW = -1; // 0xffffffff
+    field public static final int PRIORITY_MAX = 2; // 0x2
+    field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+    field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+    field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+    field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+    field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+  }
+
+  public static class NotificationCompat.Action {
+    ctor public NotificationCompat.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.PendingIntent getActionIntent();
+    method public boolean getAllowGeneratedReplies();
+    method public android.support.v4.app.RemoteInput[] getDataOnlyRemoteInputs();
+    method public android.os.Bundle getExtras();
+    method public int getIcon();
+    method public android.support.v4.app.RemoteInput[] getRemoteInputs();
+    method public java.lang.CharSequence getTitle();
+    field public android.app.PendingIntent actionIntent;
+    field public int icon;
+    field public java.lang.CharSequence title;
+  }
+
+  public static final class NotificationCompat.Action.Builder {
+    ctor public NotificationCompat.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+    ctor public NotificationCompat.Action.Builder(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Action.Builder addRemoteInput(android.support.v4.app.RemoteInput);
+    method public android.support.v4.app.NotificationCompat.Action build();
+    method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Extender);
+    method public android.os.Bundle getExtras();
+    method public android.support.v4.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+  }
+
+  public static abstract interface NotificationCompat.Action.Extender {
+    method public abstract android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+  }
+
+  public static final class NotificationCompat.Action.WearableExtender implements android.support.v4.app.NotificationCompat.Action.Extender {
+    ctor public NotificationCompat.Action.WearableExtender();
+    ctor public NotificationCompat.Action.WearableExtender(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender clone();
+    method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+    method public java.lang.CharSequence getCancelLabel();
+    method public java.lang.CharSequence getConfirmLabel();
+    method public boolean getHintDisplayActionInline();
+    method public boolean getHintLaunchesActivity();
+    method public java.lang.CharSequence getInProgressLabel();
+    method public boolean isAvailableOffline();
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.BigPictureStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigPictureStyle();
+    ctor public NotificationCompat.BigPictureStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.BigTextStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigTextStyle();
+    ctor public NotificationCompat.BigTextStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle bigText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.Builder {
+    ctor public NotificationCompat.Builder(android.content.Context);
+    method public android.support.v4.app.NotificationCompat.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder addAction(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Builder addPerson(java.lang.String);
+    method public android.app.Notification build();
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Extender);
+    method public android.os.Bundle getExtras();
+    method public deprecated android.app.Notification getNotification();
+    method protected static java.lang.CharSequence limitCharSequenceLength(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setAutoCancel(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setCategory(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setChannel(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setColor(int);
+    method public android.support.v4.app.NotificationCompat.Builder setContent(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setContentInfo(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder setContentText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setDefaults(int);
+    method public android.support.v4.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setGroup(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setGroupSummary(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.Builder setLights(int, int, int);
+    method public android.support.v4.app.NotificationCompat.Builder setLocalOnly(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setNumber(int);
+    method public android.support.v4.app.NotificationCompat.Builder setOngoing(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setPriority(int);
+    method public android.support.v4.app.NotificationCompat.Builder setProgress(int, int, boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setPublicVersion(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+    method public android.support.v4.app.NotificationCompat.Builder setShowWhen(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int);
+    method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int, int);
+    method public android.support.v4.app.NotificationCompat.Builder setSortKey(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri);
+    method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri, int);
+    method public android.support.v4.app.NotificationCompat.Builder setStyle(android.support.v4.app.NotificationCompat.Style);
+    method public android.support.v4.app.NotificationCompat.Builder setSubText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setUsesChronometer(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setVibrate(long[]);
+    method public android.support.v4.app.NotificationCompat.Builder setVisibility(int);
+    method public android.support.v4.app.NotificationCompat.Builder setWhen(long);
+    field public java.util.ArrayList<java.lang.String> mPeople;
+  }
+
+  public static final class NotificationCompat.CarExtender implements android.support.v4.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.CarExtender();
+    ctor public NotificationCompat.CarExtender(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+    method public int getColor();
+    method public android.graphics.Bitmap getLargeIcon();
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation getUnreadConversation();
+    method public android.support.v4.app.NotificationCompat.CarExtender setColor(int);
+    method public android.support.v4.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.CarExtender setUnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation);
+  }
+
+  public static class NotificationCompat.CarExtender.UnreadConversation {
+    method public long getLatestTimestamp();
+    method public java.lang.String[] getMessages();
+    method public java.lang.String getParticipant();
+    method public java.lang.String[] getParticipants();
+    method public android.app.PendingIntent getReadPendingIntent();
+    method public android.support.v4.app.RemoteInput getRemoteInput();
+    method public android.app.PendingIntent getReplyPendingIntent();
+  }
+
+  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation build();
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent, android.support.v4.app.RemoteInput);
+  }
+
+  public static abstract interface NotificationCompat.Extender {
+    method public abstract android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+  }
+
+  public static class NotificationCompat.InboxStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.InboxStyle();
+    ctor public NotificationCompat.InboxStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.InboxStyle addLine(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.InboxStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.InboxStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.MessagingStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.MessagingStyle(java.lang.CharSequence);
+    method public void addCompatExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.MessagingStyle addMessage(android.support.v4.app.NotificationCompat.MessagingStyle.Message);
+    method public static android.support.v4.app.NotificationCompat.MessagingStyle extractMessagingStyleFromNotification(android.app.Notification);
+    method public java.lang.CharSequence getConversationTitle();
+    method public java.util.List<android.support.v4.app.NotificationCompat.MessagingStyle.Message> getMessages();
+    method public java.lang.CharSequence getUserDisplayName();
+    method public android.support.v4.app.NotificationCompat.MessagingStyle setConversationTitle(java.lang.CharSequence);
+    field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+  }
+
+  public static final class NotificationCompat.MessagingStyle.Message {
+    ctor public NotificationCompat.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
+    method public java.lang.String getDataMimeType();
+    method public android.net.Uri getDataUri();
+    method public java.lang.CharSequence getSender();
+    method public java.lang.CharSequence getText();
+    method public long getTimestamp();
+    method public android.support.v4.app.NotificationCompat.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
+  }
+
+  public static abstract class NotificationCompat.Style {
+    ctor public NotificationCompat.Style();
+    method public android.app.Notification build();
+    method public void setBuilder(android.support.v4.app.NotificationCompat.Builder);
+  }
+
+  public static final class NotificationCompat.WearableExtender implements android.support.v4.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.WearableExtender();
+    ctor public NotificationCompat.WearableExtender(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addAction(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addActions(java.util.List<android.support.v4.app.NotificationCompat.Action>);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification>);
+    method public android.support.v4.app.NotificationCompat.WearableExtender clearActions();
+    method public android.support.v4.app.NotificationCompat.WearableExtender clearPages();
+    method public android.support.v4.app.NotificationCompat.WearableExtender clone();
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+    method public java.util.List<android.support.v4.app.NotificationCompat.Action> getActions();
+    method public android.graphics.Bitmap getBackground();
+    method public java.lang.String getBridgeTag();
+    method public int getContentAction();
+    method public int getContentIcon();
+    method public int getContentIconGravity();
+    method public boolean getContentIntentAvailableOffline();
+    method public int getCustomContentHeight();
+    method public int getCustomSizePreset();
+    method public java.lang.String getDismissalId();
+    method public android.app.PendingIntent getDisplayIntent();
+    method public int getGravity();
+    method public boolean getHintAmbientBigPicture();
+    method public boolean getHintAvoidBackgroundClipping();
+    method public boolean getHintContentIntentLaunchesActivity();
+    method public boolean getHintHideIcon();
+    method public int getHintScreenTimeout();
+    method public boolean getHintShowBackgroundOnly();
+    method public java.util.List<android.app.Notification> getPages();
+    method public boolean getStartScrollBottom();
+    method public android.support.v4.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setBridgeTag(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentAction(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIcon(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setDismissalId(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setGravity(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+    field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field public static final int SIZE_DEFAULT = 0; // 0x0
+    field public static final int SIZE_FULL_SCREEN = 5; // 0x5
+    field public static final int SIZE_LARGE = 4; // 0x4
+    field public static final int SIZE_MEDIUM = 3; // 0x3
+    field public static final int SIZE_SMALL = 2; // 0x2
+    field public static final int SIZE_XSMALL = 1; // 0x1
+    field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+  }
+
+  public final class NotificationCompatExtras {
+    field public static final java.lang.String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+    field public static final java.lang.String EXTRA_GROUP_KEY = "android.support.groupKey";
+    field public static final java.lang.String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+    field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+    field public static final java.lang.String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+    field public static final java.lang.String EXTRA_SORT_KEY = "android.support.sortKey";
+  }
+
+  public abstract class NotificationCompatSideChannelService extends android.app.Service {
+    ctor public NotificationCompatSideChannelService();
+    method public abstract void cancel(java.lang.String, int, java.lang.String);
+    method public abstract void cancelAll(java.lang.String);
+    method public abstract void notify(java.lang.String, int, java.lang.String, android.app.Notification);
+    method public android.os.IBinder onBind(android.content.Intent);
+  }
+
+  public final class NotificationManagerCompat {
+    method public boolean areNotificationsEnabled();
+    method public void cancel(int);
+    method public void cancel(java.lang.String, int);
+    method public void cancelAll();
+    method public static android.support.v4.app.NotificationManagerCompat from(android.content.Context);
+    method public static java.util.Set<java.lang.String> getEnabledListenerPackages(android.content.Context);
+    method public int getImportance();
+    method public void notify(int, android.app.Notification);
+    method public void notify(java.lang.String, int, android.app.Notification);
+    field public static final java.lang.String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+    field public static final java.lang.String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
+    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+  }
+
+  public final class RemoteInput extends android.support.v4.app.RemoteInputCompatBase.RemoteInput {
+    method public static void addDataResultToIntent(android.support.v4.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
+    method public static void addResultsToIntent(android.support.v4.app.RemoteInput[], android.content.Intent, android.os.Bundle);
+    method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
+    method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
+    method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.String getResultKey();
+    method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
+    field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+  }
+
+  public static final class RemoteInput.Builder {
+    ctor public RemoteInput.Builder(java.lang.String);
+    method public android.support.v4.app.RemoteInput.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.RemoteInput build();
+    method public android.os.Bundle getExtras();
+    method public android.support.v4.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
+    method public android.support.v4.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method public android.support.v4.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
+    method public android.support.v4.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
+  }
+
+   class RemoteInputCompatBase {
+  }
+
+  public static abstract class RemoteInputCompatBase.RemoteInput {
+    ctor public RemoteInputCompatBase.RemoteInput();
+    method protected abstract boolean getAllowFreeFormInput();
+    method protected abstract java.util.Set<java.lang.String> getAllowedDataTypes();
+    method protected abstract java.lang.CharSequence[] getChoices();
+    method protected abstract android.os.Bundle getExtras();
+    method protected abstract java.lang.CharSequence getLabel();
+    method protected abstract java.lang.String getResultKey();
+  }
+
+  public final class ServiceCompat {
+    method public static void stopForeground(android.app.Service, int);
+    field public static final int START_STICKY = 1; // 0x1
+    field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+    field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+  }
+
+  public final class ShareCompat {
+    method public static void configureMenuItem(android.view.MenuItem, android.support.v4.app.ShareCompat.IntentBuilder);
+    method public static void configureMenuItem(android.view.Menu, int, android.support.v4.app.ShareCompat.IntentBuilder);
+    method public static android.content.ComponentName getCallingActivity(android.app.Activity);
+    method public static java.lang.String getCallingPackage(android.app.Activity);
+    field public static final java.lang.String EXTRA_CALLING_ACTIVITY = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+    field public static final java.lang.String EXTRA_CALLING_PACKAGE = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+  }
+
+  public static class ShareCompat.IntentBuilder {
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+    method public android.content.Intent createChooserIntent();
+    method public static android.support.v4.app.ShareCompat.IntentBuilder from(android.app.Activity);
+    method public android.content.Intent getIntent();
+    method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(java.lang.CharSequence);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(int);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailBcc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailCc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailTo(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setHtmlText(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setStream(android.net.Uri);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setSubject(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setText(java.lang.CharSequence);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setType(java.lang.String);
+    method public void startChooser();
+  }
+
+  public static class ShareCompat.IntentReader {
+    method public static android.support.v4.app.ShareCompat.IntentReader from(android.app.Activity);
+    method public android.content.ComponentName getCallingActivity();
+    method public android.graphics.drawable.Drawable getCallingActivityIcon();
+    method public android.graphics.drawable.Drawable getCallingApplicationIcon();
+    method public java.lang.CharSequence getCallingApplicationLabel();
+    method public java.lang.String getCallingPackage();
+    method public java.lang.String[] getEmailBcc();
+    method public java.lang.String[] getEmailCc();
+    method public java.lang.String[] getEmailTo();
+    method public java.lang.String getHtmlText();
+    method public android.net.Uri getStream();
+    method public android.net.Uri getStream(int);
+    method public int getStreamCount();
+    method public java.lang.String getSubject();
+    method public java.lang.CharSequence getText();
+    method public java.lang.String getType();
+    method public boolean isMultipleShare();
+    method public boolean isShareIntent();
+    method public boolean isSingleShare();
+  }
+
+  public abstract class SharedElementCallback {
+    ctor public SharedElementCallback();
+    method public android.os.Parcelable onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF);
+    method public android.view.View onCreateSnapshotView(android.content.Context, android.os.Parcelable);
+    method public void onMapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
+    method public void onRejectSharedElements(java.util.List<android.view.View>);
+    method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+    method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+    method public void onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener);
+  }
+
+  public static abstract interface SharedElementCallback.OnSharedElementsReadyListener {
+    method public abstract void onSharedElementsReady();
+  }
+
+  public final class TaskStackBuilder implements java.lang.Iterable {
+    method public android.support.v4.app.TaskStackBuilder addNextIntent(android.content.Intent);
+    method public android.support.v4.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(android.app.Activity);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(java.lang.Class<?>);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+    method public static android.support.v4.app.TaskStackBuilder create(android.content.Context);
+    method public android.content.Intent editIntentAt(int);
+    method public static deprecated android.support.v4.app.TaskStackBuilder from(android.content.Context);
+    method public deprecated android.content.Intent getIntent(int);
+    method public int getIntentCount();
+    method public android.content.Intent[] getIntents();
+    method public android.app.PendingIntent getPendingIntent(int, int);
+    method public android.app.PendingIntent getPendingIntent(int, int, android.os.Bundle);
+    method public deprecated java.util.Iterator<android.content.Intent> iterator();
+    method public void startActivities();
+    method public void startActivities(android.os.Bundle);
+  }
+
+  public static abstract interface TaskStackBuilder.SupportParentable {
+    method public abstract android.content.Intent getSupportParentActivityIntent();
+  }
+
+}
+
+package android.support.v4.content {
+
+  public abstract class AsyncTaskLoader<D> extends android.support.v4.content.Loader {
+    ctor public AsyncTaskLoader(android.content.Context);
+    method public void cancelLoadInBackground();
+    method public boolean isLoadInBackgroundCanceled();
+    method public abstract D loadInBackground();
+    method public void onCanceled(D);
+    method protected D onLoadInBackground();
+    method public void setUpdateThrottle(long);
+  }
+
+  public final class ContentResolverCompat {
+    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.support.v4.os.CancellationSignal);
+  }
+
+  public class ContextCompat {
+    ctor protected ContextCompat();
+    method public static int checkSelfPermission(android.content.Context, java.lang.String);
+    method public static android.content.Context createDeviceProtectedStorageContext(android.content.Context);
+    method public static java.io.File getCodeCacheDir(android.content.Context);
+    method public static final int getColor(android.content.Context, int);
+    method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
+    method public static java.io.File getDataDir(android.content.Context);
+    method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
+    method public static java.io.File[] getExternalCacheDirs(android.content.Context);
+    method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
+    method public static final java.io.File getNoBackupFilesDir(android.content.Context);
+    method public static java.io.File[] getObbDirs(android.content.Context);
+    method public static boolean isDeviceProtectedStorage(android.content.Context);
+    method public static boolean startActivities(android.content.Context, android.content.Intent[]);
+    method public static boolean startActivities(android.content.Context, android.content.Intent[], android.os.Bundle);
+    method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle);
+  }
+
+  public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
+    ctor public CursorLoader(android.content.Context);
+    ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public void deliverResult(android.database.Cursor);
+    method public java.lang.String[] getProjection();
+    method public java.lang.String getSelection();
+    method public java.lang.String[] getSelectionArgs();
+    method public java.lang.String getSortOrder();
+    method public android.net.Uri getUri();
+    method public android.database.Cursor loadInBackground();
+    method public void onCanceled(android.database.Cursor);
+    method public void setProjection(java.lang.String[]);
+    method public void setSelection(java.lang.String);
+    method public void setSelectionArgs(java.lang.String[]);
+    method public void setSortOrder(java.lang.String);
+    method public void setUri(android.net.Uri);
+  }
+
+  public class FileProvider extends android.content.ContentProvider {
+    ctor public FileProvider();
+    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public java.lang.String getType(android.net.Uri);
+    method public static android.net.Uri getUriForFile(android.content.Context, java.lang.String, java.io.File);
+    method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public boolean onCreate();
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+  }
+
+  public final class IntentCompat {
+    method public static deprecated android.content.Intent makeMainActivity(android.content.ComponentName);
+    method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
+    method public static deprecated android.content.Intent makeRestartActivityTask(android.content.ComponentName);
+    field public static final deprecated java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
+    field public static final deprecated java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+    field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+    field public static final deprecated java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
+    field public static final deprecated java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final deprecated int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
+    field public static final deprecated int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
+  }
+
+  public class Loader<D> {
+    ctor public Loader(android.content.Context);
+    method public void abandon();
+    method public boolean cancelLoad();
+    method public void commitContentChanged();
+    method public java.lang.String dataToString(D);
+    method public void deliverCancellation();
+    method public void deliverResult(D);
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void forceLoad();
+    method public android.content.Context getContext();
+    method public int getId();
+    method public boolean isAbandoned();
+    method public boolean isReset();
+    method public boolean isStarted();
+    method protected void onAbandon();
+    method protected boolean onCancelLoad();
+    method public void onContentChanged();
+    method protected void onForceLoad();
+    method protected void onReset();
+    method protected void onStartLoading();
+    method protected void onStopLoading();
+    method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+    method public void reset();
+    method public void rollbackContentChanged();
+    method public final void startLoading();
+    method public void stopLoading();
+    method public boolean takeContentChanged();
+    method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+  }
+
+  public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+    ctor public Loader.ForceLoadContentObserver();
+  }
+
+  public static abstract interface Loader.OnLoadCanceledListener<D> {
+    method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
+  }
+
+  public static abstract interface Loader.OnLoadCompleteListener<D> {
+    method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
+  }
+
+  public final class LocalBroadcastManager {
+    method public static android.support.v4.content.LocalBroadcastManager getInstance(android.content.Context);
+    method public void registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
+    method public boolean sendBroadcast(android.content.Intent);
+    method public void sendBroadcastSync(android.content.Intent);
+    method public void unregisterReceiver(android.content.BroadcastReceiver);
+  }
+
+  public final class MimeTypeFilter {
+    method public static boolean matches(java.lang.String, java.lang.String);
+    method public static java.lang.String matches(java.lang.String, java.lang.String[]);
+    method public static java.lang.String matches(java.lang.String[], java.lang.String);
+    method public static java.lang.String[] matchesMany(java.lang.String[], java.lang.String);
+  }
+
+  public final deprecated class ParallelExecutorCompat {
+    method public static deprecated java.util.concurrent.Executor getParallelExecutor();
+  }
+
+  public final class PermissionChecker {
+    method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
+    method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
+    method public static int checkPermission(android.content.Context, java.lang.String, int, int, java.lang.String);
+    method public static int checkSelfPermission(android.content.Context, java.lang.String);
+    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+    field public static final int PERMISSION_GRANTED = 0; // 0x0
+  }
+
+  public static abstract class PermissionChecker.PermissionResult implements java.lang.annotation.Annotation {
+  }
+
+  public final class SharedPreferencesCompat {
+  }
+
+  public static final class SharedPreferencesCompat.EditorCompat {
+    method public void apply(android.content.SharedPreferences.Editor);
+    method public static android.support.v4.content.SharedPreferencesCompat.EditorCompat getInstance();
+  }
+
+  public abstract class WakefulBroadcastReceiver extends android.content.BroadcastReceiver {
+    ctor public WakefulBroadcastReceiver();
+    method public static boolean completeWakefulIntent(android.content.Intent);
+    method public static android.content.ComponentName startWakefulService(android.content.Context, android.content.Intent);
+  }
+
+}
+
+package android.support.v4.content.pm {
+
+  public final class ActivityInfoCompat {
+    field public static final int CONFIG_UI_MODE = 512; // 0x200
+  }
+
+  public class ShortcutInfoCompat {
+  }
+
+  public static class ShortcutInfoCompat.Builder {
+    ctor public ShortcutInfoCompat.Builder(android.content.Context, java.lang.String);
+    method public android.support.v4.content.pm.ShortcutInfoCompat build();
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(java.lang.CharSequence);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIcon(android.graphics.Bitmap);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIcon(int);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent[]);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setLongLabel(java.lang.CharSequence);
+    method public android.support.v4.content.pm.ShortcutInfoCompat.Builder setShortLabel(java.lang.CharSequence);
+  }
+
+  public class ShortcutManagerCompat {
+    ctor public ShortcutManagerCompat();
+    method public static android.content.Intent createShortcutResultIntent(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat);
+    method public static boolean isRequestPinShortcutSupported(android.content.Context);
+    method public static boolean requestPinShortcut(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat, android.content.IntentSender);
+  }
+
+}
+
+package android.support.v4.content.res {
+
+  public final class ConfigurationHelper {
+    method public static int getDensityDpi(android.content.res.Resources);
+    method public static deprecated int getScreenHeightDp(android.content.res.Resources);
+    method public static deprecated int getScreenWidthDp(android.content.res.Resources);
+    method public static deprecated int getSmallestScreenWidthDp(android.content.res.Resources);
+  }
+
+  public final class ResourcesCompat {
+    method public static int getColor(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.content.res.ColorStateList getColorStateList(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable getDrawable(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable getDrawableForDensity(android.content.res.Resources, int, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+  }
+
+}
+
+package android.support.v4.database {
+
+  public final class DatabaseUtilsCompat {
+    method public static java.lang.String[] appendSelectionArgs(java.lang.String[], java.lang.String[]);
+    method public static java.lang.String concatenateWhere(java.lang.String, java.lang.String);
+  }
+
+}
+
+package android.support.v4.graphics {
+
+  public final class BitmapCompat {
+    method public static int getAllocationByteCount(android.graphics.Bitmap);
+    method public static boolean hasMipMap(android.graphics.Bitmap);
+    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+  }
+
+  public final class ColorUtils {
+    method public static int HSLToColor(float[]);
+    method public static int LABToColor(double, double, double);
+    method public static void LABToXYZ(double, double, double, double[]);
+    method public static void RGBToHSL(int, int, int, float[]);
+    method public static void RGBToLAB(int, int, int, double[]);
+    method public static void RGBToXYZ(int, int, int, double[]);
+    method public static int XYZToColor(double, double, double);
+    method public static void XYZToLAB(double, double, double, double[]);
+    method public static int blendARGB(int, int, float);
+    method public static void blendHSL(float[], float[], float, float[]);
+    method public static void blendLAB(double[], double[], double, double[]);
+    method public static double calculateContrast(int, int);
+    method public static double calculateLuminance(int);
+    method public static int calculateMinimumAlpha(int, int, float);
+    method public static void colorToHSL(int, float[]);
+    method public static void colorToLAB(int, double[]);
+    method public static void colorToXYZ(int, double[]);
+    method public static int compositeColors(int, int);
+    method public static double distanceEuclidean(double[], double[]);
+    method public static int setAlphaComponent(int, int);
+  }
+
+  public final class PaintCompat {
+    method public static boolean hasGlyph(android.graphics.Paint, java.lang.String);
+  }
+
+}
+
+package android.support.v4.graphics.drawable {
+
+  public final class DrawableCompat {
+    method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+    method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+    method public static void clearColorFilter(android.graphics.drawable.Drawable);
+    method public static int getAlpha(android.graphics.drawable.Drawable);
+    method public static android.graphics.ColorFilter getColorFilter(android.graphics.drawable.Drawable);
+    method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+    method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+    method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+    method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+    method public static void setTint(android.graphics.drawable.Drawable, int);
+    method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static <T extends android.graphics.drawable.Drawable> T unwrap(android.graphics.drawable.Drawable);
+    method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+  }
+
+  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+    method public void draw(android.graphics.Canvas);
+    method public final android.graphics.Bitmap getBitmap();
+    method public float getCornerRadius();
+    method public int getGravity();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public boolean hasAntiAlias();
+    method public boolean hasMipMap();
+    method public boolean isCircular();
+    method public void setAlpha(int);
+    method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setCornerRadius(float);
+    method public void setGravity(int);
+    method public void setMipMap(boolean);
+    method public void setTargetDensity(android.graphics.Canvas);
+    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(int);
+  }
+
+  public final class RoundedBitmapDrawableFactory {
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap);
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.lang.String);
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+  }
+
+}
+
+package android.support.v4.hardware.display {
+
+  public abstract class DisplayManagerCompat {
+    method public abstract android.view.Display getDisplay(int);
+    method public abstract android.view.Display[] getDisplays();
+    method public abstract android.view.Display[] getDisplays(java.lang.String);
+    method public static android.support.v4.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+    field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+  }
+
+}
+
+package android.support.v4.hardware.fingerprint {
+
+  public final class FingerprintManagerCompat {
+    method public void authenticate(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject, int, android.support.v4.os.CancellationSignal, android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler);
+    method public static android.support.v4.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+    method public boolean hasEnrolledFingerprints();
+    method public boolean isHardwareDetected();
+  }
+
+  public static abstract class FingerprintManagerCompat.AuthenticationCallback {
+    ctor public FingerprintManagerCompat.AuthenticationCallback();
+    method public void onAuthenticationError(int, java.lang.CharSequence);
+    method public void onAuthenticationFailed();
+    method public void onAuthenticationHelp(int, java.lang.CharSequence);
+    method public void onAuthenticationSucceeded(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult);
+  }
+
+  public static final class FingerprintManagerCompat.AuthenticationResult {
+    ctor public FingerprintManagerCompat.AuthenticationResult(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject);
+    method public android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject getCryptoObject();
+  }
+
+  public static class FingerprintManagerCompat.CryptoObject {
+    ctor public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+    ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+    ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+    method public javax.crypto.Cipher getCipher();
+    method public javax.crypto.Mac getMac();
+    method public java.security.Signature getSignature();
+  }
+
+}
+
+package android.support.v4.math {
+
+  public class MathUtils {
+    ctor public MathUtils();
+    method public static float clamp(float, int, int);
+    method public static double clamp(double, double, double);
+    method public static int clamp(int, int, int);
+  }
+
+}
+
+package android.support.v4.media {
+
+  public final class MediaBrowserCompat {
+    ctor public MediaBrowserCompat(android.content.Context, android.content.ComponentName, android.support.v4.media.MediaBrowserCompat.ConnectionCallback, android.os.Bundle);
+    method public void connect();
+    method public void disconnect();
+    method public android.os.Bundle getExtras();
+    method public void getItem(java.lang.String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+    method public java.lang.String getRoot();
+    method public android.content.ComponentName getServiceComponent();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isConnected();
+    method public void subscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void subscribe(java.lang.String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void unsubscribe(java.lang.String);
+    method public void unsubscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+    field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+  }
+
+  public static class MediaBrowserCompat.ConnectionCallback {
+    ctor public MediaBrowserCompat.ConnectionCallback();
+    method public void onConnected();
+    method public void onConnectionFailed();
+    method public void onConnectionSuspended();
+  }
+
+  public static abstract class MediaBrowserCompat.ItemCallback {
+    ctor public MediaBrowserCompat.ItemCallback();
+    method public void onError(java.lang.String);
+    method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem);
+  }
+
+  public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+    ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaBrowserCompat.MediaItem fromMediaItem(java.lang.Object);
+    method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem> fromMediaItemList(java.util.List<?>);
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public int getFlags();
+    method public java.lang.String getMediaId();
+    method public boolean isBrowsable();
+    method public boolean isPlayable();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem> CREATOR;
+    field public static final int FLAG_BROWSABLE = 1; // 0x1
+    field public static final int FLAG_PLAYABLE = 2; // 0x2
+  }
+
+  public static abstract class MediaBrowserCompat.SubscriptionCallback {
+    ctor public MediaBrowserCompat.SubscriptionCallback();
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>, android.os.Bundle);
+    method public void onError(java.lang.String);
+    method public void onError(java.lang.String, android.os.Bundle);
+  }
+
+  public abstract class MediaBrowserServiceCompat extends android.app.Service {
+    ctor public MediaBrowserServiceCompat();
+    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final android.os.Bundle getBrowserRootHints();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public void notifyChildrenChanged(java.lang.String);
+    method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
+    method public abstract void onLoadChildren(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>);
+    method public void onLoadChildren(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>, android.os.Bundle);
+    method public void onLoadItem(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+    method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+  }
+
+  public static final class MediaBrowserServiceCompat.BrowserRoot {
+    ctor public MediaBrowserServiceCompat.BrowserRoot(java.lang.String, android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getRootId();
+    field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+    field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
+    field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+    field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
+  }
+
+  public static class MediaBrowserServiceCompat.Result<T> {
+    method public void detach();
+    method public void sendResult(T);
+  }
+
+  public final class MediaDescriptionCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.MediaDescriptionCompat fromMediaDescription(java.lang.Object);
+    method public java.lang.CharSequence getDescription();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.Bitmap getIconBitmap();
+    method public android.net.Uri getIconUri();
+    method public java.lang.Object getMediaDescription();
+    method public java.lang.String getMediaId();
+    method public android.net.Uri getMediaUri();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat> CREATOR;
+    field public static final java.lang.String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+  }
+
+  public static final class MediaDescriptionCompat.Builder {
+    ctor public MediaDescriptionCompat.Builder();
+    method public android.support.v4.media.MediaDescriptionCompat build();
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setDescription(java.lang.CharSequence);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconBitmap(android.graphics.Bitmap);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconUri(android.net.Uri);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaId(java.lang.String);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaUri(android.net.Uri);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setSubtitle(java.lang.CharSequence);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setTitle(java.lang.CharSequence);
+  }
+
+  public final class MediaMetadataCompat implements android.os.Parcelable {
+    method public boolean containsKey(java.lang.String);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaMetadataCompat fromMediaMetadata(java.lang.Object);
+    method public android.graphics.Bitmap getBitmap(java.lang.String);
+    method public android.os.Bundle getBundle();
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public long getLong(java.lang.String);
+    method public java.lang.Object getMediaMetadata();
+    method public android.support.v4.media.RatingCompat getRating(java.lang.String);
+    method public java.lang.String getString(java.lang.String);
+    method public java.lang.CharSequence getText(java.lang.String);
+    method public java.util.Set<java.lang.String> keySet();
+    method public int size();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat> CREATOR;
+    field public static final java.lang.String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final java.lang.String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public static final class MediaMetadataCompat.Builder {
+    ctor public MediaMetadataCompat.Builder();
+    ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat);
+    method public android.support.v4.media.MediaMetadataCompat build();
+    method public android.support.v4.media.MediaMetadataCompat.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putLong(java.lang.String, long);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putRating(java.lang.String, android.support.v4.media.RatingCompat);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putString(java.lang.String, java.lang.String);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putText(java.lang.String, java.lang.CharSequence);
+  }
+
+  public final class RatingCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.RatingCompat fromRating(java.lang.Object);
+    method public float getPercentRating();
+    method public java.lang.Object getRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.support.v4.media.RatingCompat newHeartRating(boolean);
+    method public static android.support.v4.media.RatingCompat newPercentageRating(float);
+    method public static android.support.v4.media.RatingCompat newStarRating(int, float);
+    method public static android.support.v4.media.RatingCompat newThumbRating(boolean);
+    method public static android.support.v4.media.RatingCompat newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat> CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_NONE = 0; // 0x0
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
+  public abstract class TransportController {
+    ctor public TransportController();
+    method public abstract int getBufferPercentage();
+    method public abstract long getCurrentPosition();
+    method public abstract long getDuration();
+    method public abstract int getTransportControlFlags();
+    method public abstract boolean isPlaying();
+    method public abstract void pausePlaying();
+    method public abstract void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public abstract void seekTo(long);
+    method public abstract void startPlaying();
+    method public abstract void stopPlaying();
+    method public abstract void unregisterStateListener(android.support.v4.media.TransportStateListener);
+  }
+
+  public class TransportMediator extends android.support.v4.media.TransportController {
+    ctor public TransportMediator(android.app.Activity, android.support.v4.media.TransportPerformer);
+    ctor public TransportMediator(android.view.View, android.support.v4.media.TransportPerformer);
+    method public void destroy();
+    method public boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public int getBufferPercentage();
+    method public long getCurrentPosition();
+    method public long getDuration();
+    method public java.lang.Object getRemoteControlClient();
+    method public int getTransportControlFlags();
+    method public boolean isPlaying();
+    method public void pausePlaying();
+    method public void refreshState();
+    method public void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public void seekTo(long);
+    method public void startPlaying();
+    method public void stopPlaying();
+    method public void unregisterStateListener(android.support.v4.media.TransportStateListener);
+    field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+    field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+    field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+    field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+    field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+    field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+    field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+    field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+    field public static final int KEYCODE_MEDIA_PAUSE = 127; // 0x7f
+    field public static final int KEYCODE_MEDIA_PLAY = 126; // 0x7e
+    field public static final int KEYCODE_MEDIA_RECORD = 130; // 0x82
+  }
+
+  public abstract class TransportPerformer {
+    ctor public TransportPerformer();
+    method public void onAudioFocusChange(int);
+    method public int onGetBufferPercentage();
+    method public abstract long onGetCurrentPosition();
+    method public abstract long onGetDuration();
+    method public int onGetTransportControlFlags();
+    method public abstract boolean onIsPlaying();
+    method public boolean onMediaButtonDown(int, android.view.KeyEvent);
+    method public boolean onMediaButtonUp(int, android.view.KeyEvent);
+    method public abstract void onPause();
+    method public abstract void onSeekTo(long);
+    method public abstract void onStart();
+    method public abstract void onStop();
+  }
+
+  public class TransportStateListener {
+    ctor public TransportStateListener();
+    method public void onPlayingChanged(android.support.v4.media.TransportController);
+    method public void onTransportControlsChanged(android.support.v4.media.TransportController);
+  }
+
+  public abstract class VolumeProviderCompat {
+    ctor public VolumeProviderCompat(int, int, int);
+    method public final int getCurrentVolume();
+    method public final int getMaxVolume();
+    method public final int getVolumeControl();
+    method public java.lang.Object getVolumeProvider();
+    method public void onAdjustVolume(int);
+    method public void onSetVolumeTo(int);
+    method public void setCallback(android.support.v4.media.VolumeProviderCompat.Callback);
+    method public final void setCurrentVolume(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+  }
+
+  public static abstract class VolumeProviderCompat.Callback {
+    ctor public VolumeProviderCompat.Callback();
+    method public abstract void onVolumeChanged(android.support.v4.media.VolumeProviderCompat);
+  }
+
+}
+
+package android.support.v4.media.session {
+
+  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+    ctor public MediaButtonReceiver();
+    method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, long);
+    method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long);
+    method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
+    method public void onReceive(android.content.Context, android.content.Intent);
+  }
+
+  public final class MediaControllerCompat {
+    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
+    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
+    method public void adjustVolume(int, int);
+    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+    method public android.os.Bundle getExtras();
+    method public long getFlags();
+    method public static android.support.v4.media.session.MediaControllerCompat getMediaController(android.app.Activity);
+    method public java.lang.Object getMediaController();
+    method public android.support.v4.media.MediaMetadataCompat getMetadata();
+    method public java.lang.String getPackageName();
+    method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo getPlaybackInfo();
+    method public android.support.v4.media.session.PlaybackStateCompat getPlaybackState();
+    method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> getQueue();
+    method public java.lang.CharSequence getQueueTitle();
+    method public int getRatingType();
+    method public int getRepeatMode();
+    method public android.app.PendingIntent getSessionActivity();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public android.support.v4.media.session.MediaControllerCompat.TransportControls getTransportControls();
+    method public boolean isShuffleModeEnabled();
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
+    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat);
+    method public void setVolumeTo(int, int);
+    method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+  }
+
+  public static abstract class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+    ctor public MediaControllerCompat.Callback();
+    method public void binderDied();
+    method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo);
+    method public void onExtrasChanged(android.os.Bundle);
+    method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat);
+    method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat);
+    method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+    method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onRepeatModeChanged(int);
+    method public void onSessionDestroyed();
+    method public void onSessionEvent(java.lang.String, android.os.Bundle);
+    method public void onShuffleModeChanged(boolean);
+  }
+
+  public static final class MediaControllerCompat.PlaybackInfo {
+    method public int getAudioStream();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getPlaybackType();
+    method public int getVolumeControl();
+    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+  }
+
+  public static abstract class MediaControllerCompat.TransportControls {
+    method public abstract void fastForward();
+    method public abstract void pause();
+    method public abstract void play();
+    method public abstract void playFromMediaId(java.lang.String, android.os.Bundle);
+    method public abstract void playFromSearch(java.lang.String, android.os.Bundle);
+    method public abstract void playFromUri(android.net.Uri, android.os.Bundle);
+    method public abstract void prepare();
+    method public abstract void prepareFromMediaId(java.lang.String, android.os.Bundle);
+    method public abstract void prepareFromSearch(java.lang.String, android.os.Bundle);
+    method public abstract void prepareFromUri(android.net.Uri, android.os.Bundle);
+    method public abstract void rewind();
+    method public abstract void seekTo(long);
+    method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction, android.os.Bundle);
+    method public abstract void sendCustomAction(java.lang.String, android.os.Bundle);
+    method public abstract void setRating(android.support.v4.media.RatingCompat);
+    method public abstract void setRepeatMode(int);
+    method public abstract void setShuffleModeEnabled(boolean);
+    method public abstract void skipToNext();
+    method public abstract void skipToPrevious();
+    method public abstract void skipToQueueItem(long);
+    method public abstract void stop();
+  }
+
+  public class MediaSessionCompat {
+    ctor public MediaSessionCompat(android.content.Context, java.lang.String);
+    ctor public MediaSessionCompat(android.content.Context, java.lang.String, android.content.ComponentName, android.app.PendingIntent);
+    method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+    method public static android.support.v4.media.session.MediaSessionCompat fromMediaSession(android.content.Context, java.lang.Object);
+    method public android.support.v4.media.session.MediaControllerCompat getController();
+    method public java.lang.Object getMediaSession();
+    method public java.lang.Object getRemoteControlClient();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isActive();
+    method public static deprecated android.support.v4.media.session.MediaSessionCompat obtain(android.content.Context, java.lang.Object);
+    method public void release();
+    method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+    method public void sendSessionEvent(java.lang.String, android.os.Bundle);
+    method public void setActive(boolean);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback, android.os.Handler);
+    method public void setExtras(android.os.Bundle);
+    method public void setFlags(int);
+    method public void setMediaButtonReceiver(android.app.PendingIntent);
+    method public void setMetadata(android.support.v4.media.MediaMetadataCompat);
+    method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat);
+    method public void setPlaybackToLocal(int);
+    method public void setPlaybackToRemote(android.support.v4.media.VolumeProviderCompat);
+    method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+    method public void setQueueTitle(java.lang.CharSequence);
+    method public void setRatingType(int);
+    method public void setRepeatMode(int);
+    method public void setSessionActivity(android.app.PendingIntent);
+    method public void setShuffleModeEnabled(boolean);
+    field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+  }
+
+  public static abstract class MediaSessionCompat.Callback {
+    ctor public MediaSessionCompat.Callback();
+    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void onCustomAction(java.lang.String, android.os.Bundle);
+    method public void onFastForward();
+    method public boolean onMediaButtonEvent(android.content.Intent);
+    method public void onPause();
+    method public void onPlay();
+    method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
+    method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+    method public void onPrepare();
+    method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
+    method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+    method public void onRewind();
+    method public void onSeekTo(long);
+    method public void onSetRating(android.support.v4.media.RatingCompat);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleModeEnabled(boolean);
+    method public void onSkipToNext();
+    method public void onSkipToPrevious();
+    method public void onSkipToQueueItem(long);
+    method public void onStop();
+  }
+
+  public static abstract interface MediaSessionCompat.OnActiveChangeListener {
+    method public abstract void onActiveChanged();
+  }
+
+  public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+    ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat, long);
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.QueueItem fromQueueItem(java.lang.Object);
+    method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> fromQueueItemList(java.util.List<?>);
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public long getQueueId();
+    method public java.lang.Object getQueueItem();
+    method public static deprecated android.support.v4.media.session.MediaSessionCompat.QueueItem obtain(java.lang.Object);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem> CREATOR;
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
+  }
+
+  public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.Token fromToken(java.lang.Object);
+    method public java.lang.Object getToken();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token> CREATOR;
+  }
+
+  public class ParcelableVolumeInfo implements android.os.Parcelable {
+    ctor public ParcelableVolumeInfo(int, int, int, int, int);
+    ctor public ParcelableVolumeInfo(android.os.Parcel);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo> CREATOR;
+    field public int audioStream;
+    field public int controlType;
+    field public int currentVolume;
+    field public int maxVolume;
+    field public int volumeType;
+  }
+
+  public final class PlaybackStateCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat fromPlaybackState(java.lang.Object);
+    method public long getActions();
+    method public long getActiveQueueItemId();
+    method public long getBufferedPosition();
+    method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction> getCustomActions();
+    method public int getErrorCode();
+    method public java.lang.CharSequence getErrorMessage();
+    method public android.os.Bundle getExtras();
+    method public long getLastPositionUpdateTime();
+    method public float getPlaybackSpeed();
+    method public java.lang.Object getPlaybackState();
+    method public long getPosition();
+    method public int getState();
+    method public static int toKeyCode(long);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+    field public static final long ACTION_PAUSE = 2L; // 0x2L
+    field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+    field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+    field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+    field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+    field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+    field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
+    field public static final long ACTION_REWIND = 8L; // 0x8L
+    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
+    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+    field public static final long ACTION_STOP = 1L; // 0x1L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat> CREATOR;
+    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
+    field public static final int STATE_BUFFERING = 6; // 0x6
+    field public static final int STATE_CONNECTING = 8; // 0x8
+    field public static final int STATE_ERROR = 7; // 0x7
+    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_PAUSED = 2; // 0x2
+    field public static final int STATE_PLAYING = 3; // 0x3
+    field public static final int STATE_REWINDING = 5; // 0x5
+    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  public static final class PlaybackStateCompat.Builder {
+    ctor public PlaybackStateCompat.Builder();
+    ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(java.lang.String, java.lang.String, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction);
+    method public android.support.v4.media.session.PlaybackStateCompat build();
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActions(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActiveQueueItemId(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setBufferedPosition(long);
+    method public deprecated android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(java.lang.CharSequence);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(int, java.lang.CharSequence);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float, long);
+  }
+
+  public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction fromCustomAction(java.lang.Object);
+    method public java.lang.String getAction();
+    method public java.lang.Object getCustomAction();
+    method public android.os.Bundle getExtras();
+    method public int getIcon();
+    method public java.lang.CharSequence getName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction> CREATOR;
+  }
+
+  public static final class PlaybackStateCompat.CustomAction.Builder {
+    ctor public PlaybackStateCompat.CustomAction.Builder(java.lang.String, java.lang.CharSequence, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction build();
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder setExtras(android.os.Bundle);
+  }
+
+}
+
+package android.support.v4.net {
+
+  public final class ConnectivityManagerCompat {
+    method public static android.net.NetworkInfo getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+    method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+    method public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+  }
+
+  public final class TrafficStatsCompat {
+    method public static deprecated void clearThreadStatsTag();
+    method public static deprecated int getThreadStatsTag();
+    method public static deprecated void incrementOperationCount(int);
+    method public static deprecated void incrementOperationCount(int, int);
+    method public static deprecated void setThreadStatsTag(int);
+    method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method public static deprecated void tagSocket(java.net.Socket) throws java.net.SocketException;
+    method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method public static deprecated void untagSocket(java.net.Socket) throws java.net.SocketException;
+  }
+
+}
+
+package android.support.v4.os {
+
+  public final deprecated class AsyncTaskCompat {
+    method public static deprecated <Params, Progress, Result> android.os.AsyncTask<Params, Progress, Result> executeParallel(android.os.AsyncTask<Params, Progress, Result>, Params...);
+  }
+
+  public class BuildCompat {
+    method public static boolean isAtLeastN();
+    method public static boolean isAtLeastNMR1();
+    method public static boolean isAtLeastO();
+  }
+
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
+    method public void cancel();
+    method public java.lang.Object getCancellationSignalObject();
+    method public boolean isCanceled();
+    method public void setOnCancelListener(android.support.v4.os.CancellationSignal.OnCancelListener);
+    method public void throwIfCanceled();
+  }
+
+  public static abstract interface CancellationSignal.OnCancelListener {
+    method public abstract void onCancel();
+  }
+
+  public final class EnvironmentCompat {
+    method public static java.lang.String getStorageState(java.io.File);
+    field public static final java.lang.String MEDIA_UNKNOWN = "unknown";
+  }
+
+  public class OperationCanceledException extends java.lang.RuntimeException {
+    ctor public OperationCanceledException();
+    ctor public OperationCanceledException(java.lang.String);
+  }
+
+  public final class ParcelableCompat {
+    method public static <T> android.os.Parcelable.Creator<T> newCreator(android.support.v4.os.ParcelableCompatCreatorCallbacks<T>);
+  }
+
+  public abstract interface ParcelableCompatCreatorCallbacks<T> {
+    method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
+    method public abstract T[] newArray(int);
+  }
+
+  public final class TraceCompat {
+    method public static void beginSection(java.lang.String);
+    method public static void endSection();
+  }
+
+  public class UserManagerCompat {
+    method public static boolean isUserUnlocked(android.content.Context);
+  }
+
+}
+
+package android.support.v4.print {
+
+  public final class PrintHelper {
+    ctor public PrintHelper(android.content.Context);
+    method public int getColorMode();
+    method public int getOrientation();
+    method public int getScaleMode();
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap);
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap, android.support.v4.print.PrintHelper.OnPrintFinishCallback);
+    method public void printBitmap(java.lang.String, android.net.Uri) throws java.io.FileNotFoundException;
+    method public void printBitmap(java.lang.String, android.net.Uri, android.support.v4.print.PrintHelper.OnPrintFinishCallback) throws java.io.FileNotFoundException;
+    method public void setColorMode(int);
+    method public void setOrientation(int);
+    method public void setScaleMode(int);
+    method public static boolean systemSupportsPrint();
+    field public static final int COLOR_MODE_COLOR = 2; // 0x2
+    field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
+    field public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
+    field public static final int ORIENTATION_PORTRAIT = 2; // 0x2
+    field public static final int SCALE_MODE_FILL = 2; // 0x2
+    field public static final int SCALE_MODE_FIT = 1; // 0x1
+  }
+
+  public static abstract interface PrintHelper.OnPrintFinishCallback {
+    method public abstract void onFinish();
+  }
+
+}
+
+package android.support.v4.provider {
+
+  public abstract class DocumentFile {
+    method public abstract boolean canRead();
+    method public abstract boolean canWrite();
+    method public abstract android.support.v4.provider.DocumentFile createDirectory(java.lang.String);
+    method public abstract android.support.v4.provider.DocumentFile createFile(java.lang.String, java.lang.String);
+    method public abstract boolean delete();
+    method public abstract boolean exists();
+    method public android.support.v4.provider.DocumentFile findFile(java.lang.String);
+    method public static android.support.v4.provider.DocumentFile fromFile(java.io.File);
+    method public static android.support.v4.provider.DocumentFile fromSingleUri(android.content.Context, android.net.Uri);
+    method public static android.support.v4.provider.DocumentFile fromTreeUri(android.content.Context, android.net.Uri);
+    method public abstract java.lang.String getName();
+    method public android.support.v4.provider.DocumentFile getParentFile();
+    method public abstract java.lang.String getType();
+    method public abstract android.net.Uri getUri();
+    method public abstract boolean isDirectory();
+    method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public abstract boolean isFile();
+    method public abstract boolean isVirtual();
+    method public abstract long lastModified();
+    method public abstract long length();
+    method public abstract android.support.v4.provider.DocumentFile[] listFiles();
+    method public abstract boolean renameTo(java.lang.String);
+  }
+
+}
+
+package android.support.v4.text {
+
+  public final class BidiFormatter {
+    method public static android.support.v4.text.BidiFormatter getInstance();
+    method public static android.support.v4.text.BidiFormatter getInstance(boolean);
+    method public static android.support.v4.text.BidiFormatter getInstance(java.util.Locale);
+    method public boolean getStereoReset();
+    method public boolean isRtl(java.lang.String);
+    method public boolean isRtl(java.lang.CharSequence);
+    method public boolean isRtlContext();
+    method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat, boolean);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, android.support.v4.text.TextDirectionHeuristicCompat, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, android.support.v4.text.TextDirectionHeuristicCompat);
+    method public java.lang.String unicodeWrap(java.lang.String, boolean);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String);
+    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale);
+    method public android.support.v4.text.BidiFormatter build();
+    method public android.support.v4.text.BidiFormatter.Builder setTextDirectionHeuristic(android.support.v4.text.TextDirectionHeuristicCompat);
+    method public android.support.v4.text.BidiFormatter.Builder stereoReset(boolean);
+  }
+
+  public final class ICUCompat {
+    method public static java.lang.String maximizeAndGetScript(java.util.Locale);
+  }
+
+  public abstract interface TextDirectionHeuristicCompat {
+    method public abstract boolean isRtl(char[], int, int);
+    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+  }
+
+  public final class TextDirectionHeuristicsCompat {
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat ANYRTL_LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_RTL;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat LOCALE;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat RTL;
+  }
+
+  public final class TextUtilsCompat {
+    method public static int getLayoutDirectionFromLocale(java.util.Locale);
+    method public static java.lang.String htmlEncode(java.lang.String);
+    field public static final java.util.Locale ROOT;
+  }
+
+}
+
+package android.support.v4.text.util {
+
+  public final class LinkifyCompat {
+    method public static final boolean addLinks(android.text.Spannable, int);
+    method public static final boolean addLinks(android.widget.TextView, int);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+  }
+
+  public static abstract class LinkifyCompat.LinkifyMask implements java.lang.annotation.Annotation {
+  }
+
+}
+
+package android.support.v4.util {
+
+  public class ArrayMap<K, V> extends android.support.v4.util.SimpleArrayMap implements java.util.Map {
+    ctor public ArrayMap();
+    ctor public ArrayMap(int);
+    ctor public ArrayMap(android.support.v4.util.SimpleArrayMap);
+    method public boolean containsAll(java.util.Collection<?>);
+    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public java.util.Set<K> keySet();
+    method public void putAll(java.util.Map<? extends K, ? extends V>);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public java.util.Collection<V> values();
+  }
+
+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
+    ctor public ArraySet();
+    ctor public ArraySet(int);
+    ctor public ArraySet(android.support.v4.util.ArraySet<E>);
+    method public boolean add(E);
+    method public void addAll(android.support.v4.util.ArraySet<? extends E>);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public void clear();
+    method public boolean contains(java.lang.Object);
+    method public boolean containsAll(java.util.Collection<?>);
+    method public void ensureCapacity(int);
+    method public int indexOf(java.lang.Object);
+    method public boolean isEmpty();
+    method public java.util.Iterator<E> iterator();
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(android.support.v4.util.ArraySet<? extends E>);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public E removeAt(int);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public int size();
+    method public java.lang.Object[] toArray();
+    method public <T> T[] toArray(T[]);
+    method public E valueAt(int);
+  }
+
+  public class AtomicFile {
+    ctor public AtomicFile(java.io.File);
+    method public void delete();
+    method public void failWrite(java.io.FileOutputStream);
+    method public void finishWrite(java.io.FileOutputStream);
+    method public java.io.File getBaseFile();
+    method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+    method public byte[] readFully() throws java.io.IOException;
+    method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+  }
+
+  public final class CircularArray<E> {
+    ctor public CircularArray();
+    ctor public CircularArray(int);
+    method public void addFirst(E);
+    method public void addLast(E);
+    method public void clear();
+    method public E get(int);
+    method public E getFirst();
+    method public E getLast();
+    method public boolean isEmpty();
+    method public E popFirst();
+    method public E popLast();
+    method public void removeFromEnd(int);
+    method public void removeFromStart(int);
+    method public int size();
+  }
+
+  public final class CircularIntArray {
+    ctor public CircularIntArray();
+    ctor public CircularIntArray(int);
+    method public void addFirst(int);
+    method public void addLast(int);
+    method public void clear();
+    method public int get(int);
+    method public int getFirst();
+    method public int getLast();
+    method public boolean isEmpty();
+    method public int popFirst();
+    method public int popLast();
+    method public void removeFromEnd(int);
+    method public void removeFromStart(int);
+    method public int size();
+  }
+
+  public class LongSparseArray<E> {
+    ctor public LongSparseArray();
+    ctor public LongSparseArray(int);
+    method public void append(long, E);
+    method public void clear();
+    method public android.support.v4.util.LongSparseArray<E> clone();
+    method public void delete(long);
+    method public E get(long);
+    method public E get(long, E);
+    method public int indexOfKey(long);
+    method public int indexOfValue(E);
+    method public long keyAt(int);
+    method public void put(long, E);
+    method public void remove(long);
+    method public void removeAt(int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+  public class LruCache<K, V> {
+    ctor public LruCache(int);
+    method protected V create(K);
+    method public final synchronized int createCount();
+    method protected void entryRemoved(boolean, K, V, V);
+    method public final void evictAll();
+    method public final synchronized int evictionCount();
+    method public final V get(K);
+    method public final synchronized int hitCount();
+    method public final synchronized int maxSize();
+    method public final synchronized int missCount();
+    method public final V put(K, V);
+    method public final synchronized int putCount();
+    method public final V remove(K);
+    method public void resize(int);
+    method public final synchronized int size();
+    method protected int sizeOf(K, V);
+    method public final synchronized java.util.Map<K, V> snapshot();
+    method public final synchronized java.lang.String toString();
+    method public void trimToSize(int);
+  }
+
+  public class Pair<F, S> {
+    ctor public Pair(F, S);
+    method public static <A, B> android.support.v4.util.Pair<A, B> create(A, B);
+    field public final F first;
+    field public final S second;
+  }
+
+  public final class PatternsCompat {
+    field public static final java.util.regex.Pattern DOMAIN_NAME;
+    field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+    field public static final java.util.regex.Pattern IP_ADDRESS;
+    field public static final java.util.regex.Pattern WEB_URL;
+  }
+
+  public final class Pools {
+  }
+
+  public static abstract interface Pools.Pool<T> {
+    method public abstract T acquire();
+    method public abstract boolean release(T);
+  }
+
+  public static class Pools.SimplePool<T> implements android.support.v4.util.Pools.Pool {
+    ctor public Pools.SimplePool(int);
+    method public T acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SynchronizedPool<T> extends android.support.v4.util.Pools.SimplePool {
+    ctor public Pools.SynchronizedPool(int);
+  }
+
+  public class SimpleArrayMap<K, V> {
+    ctor public SimpleArrayMap();
+    ctor public SimpleArrayMap(int);
+    ctor public SimpleArrayMap(android.support.v4.util.SimpleArrayMap);
+    method public void clear();
+    method public boolean containsKey(java.lang.Object);
+    method public boolean containsValue(java.lang.Object);
+    method public void ensureCapacity(int);
+    method public V get(java.lang.Object);
+    method public int indexOfKey(java.lang.Object);
+    method public boolean isEmpty();
+    method public K keyAt(int);
+    method public V put(K, V);
+    method public void putAll(android.support.v4.util.SimpleArrayMap<? extends K, ? extends V>);
+    method public V remove(java.lang.Object);
+    method public V removeAt(int);
+    method public V setValueAt(int, V);
+    method public int size();
+    method public V valueAt(int);
+  }
+
+  public class SparseArrayCompat<E> {
+    ctor public SparseArrayCompat();
+    ctor public SparseArrayCompat(int);
+    method public void append(int, E);
+    method public void clear();
+    method public android.support.v4.util.SparseArrayCompat<E> clone();
+    method public void delete(int);
+    method public E get(int);
+    method public E get(int, E);
+    method public int indexOfKey(int);
+    method public int indexOfValue(E);
+    method public int keyAt(int);
+    method public void put(int, E);
+    method public void remove(int);
+    method public void removeAt(int);
+    method public void removeAtRange(int, int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+}
+
+package android.support.v4.view {
+
+  public abstract class AbsSavedState implements android.os.Parcelable {
+    ctor protected AbsSavedState(android.os.Parcelable);
+    ctor protected AbsSavedState(android.os.Parcel);
+    ctor protected AbsSavedState(android.os.Parcel, java.lang.ClassLoader);
+    method public int describeContents();
+    method public final android.os.Parcelable getSuperState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.view.AbsSavedState> CREATOR;
+    field public static final android.support.v4.view.AbsSavedState EMPTY_STATE;
+  }
+
+  public class AccessibilityDelegateCompat {
+    ctor public AccessibilityDelegateCompat();
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+    method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+    method public void sendAccessibilityEvent(android.view.View, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
+  public abstract class ActionProvider {
+    ctor public ActionProvider(android.content.Context);
+    method public android.content.Context getContext();
+    method public boolean hasSubMenu();
+    method public boolean isVisible();
+    method public abstract android.view.View onCreateActionView();
+    method public android.view.View onCreateActionView(android.view.MenuItem);
+    method public boolean onPerformDefaultAction();
+    method public void onPrepareSubMenu(android.view.SubMenu);
+    method public boolean overridesItemVisibility();
+    method public void refreshVisibility();
+    method public void setVisibilityListener(android.support.v4.view.ActionProvider.VisibilityListener);
+  }
+
+  public static abstract interface ActionProvider.VisibilityListener {
+    method public abstract void onActionProviderVisibilityChanged(boolean);
+  }
+
+  public final class AsyncLayoutInflater {
+    ctor public AsyncLayoutInflater(android.content.Context);
+    method public void inflate(int, android.view.ViewGroup, android.support.v4.view.AsyncLayoutInflater.OnInflateFinishedListener);
+  }
+
+  public static abstract interface AsyncLayoutInflater.OnInflateFinishedListener {
+    method public abstract void onInflateFinished(android.view.View, int, android.view.ViewGroup);
+  }
+
+  public final class GestureDetectorCompat {
+    ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+    ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler);
+    method public boolean isLongpressEnabled();
+    method public boolean onTouchEvent(android.view.MotionEvent);
+    method public void setIsLongpressEnabled(boolean);
+    method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
+  }
+
+  public final class GravityCompat {
+    method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+    method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+    method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+    method public static int getAbsoluteGravity(int, int);
+    field public static final int END = 8388613; // 0x800005
+    field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+    field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+    field public static final int START = 8388611; // 0x800003
+  }
+
+  public final class InputDeviceCompat {
+    field public static final int SOURCE_ANY = -256; // 0xffffff00
+    field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+    field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+    field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+    field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+    field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+    field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+    field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+    field public static final int SOURCE_DPAD = 513; // 0x201
+    field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+    field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+    field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+    field public static final int SOURCE_KEYBOARD = 257; // 0x101
+    field public static final int SOURCE_MOUSE = 8194; // 0x2002
+    field public static final int SOURCE_STYLUS = 16386; // 0x4002
+    field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+    field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+    field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+    field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+    field public static final int SOURCE_UNKNOWN = 0; // 0x0
+  }
+
+  public final deprecated class KeyEventCompat {
+    method public static deprecated boolean dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object);
+    method public static deprecated java.lang.Object getKeyDispatcherState(android.view.View);
+    method public static deprecated boolean hasModifiers(android.view.KeyEvent, int);
+    method public static deprecated boolean hasNoModifiers(android.view.KeyEvent);
+    method public static deprecated boolean isCtrlPressed(android.view.KeyEvent);
+    method public static deprecated boolean isTracking(android.view.KeyEvent);
+    method public static deprecated boolean metaStateHasModifiers(int, int);
+    method public static deprecated boolean metaStateHasNoModifiers(int);
+    method public static deprecated int normalizeMetaState(int);
+    method public static deprecated void startTracking(android.view.KeyEvent);
+  }
+
+  public final class LayoutInflaterCompat {
+    method public static deprecated android.support.v4.view.LayoutInflaterFactory getFactory(android.view.LayoutInflater);
+    method public static deprecated void setFactory(android.view.LayoutInflater, android.support.v4.view.LayoutInflaterFactory);
+    method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+  }
+
+  public abstract deprecated interface LayoutInflaterFactory {
+    method public abstract android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+  }
+
+  public final class MarginLayoutParamsCompat {
+    method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+    method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+    method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+    method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+    method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+  }
+
+  public final class MenuCompat {
+    method public static deprecated void setShowAsAction(android.view.MenuItem, int);
+  }
+
+  public final class MenuItemCompat {
+    method public static boolean collapseActionView(android.view.MenuItem);
+    method public static boolean expandActionView(android.view.MenuItem);
+    method public static android.support.v4.view.ActionProvider getActionProvider(android.view.MenuItem);
+    method public static android.view.View getActionView(android.view.MenuItem);
+    method public static java.lang.CharSequence getContentDescription(android.view.MenuItem);
+    method public static java.lang.CharSequence getTooltipText(android.view.MenuItem);
+    method public static boolean isActionViewExpanded(android.view.MenuItem);
+    method public static android.view.MenuItem setActionProvider(android.view.MenuItem, android.support.v4.view.ActionProvider);
+    method public static android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
+    method public static android.view.MenuItem setActionView(android.view.MenuItem, int);
+    method public static void setContentDescription(android.view.MenuItem, java.lang.CharSequence);
+    method public static android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
+    method public static void setShowAsAction(android.view.MenuItem, int);
+    method public static void setTooltipText(android.view.MenuItem, java.lang.CharSequence);
+    field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+  }
+
+  public static abstract interface MenuItemCompat.OnActionExpandListener {
+    method public abstract boolean onMenuItemActionCollapse(android.view.MenuItem);
+    method public abstract boolean onMenuItemActionExpand(android.view.MenuItem);
+  }
+
+  public final class MotionEventCompat {
+    method public static deprecated int findPointerIndex(android.view.MotionEvent, int);
+    method public static deprecated int getActionIndex(android.view.MotionEvent);
+    method public static deprecated int getActionMasked(android.view.MotionEvent);
+    method public static deprecated float getAxisValue(android.view.MotionEvent, int);
+    method public static deprecated float getAxisValue(android.view.MotionEvent, int, int);
+    method public static deprecated int getButtonState(android.view.MotionEvent);
+    method public static deprecated int getPointerCount(android.view.MotionEvent);
+    method public static deprecated int getPointerId(android.view.MotionEvent, int);
+    method public static deprecated int getSource(android.view.MotionEvent);
+    method public static deprecated float getX(android.view.MotionEvent, int);
+    method public static deprecated float getY(android.view.MotionEvent, int);
+    method public static boolean isFromSource(android.view.MotionEvent, int);
+    field public static final deprecated int ACTION_HOVER_ENTER = 9; // 0x9
+    field public static final deprecated int ACTION_HOVER_EXIT = 10; // 0xa
+    field public static final deprecated int ACTION_HOVER_MOVE = 7; // 0x7
+    field public static final deprecated int ACTION_MASK = 255; // 0xff
+    field public static final deprecated int ACTION_POINTER_DOWN = 5; // 0x5
+    field public static final deprecated int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+    field public static final deprecated int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+    field public static final deprecated int ACTION_POINTER_UP = 6; // 0x6
+    field public static final deprecated int ACTION_SCROLL = 8; // 0x8
+    field public static final deprecated int AXIS_BRAKE = 23; // 0x17
+    field public static final deprecated int AXIS_DISTANCE = 24; // 0x18
+    field public static final deprecated int AXIS_GAS = 22; // 0x16
+    field public static final deprecated int AXIS_GENERIC_1 = 32; // 0x20
+    field public static final deprecated int AXIS_GENERIC_10 = 41; // 0x29
+    field public static final deprecated int AXIS_GENERIC_11 = 42; // 0x2a
+    field public static final deprecated int AXIS_GENERIC_12 = 43; // 0x2b
+    field public static final deprecated int AXIS_GENERIC_13 = 44; // 0x2c
+    field public static final deprecated int AXIS_GENERIC_14 = 45; // 0x2d
+    field public static final deprecated int AXIS_GENERIC_15 = 46; // 0x2e
+    field public static final deprecated int AXIS_GENERIC_16 = 47; // 0x2f
+    field public static final deprecated int AXIS_GENERIC_2 = 33; // 0x21
+    field public static final deprecated int AXIS_GENERIC_3 = 34; // 0x22
+    field public static final deprecated int AXIS_GENERIC_4 = 35; // 0x23
+    field public static final deprecated int AXIS_GENERIC_5 = 36; // 0x24
+    field public static final deprecated int AXIS_GENERIC_6 = 37; // 0x25
+    field public static final deprecated int AXIS_GENERIC_7 = 38; // 0x26
+    field public static final deprecated int AXIS_GENERIC_8 = 39; // 0x27
+    field public static final deprecated int AXIS_GENERIC_9 = 40; // 0x28
+    field public static final deprecated int AXIS_HAT_X = 15; // 0xf
+    field public static final deprecated int AXIS_HAT_Y = 16; // 0x10
+    field public static final deprecated int AXIS_HSCROLL = 10; // 0xa
+    field public static final deprecated int AXIS_LTRIGGER = 17; // 0x11
+    field public static final deprecated int AXIS_ORIENTATION = 8; // 0x8
+    field public static final deprecated int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+    field public static final deprecated int AXIS_RTRIGGER = 18; // 0x12
+    field public static final deprecated int AXIS_RUDDER = 20; // 0x14
+    field public static final deprecated int AXIS_RX = 12; // 0xc
+    field public static final deprecated int AXIS_RY = 13; // 0xd
+    field public static final deprecated int AXIS_RZ = 14; // 0xe
+    field public static final deprecated int AXIS_SIZE = 3; // 0x3
+    field public static final deprecated int AXIS_THROTTLE = 19; // 0x13
+    field public static final deprecated int AXIS_TILT = 25; // 0x19
+    field public static final deprecated int AXIS_TOOL_MAJOR = 6; // 0x6
+    field public static final deprecated int AXIS_TOOL_MINOR = 7; // 0x7
+    field public static final deprecated int AXIS_TOUCH_MAJOR = 4; // 0x4
+    field public static final deprecated int AXIS_TOUCH_MINOR = 5; // 0x5
+    field public static final deprecated int AXIS_VSCROLL = 9; // 0x9
+    field public static final deprecated int AXIS_WHEEL = 21; // 0x15
+    field public static final deprecated int AXIS_X = 0; // 0x0
+    field public static final deprecated int AXIS_Y = 1; // 0x1
+    field public static final deprecated int AXIS_Z = 11; // 0xb
+    field public static final deprecated int BUTTON_PRIMARY = 1; // 0x1
+  }
+
+  public abstract interface NestedScrollingChild {
+    method public abstract boolean dispatchNestedFling(float, float, boolean);
+    method public abstract boolean dispatchNestedPreFling(float, float);
+    method public abstract boolean dispatchNestedPreScroll(int, int, int[], int[]);
+    method public abstract boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public abstract boolean hasNestedScrollingParent();
+    method public abstract boolean isNestedScrollingEnabled();
+    method public abstract void setNestedScrollingEnabled(boolean);
+    method public abstract boolean startNestedScroll(int);
+    method public abstract void stopNestedScroll();
+  }
+
+  public class NestedScrollingChildHelper {
+    ctor public NestedScrollingChildHelper(android.view.View);
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public boolean hasNestedScrollingParent();
+    method public boolean isNestedScrollingEnabled();
+    method public void onDetachedFromWindow();
+    method public void onStopNestedScroll(android.view.View);
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public void stopNestedScroll();
+  }
+
+  public abstract interface NestedScrollingParent {
+    method public abstract int getNestedScrollAxes();
+    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
+    method public abstract boolean onNestedPreFling(android.view.View, float, float);
+    method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
+    method public abstract void onNestedScroll(android.view.View, int, int, int, int);
+    method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public abstract boolean onStartNestedScroll(android.view.View, android.view.View, int);
+    method public abstract void onStopNestedScroll(android.view.View);
+  }
+
+  public class NestedScrollingParentHelper {
+    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+    method public int getNestedScrollAxes();
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.view.View);
+  }
+
+  public abstract interface OnApplyWindowInsetsListener {
+    method public abstract android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+  }
+
+  public abstract class PagerAdapter {
+    ctor public PagerAdapter();
+    method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
+    method public void finishUpdate(android.view.ViewGroup);
+    method public deprecated void finishUpdate(android.view.View);
+    method public abstract int getCount();
+    method public int getItemPosition(java.lang.Object);
+    method public java.lang.CharSequence getPageTitle(int);
+    method public float getPageWidth(int);
+    method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
+    method public deprecated java.lang.Object instantiateItem(android.view.View, int);
+    method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
+    method public void notifyDataSetChanged();
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+    method public android.os.Parcelable saveState();
+    method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
+    method public void startUpdate(android.view.ViewGroup);
+    method public deprecated void startUpdate(android.view.View);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
+    field public static final int POSITION_NONE = -2; // 0xfffffffe
+    field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
+  }
+
+  public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
+    ctor public PagerTabStrip(android.content.Context);
+    ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
+    method public boolean getDrawFullUnderline();
+    method public int getTabIndicatorColor();
+    method public void setDrawFullUnderline(boolean);
+    method public void setTabIndicatorColor(int);
+    method public void setTabIndicatorColorResource(int);
+  }
+
+  public class PagerTitleStrip extends android.view.ViewGroup {
+    ctor public PagerTitleStrip(android.content.Context);
+    ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
+    method public int getTextSpacing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setGravity(int);
+    method public void setNonPrimaryAlpha(float);
+    method public void setTextColor(int);
+    method public void setTextSize(int, float);
+    method public void setTextSpacing(int);
+  }
+
+  public final class PointerIconCompat {
+    method public static android.support.v4.view.PointerIconCompat create(android.graphics.Bitmap, float, float);
+    method public static android.support.v4.view.PointerIconCompat getSystemIcon(android.content.Context, int);
+    method public static android.support.v4.view.PointerIconCompat load(android.content.res.Resources, int);
+    field public static final int TYPE_ALIAS = 1010; // 0x3f2
+    field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int TYPE_ARROW = 1000; // 0x3e8
+    field public static final int TYPE_CELL = 1006; // 0x3ee
+    field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int TYPE_COPY = 1011; // 0x3f3
+    field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+    field public static final int TYPE_GRAB = 1020; // 0x3fc
+    field public static final int TYPE_GRABBING = 1021; // 0x3fd
+    field public static final int TYPE_HAND = 1002; // 0x3ea
+    field public static final int TYPE_HELP = 1003; // 0x3eb
+    field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+    field public static final int TYPE_NULL = 0; // 0x0
+    field public static final int TYPE_TEXT = 1008; // 0x3f0
+    field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int TYPE_WAIT = 1004; // 0x3ec
+    field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
+  public final class ScaleGestureDetectorCompat {
+    method public static boolean isQuickScaleEnabled(java.lang.Object);
+    method public static void setQuickScaleEnabled(java.lang.Object, boolean);
+  }
+
+  public abstract interface ScrollingView {
+    method public abstract int computeHorizontalScrollExtent();
+    method public abstract int computeHorizontalScrollOffset();
+    method public abstract int computeHorizontalScrollRange();
+    method public abstract int computeVerticalScrollExtent();
+    method public abstract int computeVerticalScrollOffset();
+    method public abstract int computeVerticalScrollRange();
+  }
+
+  public abstract interface TintableBackgroundView {
+    method public abstract android.content.res.ColorStateList getSupportBackgroundTintList();
+    method public abstract android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+    method public abstract void setSupportBackgroundTintList(android.content.res.ColorStateList);
+    method public abstract void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final deprecated class VelocityTrackerCompat {
+    method public static deprecated float getXVelocity(android.view.VelocityTracker, int);
+    method public static deprecated float getYVelocity(android.view.VelocityTracker, int);
+  }
+
+  public class ViewCompat {
+    ctor protected ViewCompat();
+    method public static android.support.v4.view.ViewPropertyAnimatorCompat animate(android.view.View);
+    method public static boolean canScrollHorizontally(android.view.View, int);
+    method public static boolean canScrollVertically(android.view.View, int);
+    method public static deprecated int combineMeasuredStates(int, int);
+    method public static android.support.v4.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+    method public static void dispatchFinishTemporaryDetach(android.view.View);
+    method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+    method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[], int[]);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]);
+    method public static void dispatchStartTemporaryDetach(android.view.View);
+    method public static int getAccessibilityLiveRegion(android.view.View);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+    method public static deprecated float getAlpha(android.view.View);
+    method public static android.content.res.ColorStateList getBackgroundTintList(android.view.View);
+    method public static android.graphics.PorterDuff.Mode getBackgroundTintMode(android.view.View);
+    method public static android.graphics.Rect getClipBounds(android.view.View);
+    method public static android.view.Display getDisplay(android.view.View);
+    method public static float getElevation(android.view.View);
+    method public static boolean getFitsSystemWindows(android.view.View);
+    method public static int getImportantForAccessibility(android.view.View);
+    method public static int getLabelFor(android.view.View);
+    method public static deprecated int getLayerType(android.view.View);
+    method public static int getLayoutDirection(android.view.View);
+    method public static deprecated android.graphics.Matrix getMatrix(android.view.View);
+    method public static deprecated int getMeasuredHeightAndState(android.view.View);
+    method public static deprecated int getMeasuredState(android.view.View);
+    method public static deprecated int getMeasuredWidthAndState(android.view.View);
+    method public static int getMinimumHeight(android.view.View);
+    method public static int getMinimumWidth(android.view.View);
+    method public static deprecated int getOverScrollMode(android.view.View);
+    method public static int getPaddingEnd(android.view.View);
+    method public static int getPaddingStart(android.view.View);
+    method public static android.view.ViewParent getParentForAccessibility(android.view.View);
+    method public static deprecated float getPivotX(android.view.View);
+    method public static deprecated float getPivotY(android.view.View);
+    method public static deprecated float getRotation(android.view.View);
+    method public static deprecated float getRotationX(android.view.View);
+    method public static deprecated float getRotationY(android.view.View);
+    method public static deprecated float getScaleX(android.view.View);
+    method public static deprecated float getScaleY(android.view.View);
+    method public static int getScrollIndicators(android.view.View);
+    method public static java.lang.String getTransitionName(android.view.View);
+    method public static deprecated float getTranslationX(android.view.View);
+    method public static deprecated float getTranslationY(android.view.View);
+    method public static float getTranslationZ(android.view.View);
+    method public static int getWindowSystemUiVisibility(android.view.View);
+    method public static deprecated float getX(android.view.View);
+    method public static deprecated float getY(android.view.View);
+    method public static float getZ(android.view.View);
+    method public static boolean hasAccessibilityDelegate(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View);
+    method public static boolean hasOnClickListeners(android.view.View);
+    method public static boolean hasOverlappingRendering(android.view.View);
+    method public static boolean hasTransientState(android.view.View);
+    method public static boolean isAttachedToWindow(android.view.View);
+    method public static boolean isImportantForAccessibility(android.view.View);
+    method public static boolean isInLayout(android.view.View);
+    method public static boolean isLaidOut(android.view.View);
+    method public static boolean isLayoutDirectionResolved(android.view.View);
+    method public static boolean isNestedScrollingEnabled(android.view.View);
+    method public static deprecated boolean isOpaque(android.view.View);
+    method public static boolean isPaddingRelative(android.view.View);
+    method public static deprecated void jumpDrawablesToCurrentState(android.view.View);
+    method public static void offsetLeftAndRight(android.view.View, int);
+    method public static void offsetTopAndBottom(android.view.View, int);
+    method public static android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+    method public static void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public static void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+    method public static void postInvalidateOnAnimation(android.view.View);
+    method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method public static void postOnAnimation(android.view.View, java.lang.Runnable);
+    method public static void postOnAnimationDelayed(android.view.View, java.lang.Runnable, long);
+    method public static void requestApplyInsets(android.view.View);
+    method public static deprecated int resolveSizeAndState(int, int, int);
+    method public static void setAccessibilityDelegate(android.view.View, android.support.v4.view.AccessibilityDelegateCompat);
+    method public static void setAccessibilityLiveRegion(android.view.View, int);
+    method public static deprecated void setActivated(android.view.View, boolean);
+    method public static deprecated void setAlpha(android.view.View, float);
+    method public static void setBackground(android.view.View, android.graphics.drawable.Drawable);
+    method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList);
+    method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode);
+    method public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup, boolean);
+    method public static void setClipBounds(android.view.View, android.graphics.Rect);
+    method public static void setElevation(android.view.View, float);
+    method public static void setFitsSystemWindows(android.view.View, boolean);
+    method public static void setHasTransientState(android.view.View, boolean);
+    method public static void setImportantForAccessibility(android.view.View, int);
+    method public static void setLabelFor(android.view.View, int);
+    method public static void setLayerPaint(android.view.View, android.graphics.Paint);
+    method public static deprecated void setLayerType(android.view.View, int, android.graphics.Paint);
+    method public static void setLayoutDirection(android.view.View, int);
+    method public static void setNestedScrollingEnabled(android.view.View, boolean);
+    method public static void setOnApplyWindowInsetsListener(android.view.View, android.support.v4.view.OnApplyWindowInsetsListener);
+    method public static deprecated void setOverScrollMode(android.view.View, int);
+    method public static void setPaddingRelative(android.view.View, int, int, int, int);
+    method public static deprecated void setPivotX(android.view.View, float);
+    method public static deprecated void setPivotY(android.view.View, float);
+    method public static void setPointerIcon(android.view.View, android.support.v4.view.PointerIconCompat);
+    method public static deprecated void setRotation(android.view.View, float);
+    method public static deprecated void setRotationX(android.view.View, float);
+    method public static deprecated void setRotationY(android.view.View, float);
+    method public static deprecated void setSaveFromParentEnabled(android.view.View, boolean);
+    method public static deprecated void setScaleX(android.view.View, float);
+    method public static deprecated void setScaleY(android.view.View, float);
+    method public static void setScrollIndicators(android.view.View, int);
+    method public static void setScrollIndicators(android.view.View, int, int);
+    method public static void setTooltipText(android.view.View, java.lang.CharSequence);
+    method public static void setTransitionName(android.view.View, java.lang.String);
+    method public static deprecated void setTranslationX(android.view.View, float);
+    method public static deprecated void setTranslationY(android.view.View, float);
+    method public static void setTranslationZ(android.view.View, float);
+    method public static deprecated void setX(android.view.View, float);
+    method public static deprecated void setY(android.view.View, float);
+    method public static void setZ(android.view.View, float);
+    method public static boolean startNestedScroll(android.view.View, int);
+    method public static void stopNestedScroll(android.view.View);
+    field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+    field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+    field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+    field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+    field public static final int LAYER_TYPE_NONE = 0; // 0x0
+    field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+    field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+    field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+    field public static final deprecated int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+    field public static final deprecated int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+    field public static final deprecated int MEASURED_STATE_MASK = -16777216; // 0xff000000
+    field public static final deprecated int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+    field public static final deprecated int OVER_SCROLL_ALWAYS = 0; // 0x0
+    field public static final deprecated int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+    field public static final deprecated int OVER_SCROLL_NEVER = 2; // 0x2
+    field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+    field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+    field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+    field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+    field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+    field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+    field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+  }
+
+  public final class ViewConfigurationCompat {
+    method public static deprecated int getScaledPagingTouchSlop(android.view.ViewConfiguration);
+    method public static boolean hasPermanentMenuKey(android.view.ViewConfiguration);
+  }
+
+  public final class ViewGroupCompat {
+    method public static int getLayoutMode(android.view.ViewGroup);
+    method public static int getNestedScrollAxes(android.view.ViewGroup);
+    method public static boolean isTransitionGroup(android.view.ViewGroup);
+    method public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static void setLayoutMode(android.view.ViewGroup, int);
+    method public static void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
+    method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+    field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+    field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+  }
+
+  public class ViewPager extends android.view.ViewGroup {
+    ctor public ViewPager(android.content.Context);
+    ctor public ViewPager(android.content.Context, android.util.AttributeSet);
+    method public void addOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+    method public void addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public boolean arrowScroll(int);
+    method public boolean beginFakeDrag();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public void clearOnPageChangeListeners();
+    method public void endFakeDrag();
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fakeDragBy(float);
+    method public android.support.v4.view.PagerAdapter getAdapter();
+    method public int getCurrentItem();
+    method public int getOffscreenPageLimit();
+    method public int getPageMargin();
+    method public boolean isFakeDragging();
+    method protected void onLayout(boolean, int, int, int, int);
+    method protected void onPageScrolled(int, float, int);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void removeOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+    method public void removeOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setAdapter(android.support.v4.view.PagerAdapter);
+    method public void setCurrentItem(int);
+    method public void setCurrentItem(int, boolean);
+    method public void setOffscreenPageLimit(int);
+    method public deprecated void setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setPageMargin(int);
+    method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
+    method public void setPageMarginDrawable(int);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer, int);
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class ViewPager.DecorView implements java.lang.annotation.Annotation {
+  }
+
+  public static class ViewPager.LayoutParams extends android.view.ViewGroup.LayoutParams {
+    ctor public ViewPager.LayoutParams();
+    ctor public ViewPager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public int gravity;
+    field public boolean isDecor;
+  }
+
+  public static abstract interface ViewPager.OnAdapterChangeListener {
+    method public abstract void onAdapterChanged(android.support.v4.view.ViewPager, android.support.v4.view.PagerAdapter, android.support.v4.view.PagerAdapter);
+  }
+
+  public static abstract interface ViewPager.OnPageChangeListener {
+    method public abstract void onPageScrollStateChanged(int);
+    method public abstract void onPageScrolled(int, float, int);
+    method public abstract void onPageSelected(int);
+  }
+
+  public static abstract interface ViewPager.PageTransformer {
+    method public abstract void transformPage(android.view.View, float);
+  }
+
+  public static class ViewPager.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public ViewPager.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.view.ViewPager.SavedState> CREATOR;
+  }
+
+  public static class ViewPager.SimpleOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+    ctor public ViewPager.SimpleOnPageChangeListener();
+    method public void onPageScrollStateChanged(int);
+    method public void onPageScrolled(int, float, int);
+    method public void onPageSelected(int);
+  }
+
+  public final class ViewParentCompat {
+    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+    method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+    method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+    method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+    method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+    method public static boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
+  public final class ViewPropertyAnimatorCompat {
+    method public android.support.v4.view.ViewPropertyAnimatorCompat alpha(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat alphaBy(float);
+    method public void cancel();
+    method public long getDuration();
+    method public android.view.animation.Interpolator getInterpolator();
+    method public long getStartDelay();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotation(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setDuration(long);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setListener(android.support.v4.view.ViewPropertyAnimatorListener);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setStartDelay(long);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setUpdateListener(android.support.v4.view.ViewPropertyAnimatorUpdateListener);
+    method public void start();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationZ(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationZBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withEndAction(java.lang.Runnable);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withLayer();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withStartAction(java.lang.Runnable);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat x(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat xBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat y(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat yBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat z(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat zBy(float);
+  }
+
+  public abstract interface ViewPropertyAnimatorListener {
+    method public abstract void onAnimationCancel(android.view.View);
+    method public abstract void onAnimationEnd(android.view.View);
+    method public abstract void onAnimationStart(android.view.View);
+  }
+
+  public class ViewPropertyAnimatorListenerAdapter implements android.support.v4.view.ViewPropertyAnimatorListener {
+    ctor public ViewPropertyAnimatorListenerAdapter();
+    method public void onAnimationCancel(android.view.View);
+    method public void onAnimationEnd(android.view.View);
+    method public void onAnimationStart(android.view.View);
+  }
+
+  public abstract interface ViewPropertyAnimatorUpdateListener {
+    method public abstract void onAnimationUpdate(android.view.View);
+  }
+
+  public final class WindowCompat {
+    field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+    field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+  }
+
+  public class WindowInsetsCompat {
+    ctor public WindowInsetsCompat(android.support.v4.view.WindowInsetsCompat);
+    method public android.support.v4.view.WindowInsetsCompat consumeStableInsets();
+    method public android.support.v4.view.WindowInsetsCompat consumeSystemWindowInsets();
+    method public int getStableInsetBottom();
+    method public int getStableInsetLeft();
+    method public int getStableInsetRight();
+    method public int getStableInsetTop();
+    method public int getSystemWindowInsetBottom();
+    method public int getSystemWindowInsetLeft();
+    method public int getSystemWindowInsetRight();
+    method public int getSystemWindowInsetTop();
+    method public boolean hasInsets();
+    method public boolean hasStableInsets();
+    method public boolean hasSystemWindowInsets();
+    method public boolean isConsumed();
+    method public boolean isRound();
+    method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+    method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+  }
+
+}
+
+package android.support.v4.view.accessibility {
+
+  public final class AccessibilityEventCompat {
+    method public static void appendRecord(android.view.accessibility.AccessibilityEvent, android.support.v4.view.accessibility.AccessibilityRecordCompat);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat asRecord(android.view.accessibility.AccessibilityEvent);
+    method public int getAction(android.view.accessibility.AccessibilityEvent);
+    method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+    method public int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat getRecord(android.view.accessibility.AccessibilityEvent, int);
+    method public static int getRecordCount(android.view.accessibility.AccessibilityEvent);
+    method public void setAction(android.view.accessibility.AccessibilityEvent, int);
+    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+    method public void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+    field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+    field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+    field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+    field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+    field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+    field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+    field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+    field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+    field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+    field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+    field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+    field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+    field public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+    field public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+    field public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+    field public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+    field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+    field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+    field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+  }
+
+  public final class AccessibilityManagerCompat {
+    method public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener);
+    method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+    method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager, int);
+    method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager);
+    method public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager);
+    method public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener);
+    method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+  }
+
+  public static abstract interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    method public abstract void onAccessibilityStateChanged(boolean);
+  }
+
+  public static abstract deprecated class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    ctor public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+  }
+
+  public static abstract interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+    method public abstract void onTouchExplorationStateChanged(boolean);
+  }
+
+  public class AccessibilityNodeInfoCompat {
+    ctor public AccessibilityNodeInfoCompat(java.lang.Object);
+    method public void addAction(int);
+    method public void addAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+    method public void addChild(android.view.View);
+    method public void addChild(android.view.View, int);
+    method public boolean canOpenPopup();
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(java.lang.String);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat focusSearch(int);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat> getActionList();
+    method public int getActions();
+    method public void getBoundsInParent(android.graphics.Rect);
+    method public void getBoundsInScreen(android.graphics.Rect);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getChild(int);
+    method public int getChildCount();
+    method public java.lang.CharSequence getClassName();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat getCollectionInfo();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat getCollectionItemInfo();
+    method public java.lang.CharSequence getContentDescription();
+    method public int getDrawingOrder();
+    method public java.lang.CharSequence getError();
+    method public android.os.Bundle getExtras();
+    method public java.lang.Object getInfo();
+    method public int getInputType();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabelFor();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabeledBy();
+    method public int getLiveRegion();
+    method public int getMaxTextLength();
+    method public int getMovementGranularities();
+    method public java.lang.CharSequence getPackageName();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getParent();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat getRangeInfo();
+    method public java.lang.CharSequence getRoleDescription();
+    method public java.lang.CharSequence getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalAfter();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalBefore();
+    method public java.lang.String getViewIdResourceName();
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getWindow();
+    method public int getWindowId();
+    method public boolean isAccessibilityFocused();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isContentInvalid();
+    method public boolean isContextClickable();
+    method public boolean isDismissable();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isImportantForAccessibility();
+    method public boolean isLongClickable();
+    method public boolean isMultiLine();
+    method public boolean isPassword();
+    method public boolean isScrollable();
+    method public boolean isSelected();
+    method public boolean isVisibleToUser();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View, int);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public boolean performAction(int);
+    method public boolean performAction(int, android.os.Bundle);
+    method public void recycle();
+    method public boolean refresh();
+    method public boolean removeAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+    method public boolean removeChild(android.view.View);
+    method public boolean removeChild(android.view.View, int);
+    method public void setAccessibilityFocused(boolean);
+    method public void setBoundsInParent(android.graphics.Rect);
+    method public void setBoundsInScreen(android.graphics.Rect);
+    method public void setCanOpenPopup(boolean);
+    method public void setCheckable(boolean);
+    method public void setChecked(boolean);
+    method public void setClassName(java.lang.CharSequence);
+    method public void setClickable(boolean);
+    method public void setCollectionInfo(java.lang.Object);
+    method public void setCollectionItemInfo(java.lang.Object);
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setContentInvalid(boolean);
+    method public void setContextClickable(boolean);
+    method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
+    method public void setEditable(boolean);
+    method public void setEnabled(boolean);
+    method public void setError(java.lang.CharSequence);
+    method public void setFocusable(boolean);
+    method public void setFocused(boolean);
+    method public void setImportantForAccessibility(boolean);
+    method public void setInputType(int);
+    method public void setLabelFor(android.view.View);
+    method public void setLabelFor(android.view.View, int);
+    method public void setLabeledBy(android.view.View);
+    method public void setLabeledBy(android.view.View, int);
+    method public void setLiveRegion(int);
+    method public void setLongClickable(boolean);
+    method public void setMaxTextLength(int);
+    method public void setMovementGranularities(int);
+    method public void setMultiLine(boolean);
+    method public void setPackageName(java.lang.CharSequence);
+    method public void setParent(android.view.View);
+    method public void setParent(android.view.View, int);
+    method public void setPassword(boolean);
+    method public void setRangeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat);
+    method public void setRoleDescription(java.lang.CharSequence);
+    method public void setScrollable(boolean);
+    method public void setSelected(boolean);
+    method public void setSource(android.view.View);
+    method public void setSource(android.view.View, int);
+    method public void setText(java.lang.CharSequence);
+    method public void setTextSelection(int, int);
+    method public void setTraversalAfter(android.view.View);
+    method public void setTraversalAfter(android.view.View, int);
+    method public void setTraversalBefore(android.view.View);
+    method public void setTraversalBefore(android.view.View, int);
+    method public void setViewIdResourceName(java.lang.String);
+    method public void setVisibleToUser(boolean);
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+    field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+    field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+    field public static final java.lang.String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+    field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+    field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+    field public static final int ACTION_CLICK = 16; // 0x10
+    field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+    field public static final int ACTION_COPY = 16384; // 0x4000
+    field public static final int ACTION_CUT = 65536; // 0x10000
+    field public static final int ACTION_DISMISS = 1048576; // 0x100000
+    field public static final int ACTION_EXPAND = 262144; // 0x40000
+    field public static final int ACTION_FOCUS = 1; // 0x1
+    field public static final int ACTION_LONG_CLICK = 32; // 0x20
+    field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+    field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+    field public static final int ACTION_PASTE = 32768; // 0x8000
+    field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+    field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+    field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+    field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+    field public static final int ACTION_SELECT = 4; // 0x4
+    field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+    field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+    field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+    field public static final int FOCUS_INPUT = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+    field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+    field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+    field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+  }
+
+  public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+    ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, java.lang.CharSequence);
+    method public int getId();
+    method public java.lang.CharSequence getLabel();
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_ACCESSIBILITY_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_SELECTION;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COLLAPSE;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CONTEXT_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COPY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CUT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DISMISS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_EXPAND;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_LONG_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PASTE;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_HTML_ELEMENT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_BACKWARD;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_DOWN;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_FORWARD;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_LEFT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_RIGHT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_TO_POSITION;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_UP;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SELECT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_PROGRESS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_SELECTION;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_TEXT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_ON_SCREEN;
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+    method public int getColumnCount();
+    method public int getRowCount();
+    method public int getSelectionMode();
+    method public boolean isHierarchical();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat obtain(int, int, boolean, int);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat obtain(int, int, boolean);
+    field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+    field public static final int SELECTION_MODE_NONE = 0; // 0x0
+    field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+    method public int getColumnIndex();
+    method public int getColumnSpan();
+    method public int getRowIndex();
+    method public int getRowSpan();
+    method public boolean isHeading();
+    method public boolean isSelected();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat obtain(int, int, int, int, boolean, boolean);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat obtain(int, int, int, int, boolean);
+  }
+
+  public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+    method public float getCurrent();
+    method public float getMax();
+    method public float getMin();
+    method public int getType();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat obtain(int, float, float, float);
+    field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+    field public static final int RANGE_TYPE_INT = 0; // 0x0
+    field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+  }
+
+  public class AccessibilityNodeProviderCompat {
+    ctor public AccessibilityNodeProviderCompat();
+    ctor public AccessibilityNodeProviderCompat(java.lang.Object);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String, int);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+    method public java.lang.Object getProvider();
+    method public boolean performAction(int, int, android.os.Bundle);
+    field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+  }
+
+  public class AccessibilityRecordCompat {
+    ctor public deprecated AccessibilityRecordCompat(java.lang.Object);
+    method public int getAddedCount();
+    method public java.lang.CharSequence getBeforeText();
+    method public java.lang.CharSequence getClassName();
+    method public java.lang.CharSequence getContentDescription();
+    method public int getCurrentItemIndex();
+    method public int getFromIndex();
+    method public deprecated java.lang.Object getImpl();
+    method public int getItemCount();
+    method public int getMaxScrollX();
+    method public int getMaxScrollY();
+    method public android.os.Parcelable getParcelableData();
+    method public int getRemovedCount();
+    method public int getScrollX();
+    method public int getScrollY();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getSource();
+    method public java.util.List<java.lang.CharSequence> getText();
+    method public int getToIndex();
+    method public int getWindowId();
+    method public boolean isChecked();
+    method public boolean isEnabled();
+    method public boolean isFullScreen();
+    method public boolean isPassword();
+    method public boolean isScrollable();
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain(android.support.v4.view.accessibility.AccessibilityRecordCompat);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain();
+    method public void recycle();
+    method public void setAddedCount(int);
+    method public void setBeforeText(java.lang.CharSequence);
+    method public void setChecked(boolean);
+    method public void setClassName(java.lang.CharSequence);
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setCurrentItemIndex(int);
+    method public void setEnabled(boolean);
+    method public void setFromIndex(int);
+    method public void setFullScreen(boolean);
+    method public void setItemCount(int);
+    method public void setMaxScrollX(int);
+    method public void setMaxScrollY(int);
+    method public void setParcelableData(android.os.Parcelable);
+    method public void setPassword(boolean);
+    method public void setRemovedCount(int);
+    method public void setScrollX(int);
+    method public void setScrollY(int);
+    method public void setScrollable(boolean);
+    method public void setSource(android.view.View);
+    method public void setSource(android.view.View, int);
+    method public void setToIndex(int);
+  }
+
+  public class AccessibilityWindowInfoCompat {
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getAnchor();
+    method public void getBoundsInScreen(android.graphics.Rect);
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getChild(int);
+    method public int getChildCount();
+    method public int getId();
+    method public int getLayer();
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getParent();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getRoot();
+    method public java.lang.CharSequence getTitle();
+    method public int getType();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActive();
+    method public boolean isFocused();
+    method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain();
+    method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityWindowInfoCompat);
+    method public void recycle();
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+    field public static final int TYPE_APPLICATION = 1; // 0x1
+    field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+    field public static final int TYPE_SYSTEM = 3; // 0x3
+  }
+
+}
+
+package android.support.v4.view.animation {
+
+  public class FastOutLinearInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public FastOutLinearInInterpolator();
+  }
+
+  public class FastOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public FastOutSlowInInterpolator();
+  }
+
+  public class LinearOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public LinearOutSlowInInterpolator();
+  }
+
+   abstract class LookupTableInterpolator implements android.view.animation.Interpolator {
+    ctor public LookupTableInterpolator(float[]);
+    method public float getInterpolation(float);
+  }
+
+  public final class PathInterpolatorCompat {
+    method public static android.view.animation.Interpolator create(android.graphics.Path);
+    method public static android.view.animation.Interpolator create(float, float);
+    method public static android.view.animation.Interpolator create(float, float, float, float);
+  }
+
+}
+
+package android.support.v4.widget {
+
+  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+    ctor public AutoScrollHelper(android.view.View);
+    method public abstract boolean canTargetScrollHorizontally(int);
+    method public abstract boolean canTargetScrollVertically(int);
+    method public boolean isEnabled();
+    method public boolean isExclusive();
+    method public boolean onTouch(android.view.View, android.view.MotionEvent);
+    method public abstract void scrollTargetBy(int, int);
+    method public android.support.v4.widget.AutoScrollHelper setActivationDelay(int);
+    method public android.support.v4.widget.AutoScrollHelper setEdgeType(int);
+    method public android.support.v4.widget.AutoScrollHelper setEnabled(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setExclusive(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMinimumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRampDownDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRampUpDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeVelocity(float, float);
+    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+    field public static final float NO_MAX = 3.4028235E38f;
+    field public static final float NO_MIN = 0.0f;
+    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+  }
+
+  public final class CompoundButtonCompat {
+    method public static android.graphics.drawable.Drawable getButtonDrawable(android.widget.CompoundButton);
+    method public static android.content.res.ColorStateList getButtonTintList(android.widget.CompoundButton);
+    method public static android.graphics.PorterDuff.Mode getButtonTintMode(android.widget.CompoundButton);
+    method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList);
+    method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode);
+  }
+
+  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+    ctor public ContentLoadingProgressBar(android.content.Context);
+    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
+    method public void hide();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void show();
+  }
+
+  public abstract class CursorAdapter extends android.widget.BaseAdapter {
+    ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
+    method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursor(android.database.Cursor);
+    method public java.lang.CharSequence convertToString(android.database.Cursor);
+    method public int getCount();
+    method public android.database.Cursor getCursor();
+    method public android.widget.Filter getFilter();
+    method public android.widget.FilterQueryProvider getFilterQueryProvider();
+    method public java.lang.Object getItem(int);
+    method public long getItemId(int);
+    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+    method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+    method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method protected void onContentChanged();
+    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+    field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+    field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
+  }
+
+  public class DrawerLayout extends android.view.ViewGroup {
+    ctor public DrawerLayout(android.content.Context);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void addDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void closeDrawer(android.view.View);
+    method public void closeDrawer(android.view.View, boolean);
+    method public void closeDrawer(int);
+    method public void closeDrawer(int, boolean);
+    method public void closeDrawers();
+    method public float getDrawerElevation();
+    method public int getDrawerLockMode(int);
+    method public int getDrawerLockMode(android.view.View);
+    method public java.lang.CharSequence getDrawerTitle(int);
+    method public android.graphics.drawable.Drawable getStatusBarBackgroundDrawable();
+    method public boolean isDrawerOpen(android.view.View);
+    method public boolean isDrawerOpen(int);
+    method public boolean isDrawerVisible(android.view.View);
+    method public boolean isDrawerVisible(int);
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void openDrawer(android.view.View);
+    method public void openDrawer(android.view.View, boolean);
+    method public void openDrawer(int);
+    method public void openDrawer(int, boolean);
+    method public void removeDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void setDrawerElevation(float);
+    method public deprecated void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void setDrawerLockMode(int);
+    method public void setDrawerLockMode(int, int);
+    method public void setDrawerLockMode(int, android.view.View);
+    method public void setDrawerShadow(android.graphics.drawable.Drawable, int);
+    method public void setDrawerShadow(int, int);
+    method public void setDrawerTitle(int, java.lang.CharSequence);
+    method public void setScrimColor(int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackground(int);
+    method public void setStatusBarBackgroundColor(int);
+    field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
+    field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+    field public static final int LOCK_MODE_UNDEFINED = 3; // 0x3
+    field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract interface DrawerLayout.DrawerListener {
+    method public abstract void onDrawerClosed(android.view.View);
+    method public abstract void onDrawerOpened(android.view.View);
+    method public abstract void onDrawerSlide(android.view.View, float);
+    method public abstract void onDrawerStateChanged(int);
+  }
+
+  public static class DrawerLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public DrawerLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout.LayoutParams(int, int);
+    ctor public DrawerLayout.LayoutParams(int, int, int);
+    ctor public DrawerLayout.LayoutParams(android.support.v4.widget.DrawerLayout.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    field public int gravity;
+  }
+
+  protected static class DrawerLayout.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public DrawerLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public DrawerLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.widget.DrawerLayout.SavedState> CREATOR;
+  }
+
+  public static abstract class DrawerLayout.SimpleDrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public DrawerLayout.SimpleDrawerListener();
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+  }
+
+  public final class EdgeEffectCompat {
+    ctor public EdgeEffectCompat(android.content.Context);
+    method public boolean draw(android.graphics.Canvas);
+    method public void finish();
+    method public boolean isFinished();
+    method public boolean onAbsorb(int);
+    method public deprecated boolean onPull(float);
+    method public boolean onPull(float, float);
+    method public boolean onRelease();
+    method public void setSize(int, int);
+  }
+
+  public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public ExploreByTouchHelper(android.view.View);
+    method public final boolean clearKeyboardFocusForVirtualView(int);
+    method public final boolean dispatchHoverEvent(android.view.MotionEvent);
+    method public final boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public final int getAccessibilityFocusedVirtualViewId();
+    method public deprecated int getFocusedVirtualView();
+    method public final int getKeyboardFocusedVirtualViewId();
+    method protected abstract int getVirtualViewAt(float, float);
+    method protected abstract void getVisibleVirtualViews(java.util.List<java.lang.Integer>);
+    method public final void invalidateRoot();
+    method public final void invalidateVirtualView(int);
+    method public final void invalidateVirtualView(int, int);
+    method public final void onFocusChanged(boolean, int, android.graphics.Rect);
+    method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
+    method protected void onPopulateEventForHost(android.view.accessibility.AccessibilityEvent);
+    method protected void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
+    method protected void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method protected void onVirtualViewKeyboardFocusChanged(int, boolean);
+    method public final boolean requestKeyboardFocusForVirtualView(int);
+    method public final boolean sendEventForVirtualView(int, int);
+    field public static final int HOST_ID = -1; // 0xffffffff
+    field public static final int INVALID_ID = -2147483648; // 0x80000000
+  }
+
+  public final class ListPopupWindowCompat {
+    method public static android.view.View.OnTouchListener createDragToOpenListener(java.lang.Object, android.view.View);
+  }
+
+  public class ListViewAutoScrollHelper extends android.support.v4.widget.AutoScrollHelper {
+    ctor public ListViewAutoScrollHelper(android.widget.ListView);
+    method public boolean canTargetScrollHorizontally(int);
+    method public boolean canTargetScrollVertically(int);
+    method public void scrollTargetBy(int, int);
+  }
+
+  public final class ListViewCompat {
+    method public static void scrollListBy(android.widget.ListView, int);
+  }
+
+  public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
+    ctor public NestedScrollView(android.content.Context);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
+    method public boolean arrowScroll(int);
+    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect);
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fling(int);
+    method public boolean fullScroll(int);
+    method public int getMaxScrollAmount();
+    method public boolean isFillViewport();
+    method public boolean isSmoothScrollingEnabled();
+    method public void onAttachedToWindow();
+    method public boolean pageScroll(int);
+    method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
+    method public void setSmoothScrollingEnabled(boolean);
+    method public final void smoothScrollBy(int, int);
+    method public final void smoothScrollTo(int, int);
+  }
+
+  public static abstract interface NestedScrollView.OnScrollChangeListener {
+    method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
+  }
+
+  public final class PopupMenuCompat {
+    method public static android.view.View.OnTouchListener getDragToOpenListener(java.lang.Object);
+  }
+
+  public final class PopupWindowCompat {
+    method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+    method public static int getWindowLayoutType(android.widget.PopupWindow);
+    method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+    method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+  }
+
+  public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
+    ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
+    method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public void setDropDownViewResource(int);
+    method public void setViewResource(int);
+  }
+
+  public final class ScrollerCompat {
+    method public void abortAnimation();
+    method public boolean computeScrollOffset();
+    method public static android.support.v4.widget.ScrollerCompat create(android.content.Context);
+    method public static android.support.v4.widget.ScrollerCompat create(android.content.Context, android.view.animation.Interpolator);
+    method public void fling(int, int, int, int, int, int, int, int);
+    method public void fling(int, int, int, int, int, int, int, int, int, int);
+    method public float getCurrVelocity();
+    method public int getCurrX();
+    method public int getCurrY();
+    method public int getFinalX();
+    method public int getFinalY();
+    method public boolean isFinished();
+    method public boolean isOverScrolled();
+    method public void notifyHorizontalEdgeReached(int, int, int);
+    method public void notifyVerticalEdgeReached(int, int, int);
+    method public boolean springBack(int, int, int, int, int, int);
+    method public void startScroll(int, int, int, int);
+    method public void startScroll(int, int, int, int, int);
+  }
+
+  public final deprecated class SearchViewCompat {
+    method public static deprecated java.lang.CharSequence getQuery(android.view.View);
+    method public static deprecated boolean isIconified(android.view.View);
+    method public static deprecated boolean isQueryRefinementEnabled(android.view.View);
+    method public static deprecated boolean isSubmitButtonEnabled(android.view.View);
+    method public static deprecated android.view.View newSearchView(android.content.Context);
+    method public static deprecated void setIconified(android.view.View, boolean);
+    method public static deprecated void setImeOptions(android.view.View, int);
+    method public static deprecated void setInputType(android.view.View, int);
+    method public static deprecated void setMaxWidth(android.view.View, int);
+    method public static deprecated void setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener);
+    method public static deprecated void setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener);
+    method public static deprecated void setQuery(android.view.View, java.lang.CharSequence, boolean);
+    method public static deprecated void setQueryHint(android.view.View, java.lang.CharSequence);
+    method public static deprecated void setQueryRefinementEnabled(android.view.View, boolean);
+    method public static deprecated void setSearchableInfo(android.view.View, android.content.ComponentName);
+    method public static deprecated void setSubmitButtonEnabled(android.view.View, boolean);
+  }
+
+  public static abstract deprecated interface SearchViewCompat.OnCloseListener {
+    method public abstract boolean onClose();
+  }
+
+  public static abstract deprecated class SearchViewCompat.OnCloseListenerCompat implements android.support.v4.widget.SearchViewCompat.OnCloseListener {
+    ctor public SearchViewCompat.OnCloseListenerCompat();
+    method public boolean onClose();
+  }
+
+  public static abstract deprecated interface SearchViewCompat.OnQueryTextListener {
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public static abstract deprecated class SearchViewCompat.OnQueryTextListenerCompat implements android.support.v4.widget.SearchViewCompat.OnQueryTextListener {
+    ctor public SearchViewCompat.OnQueryTextListenerCompat();
+    method public boolean onQueryTextChange(java.lang.String);
+    method public boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
+    ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
+    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+    method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+    method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
+    method public int getStringConversionColumn();
+    method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
+    method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
+    method public void setStringConversionColumn(int);
+    method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
+    method public void setViewImage(android.widget.ImageView, java.lang.String);
+    method public void setViewText(android.widget.TextView, java.lang.String);
+  }
+
+  public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
+    method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+  }
+
+  public static abstract interface SimpleCursorAdapter.ViewBinder {
+    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+  }
+
+  public class SlidingPaneLayout extends android.view.ViewGroup {
+    ctor public SlidingPaneLayout(android.content.Context);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public deprecated boolean canSlide();
+    method public boolean closePane();
+    method public int getCoveredFadeColor();
+    method public int getParallaxDistance();
+    method public int getSliderFadeColor();
+    method public boolean isOpen();
+    method public boolean isSlideable();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public boolean openPane();
+    method public void setCoveredFadeColor(int);
+    method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
+    method public void setParallaxDistance(int);
+    method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
+    method public deprecated void setShadowResource(int);
+    method public void setShadowResourceLeft(int);
+    method public void setShadowResourceRight(int);
+    method public void setSliderFadeColor(int);
+    method public deprecated void smoothSlideClosed();
+    method public deprecated void smoothSlideOpen();
+  }
+
+  public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public SlidingPaneLayout.LayoutParams();
+    ctor public SlidingPaneLayout.LayoutParams(int, int);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public float weight;
+  }
+
+  public static abstract interface SlidingPaneLayout.PanelSlideListener {
+    method public abstract void onPanelClosed(android.view.View);
+    method public abstract void onPanelOpened(android.view.View);
+    method public abstract void onPanelSlide(android.view.View, float);
+  }
+
+  public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
+    ctor public SlidingPaneLayout.SimplePanelSlideListener();
+    method public void onPanelClosed(android.view.View);
+    method public void onPanelOpened(android.view.View);
+    method public void onPanelSlide(android.view.View, float);
+  }
+
+  public class Space extends android.view.View {
+    ctor public Space(android.content.Context, android.util.AttributeSet, int);
+    ctor public Space(android.content.Context, android.util.AttributeSet);
+    ctor public Space(android.content.Context);
+  }
+
+  public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+    ctor public SwipeRefreshLayout(android.content.Context);
+    ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
+    method public boolean canChildScrollUp();
+    method public int getProgressCircleDiameter();
+    method public int getProgressViewEndOffset();
+    method public int getProgressViewStartOffset();
+    method public boolean isRefreshing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onMeasure(int, int);
+    method public deprecated void setColorScheme(int...);
+    method public void setColorSchemeColors(int...);
+    method public void setColorSchemeResources(int...);
+    method public void setDistanceToTriggerSync(int);
+    method public void setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback);
+    method public void setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener);
+    method public deprecated void setProgressBackgroundColor(int);
+    method public void setProgressBackgroundColorSchemeColor(int);
+    method public void setProgressBackgroundColorSchemeResource(int);
+    method public void setProgressViewEndTarget(boolean, int);
+    method public void setProgressViewOffset(boolean, int, int);
+    method public void setRefreshing(boolean);
+    method public void setSize(int);
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int LARGE = 0; // 0x0
+    field protected int mFrom;
+    field protected int mOriginalOffsetTop;
+  }
+
+  public static abstract interface SwipeRefreshLayout.OnChildScrollUpCallback {
+    method public abstract boolean canChildScrollUp(android.support.v4.widget.SwipeRefreshLayout, android.view.View);
+  }
+
+  public static abstract interface SwipeRefreshLayout.OnRefreshListener {
+    method public abstract void onRefresh();
+  }
+
+  public final class TextViewCompat {
+    method public static android.graphics.drawable.Drawable[] getCompoundDrawablesRelative(android.widget.TextView);
+    method public static int getMaxLines(android.widget.TextView);
+    method public static int getMinLines(android.widget.TextView);
+    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, int, int, int, int);
+    method public static void setTextAppearance(android.widget.TextView, int);
+  }
+
+  public abstract interface TintableCompoundButton {
+    method public abstract android.content.res.ColorStateList getSupportButtonTintList();
+    method public abstract android.graphics.PorterDuff.Mode getSupportButtonTintMode();
+    method public abstract void setSupportButtonTintList(android.content.res.ColorStateList);
+    method public abstract void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
+  }
+
+  public class ViewDragHelper {
+    method public void abort();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int, int);
+    method public void cancel();
+    method public void captureChildView(android.view.View, int);
+    method public boolean checkTouchSlop(int);
+    method public boolean checkTouchSlop(int, int);
+    method public boolean continueSettling(boolean);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, android.support.v4.widget.ViewDragHelper.Callback);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, float, android.support.v4.widget.ViewDragHelper.Callback);
+    method public android.view.View findTopChildUnder(int, int);
+    method public void flingCapturedView(int, int, int, int);
+    method public int getActivePointerId();
+    method public android.view.View getCapturedView();
+    method public int getEdgeSize();
+    method public float getMinVelocity();
+    method public int getTouchSlop();
+    method public int getViewDragState();
+    method public boolean isCapturedViewUnder(int, int);
+    method public boolean isEdgeTouched(int);
+    method public boolean isEdgeTouched(int, int);
+    method public boolean isPointerDown(int);
+    method public boolean isViewUnder(android.view.View, int, int);
+    method public void processTouchEvent(android.view.MotionEvent);
+    method public void setEdgeTrackingEnabled(int);
+    method public void setMinVelocity(float);
+    method public boolean settleCapturedViewAt(int, int);
+    method public boolean shouldInterceptTouchEvent(android.view.MotionEvent);
+    method public boolean smoothSlideViewTo(android.view.View, int, int);
+    field public static final int DIRECTION_ALL = 3; // 0x3
+    field public static final int DIRECTION_HORIZONTAL = 1; // 0x1
+    field public static final int DIRECTION_VERTICAL = 2; // 0x2
+    field public static final int EDGE_ALL = 15; // 0xf
+    field public static final int EDGE_BOTTOM = 8; // 0x8
+    field public static final int EDGE_LEFT = 1; // 0x1
+    field public static final int EDGE_RIGHT = 2; // 0x2
+    field public static final int EDGE_TOP = 4; // 0x4
+    field public static final int INVALID_POINTER = -1; // 0xffffffff
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class ViewDragHelper.Callback {
+    ctor public ViewDragHelper.Callback();
+    method public int clampViewPositionHorizontal(android.view.View, int, int);
+    method public int clampViewPositionVertical(android.view.View, int, int);
+    method public int getOrderedChildIndex(int);
+    method public int getViewHorizontalDragRange(android.view.View);
+    method public int getViewVerticalDragRange(android.view.View);
+    method public void onEdgeDragStarted(int, int);
+    method public boolean onEdgeLock(int);
+    method public void onEdgeTouched(int, int);
+    method public void onViewCaptured(android.view.View, int);
+    method public void onViewDragStateChanged(int);
+    method public void onViewPositionChanged(android.view.View, int, int, int, int);
+    method public void onViewReleased(android.view.View, float, float);
+    method public abstract boolean tryCaptureView(android.view.View, int);
+  }
+
+}
+
+package android.support.v7.app {
+
+  public abstract class ActionBar {
+    ctor public ActionBar();
+    method public abstract void addOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, boolean);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int, boolean);
+    method public abstract android.view.View getCustomView();
+    method public abstract int getDisplayOptions();
+    method public float getElevation();
+    method public abstract int getHeight();
+    method public int getHideOffset();
+    method public abstract deprecated int getNavigationItemCount();
+    method public abstract deprecated int getNavigationMode();
+    method public abstract deprecated int getSelectedNavigationIndex();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab getSelectedTab();
+    method public abstract java.lang.CharSequence getSubtitle();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab getTabAt(int);
+    method public abstract deprecated int getTabCount();
+    method public android.content.Context getThemedContext();
+    method public abstract java.lang.CharSequence getTitle();
+    method public abstract void hide();
+    method public boolean isHideOnContentScrollEnabled();
+    method public abstract boolean isShowing();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab newTab();
+    method public abstract deprecated void removeAllTabs();
+    method public abstract void removeOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract deprecated void removeTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract deprecated void removeTabAt(int);
+    method public abstract deprecated void selectTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setCustomView(android.view.View);
+    method public abstract void setCustomView(android.view.View, android.support.v7.app.ActionBar.LayoutParams);
+    method public abstract void setCustomView(int);
+    method public abstract void setDisplayHomeAsUpEnabled(boolean);
+    method public abstract void setDisplayOptions(int);
+    method public abstract void setDisplayOptions(int, int);
+    method public abstract void setDisplayShowCustomEnabled(boolean);
+    method public abstract void setDisplayShowHomeEnabled(boolean);
+    method public abstract void setDisplayShowTitleEnabled(boolean);
+    method public abstract void setDisplayUseLogoEnabled(boolean);
+    method public void setElevation(float);
+    method public void setHideOffset(int);
+    method public void setHideOnContentScrollEnabled(boolean);
+    method public void setHomeActionContentDescription(java.lang.CharSequence);
+    method public void setHomeActionContentDescription(int);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setHomeButtonEnabled(boolean);
+    method public abstract void setIcon(int);
+    method public abstract void setIcon(android.graphics.drawable.Drawable);
+    method public abstract deprecated void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.support.v7.app.ActionBar.OnNavigationListener);
+    method public abstract void setLogo(int);
+    method public abstract void setLogo(android.graphics.drawable.Drawable);
+    method public abstract deprecated void setNavigationMode(int);
+    method public abstract deprecated void setSelectedNavigationItem(int);
+    method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setSubtitle(java.lang.CharSequence);
+    method public abstract void setSubtitle(int);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract void setTitle(int);
+    method public abstract void show();
+    field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
+    field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
+    field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
+    field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
+    field public static final int DISPLAY_USE_LOGO = 1; // 0x1
+    field public static final deprecated int NAVIGATION_MODE_LIST = 1; // 0x1
+    field public static final deprecated int NAVIGATION_MODE_STANDARD = 0; // 0x0
+    field public static final deprecated int NAVIGATION_MODE_TABS = 2; // 0x2
+  }
+
+  public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionBar.LayoutParams(int, int);
+    ctor public ActionBar.LayoutParams(int, int, int);
+    ctor public ActionBar.LayoutParams(int);
+    ctor public ActionBar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+    ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
+    field public int gravity;
+  }
+
+  public static abstract interface ActionBar.OnMenuVisibilityListener {
+    method public abstract void onMenuVisibilityChanged(boolean);
+  }
+
+  public static abstract deprecated interface ActionBar.OnNavigationListener {
+    method public abstract boolean onNavigationItemSelected(int, long);
+  }
+
+  public static abstract deprecated class ActionBar.Tab {
+    ctor public ActionBar.Tab();
+    method public abstract java.lang.CharSequence getContentDescription();
+    method public abstract android.view.View getCustomView();
+    method public abstract android.graphics.drawable.Drawable getIcon();
+    method public abstract int getPosition();
+    method public abstract java.lang.Object getTag();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract void select();
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(android.view.View);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setTabListener(android.support.v7.app.ActionBar.TabListener);
+    method public abstract android.support.v7.app.ActionBar.Tab setTag(java.lang.Object);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(int);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static abstract deprecated interface ActionBar.TabListener {
+    method public abstract void onTabReselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabSelected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabUnselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+  }
+
+  public deprecated class ActionBarActivity extends android.support.v7.app.AppCompatActivity {
+    ctor public ActionBarActivity();
+  }
+
+  public class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int);
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, android.support.v7.widget.Toolbar, int, int);
+    method public android.support.v7.graphics.drawable.DrawerArrowDrawable getDrawerArrowDrawable();
+    method public android.view.View.OnClickListener getToolbarNavigationClickListener();
+    method public boolean isDrawerIndicatorEnabled();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable);
+    method public void setDrawerIndicatorEnabled(boolean);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
+    method public void syncState();
+  }
+
+  public static abstract interface ActionBarDrawerToggle.Delegate {
+    method public abstract android.content.Context getActionBarThemedContext();
+    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+    method public abstract boolean isNavigationVisible();
+    method public abstract void setActionBarDescription(int);
+    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+  }
+
+  public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+    method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+  }
+
+  public class AlertDialog extends android.support.v7.app.AppCompatDialog implements android.content.DialogInterface {
+    ctor protected AlertDialog(android.content.Context);
+    ctor protected AlertDialog(android.content.Context, int);
+    ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.widget.Button getButton(int);
+    method public android.widget.ListView getListView();
+    method public void setButton(int, java.lang.CharSequence, android.os.Message);
+    method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public void setCustomTitle(android.view.View);
+    method public void setIcon(int);
+    method public void setIcon(android.graphics.drawable.Drawable);
+    method public void setIconAttribute(int);
+    method public void setMessage(java.lang.CharSequence);
+    method public void setView(android.view.View);
+    method public void setView(android.view.View, int, int, int, int);
+  }
+
+  public static class AlertDialog.Builder {
+    ctor public AlertDialog.Builder(android.content.Context);
+    ctor public AlertDialog.Builder(android.content.Context, int);
+    method public android.support.v7.app.AlertDialog create();
+    method public android.content.Context getContext();
+    method public android.support.v7.app.AlertDialog.Builder setAdapter(android.widget.ListAdapter, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setCancelable(boolean);
+    method public android.support.v7.app.AlertDialog.Builder setCursor(android.database.Cursor, android.content.DialogInterface.OnClickListener, java.lang.String);
+    method public android.support.v7.app.AlertDialog.Builder setCustomTitle(android.view.View);
+    method public android.support.v7.app.AlertDialog.Builder setIcon(int);
+    method public android.support.v7.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.support.v7.app.AlertDialog.Builder setIconAttribute(int);
+    method public deprecated android.support.v7.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public android.support.v7.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMessage(int);
+    method public android.support.v7.app.AlertDialog.Builder setMessage(java.lang.CharSequence);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(int, boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(java.lang.CharSequence[], boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, java.lang.String, java.lang.String, android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNegativeButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNegativeButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNeutralButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNeutralButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnCancelListener(android.content.DialogInterface.OnCancelListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnDismissListener(android.content.DialogInterface.OnDismissListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnKeyListener(android.content.DialogInterface.OnKeyListener);
+    method public android.support.v7.app.AlertDialog.Builder setPositiveButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setPositiveButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(int, int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, java.lang.String, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(java.lang.CharSequence[], int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.widget.ListAdapter, int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setTitle(int);
+    method public android.support.v7.app.AlertDialog.Builder setTitle(java.lang.CharSequence);
+    method public android.support.v7.app.AlertDialog.Builder setView(int);
+    method public android.support.v7.app.AlertDialog.Builder setView(android.view.View);
+    method public android.support.v7.app.AlertDialog show();
+  }
+
+  public class AppCompatActivity extends android.support.v4.app.FragmentActivity implements android.support.v7.app.ActionBarDrawerToggle.DelegateProvider android.support.v7.app.AppCompatCallback android.support.v4.app.TaskStackBuilder.SupportParentable {
+    ctor public AppCompatActivity();
+    method public android.support.v7.app.AppCompatDelegate getDelegate();
+    method public android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+    method public android.support.v7.app.ActionBar getSupportActionBar();
+    method public android.content.Intent getSupportParentActivityIntent();
+    method public void onCreateSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+    method public final boolean onMenuItemSelected(int, android.view.MenuItem);
+    method public void onPrepareSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+    method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public deprecated void onSupportContentChanged();
+    method public boolean onSupportNavigateUp();
+    method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public void setSupportActionBar(android.support.v7.widget.Toolbar);
+    method public deprecated void setSupportProgress(int);
+    method public deprecated void setSupportProgressBarIndeterminate(boolean);
+    method public deprecated void setSupportProgressBarIndeterminateVisibility(boolean);
+    method public deprecated void setSupportProgressBarVisibility(boolean);
+    method public android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public void supportNavigateUpTo(android.content.Intent);
+    method public boolean supportRequestWindowFeature(int);
+    method public boolean supportShouldUpRecreateTask(android.content.Intent);
+  }
+
+  public abstract interface AppCompatCallback {
+    method public abstract void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public abstract void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public abstract android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+  }
+
+  public abstract class AppCompatDelegate {
+    method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract boolean applyDayNight();
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Activity, android.support.v7.app.AppCompatCallback);
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Dialog, android.support.v7.app.AppCompatCallback);
+    method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public abstract android.view.View findViewById(int);
+    method public static int getDefaultNightMode();
+    method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+    method public abstract android.view.MenuInflater getMenuInflater();
+    method public abstract android.support.v7.app.ActionBar getSupportActionBar();
+    method public abstract boolean hasWindowFeature(int);
+    method public abstract void installViewFactory();
+    method public abstract void invalidateOptionsMenu();
+    method public static boolean isCompatVectorFromResourcesEnabled();
+    method public abstract boolean isHandleNativeActionModesEnabled();
+    method public abstract void onConfigurationChanged(android.content.res.Configuration);
+    method public abstract void onCreate(android.os.Bundle);
+    method public abstract void onDestroy();
+    method public abstract void onPostCreate(android.os.Bundle);
+    method public abstract void onPostResume();
+    method public abstract void onSaveInstanceState(android.os.Bundle);
+    method public abstract void onStart();
+    method public abstract void onStop();
+    method public abstract boolean requestWindowFeature(int);
+    method public static void setCompatVectorFromResourcesEnabled(boolean);
+    method public abstract void setContentView(android.view.View);
+    method public abstract void setContentView(int);
+    method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public static void setDefaultNightMode(int);
+    method public abstract void setHandleNativeActionModesEnabled(boolean);
+    method public abstract void setLocalNightMode(int);
+    method public abstract void setSupportActionBar(android.support.v7.widget.Toolbar);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+    field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
+    field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
+    field public static final int MODE_NIGHT_AUTO = 0; // 0x0
+    field public static final int MODE_NIGHT_FOLLOW_SYSTEM = -1; // 0xffffffff
+    field public static final int MODE_NIGHT_NO = 1; // 0x1
+    field public static final int MODE_NIGHT_YES = 2; // 0x2
+  }
+
+  public class AppCompatDialog extends android.app.Dialog implements android.support.v7.app.AppCompatCallback {
+    ctor public AppCompatDialog(android.content.Context);
+    ctor public AppCompatDialog(android.content.Context, int);
+    ctor protected AppCompatDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.support.v7.app.AppCompatDelegate getDelegate();
+    method public android.support.v7.app.ActionBar getSupportActionBar();
+    method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public boolean supportRequestWindowFeature(int);
+  }
+
+  public class AppCompatDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public AppCompatDialogFragment();
+  }
+
+  public class MediaRouteActionProvider extends android.support.v4.view.ActionProvider {
+    ctor public MediaRouteActionProvider(android.content.Context);
+    method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+    method public android.support.v7.app.MediaRouteButton getMediaRouteButton();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.view.View onCreateActionView();
+    method public android.support.v7.app.MediaRouteButton onCreateMediaRouteButton();
+    method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteButton extends android.view.View {
+    ctor public MediaRouteButton(android.content.Context);
+    ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet);
+    ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+    method public void setRemoteIndicatorDrawable(android.graphics.drawable.Drawable);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+    method public boolean showDialog();
+  }
+
+  public class MediaRouteChooserDialog extends android.support.v7.app.AppCompatDialog {
+    ctor public MediaRouteChooserDialog(android.content.Context);
+    ctor public MediaRouteChooserDialog(android.content.Context, int);
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public boolean onFilterRoute(android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onFilterRoutes(java.util.List<android.support.v7.media.MediaRouter.RouteInfo>);
+    method public void refreshRoutes();
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteChooserDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public MediaRouteChooserDialogFragment();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.support.v7.app.MediaRouteChooserDialog onCreateChooserDialog(android.content.Context, android.os.Bundle);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteControllerDialog extends android.support.v7.app.AlertDialog {
+    ctor public MediaRouteControllerDialog(android.content.Context);
+    ctor public MediaRouteControllerDialog(android.content.Context, int);
+    method public android.view.View getMediaControlView();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSession();
+    method public android.support.v7.media.MediaRouter.RouteInfo getRoute();
+    method public boolean isVolumeControlEnabled();
+    method public android.view.View onCreateMediaControlView(android.os.Bundle);
+    method public void setVolumeControlEnabled(boolean);
+  }
+
+  public class MediaRouteControllerDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public MediaRouteControllerDialogFragment();
+    method public android.support.v7.app.MediaRouteControllerDialog onCreateControllerDialog(android.content.Context, android.os.Bundle);
+  }
+
+  public class MediaRouteDialogFactory {
+    ctor public MediaRouteDialogFactory();
+    method public static android.support.v7.app.MediaRouteDialogFactory getDefault();
+    method public android.support.v7.app.MediaRouteChooserDialogFragment onCreateChooserDialogFragment();
+    method public android.support.v7.app.MediaRouteControllerDialogFragment onCreateControllerDialogFragment();
+  }
+
+  public class MediaRouteDiscoveryFragment extends android.support.v4.app.Fragment {
+    ctor public MediaRouteDiscoveryFragment();
+    method public android.support.v7.media.MediaRouter getMediaRouter();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.support.v7.media.MediaRouter.Callback onCreateCallback();
+    method public int onPrepareCallbackFlags();
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class NotificationCompat extends android.support.v4.app.NotificationCompat {
+    ctor public NotificationCompat();
+    method public static android.support.v4.media.session.MediaSessionCompat.Token getMediaSession(android.app.Notification);
+  }
+
+  public static class NotificationCompat.Builder extends android.support.v4.app.NotificationCompat.Builder {
+    ctor public NotificationCompat.Builder(android.content.Context);
+  }
+
+  public static class NotificationCompat.DecoratedCustomViewStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.DecoratedCustomViewStyle();
+  }
+
+  public static class NotificationCompat.DecoratedMediaCustomViewStyle extends android.support.v7.app.NotificationCompat.MediaStyle {
+    ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+  }
+
+  public static class NotificationCompat.MediaStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.MediaStyle();
+    ctor public NotificationCompat.MediaStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setCancelButtonIntent(android.app.PendingIntent);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setShowActionsInCompactView(int...);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setShowCancelButton(boolean);
+  }
+
+}
+
+package android.support.v7.content.res {
+
+  public final class AppCompatResources {
+    method public static android.content.res.ColorStateList getColorStateList(android.content.Context, int);
+    method public static android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
+  }
+
+}
+
+package android.support.v7.graphics {
+
+  public final class Palette {
+    method public static android.support.v7.graphics.Palette.Builder from(android.graphics.Bitmap);
+    method public static android.support.v7.graphics.Palette from(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+    method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap);
+    method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap, int);
+    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, int, android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public int getColorForTarget(android.support.v7.graphics.Target, int);
+    method public int getDarkMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDarkMutedSwatch();
+    method public int getDarkVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDarkVibrantSwatch();
+    method public int getDominantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDominantSwatch();
+    method public int getLightMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getLightMutedSwatch();
+    method public int getLightVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getLightVibrantSwatch();
+    method public int getMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getMutedSwatch();
+    method public android.support.v7.graphics.Palette.Swatch getSwatchForTarget(android.support.v7.graphics.Target);
+    method public java.util.List<android.support.v7.graphics.Palette.Swatch> getSwatches();
+    method public java.util.List<android.support.v7.graphics.Target> getTargets();
+    method public int getVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getVibrantSwatch();
+  }
+
+  public static final class Palette.Builder {
+    ctor public Palette.Builder(android.graphics.Bitmap);
+    ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+    method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+    method public android.support.v7.graphics.Palette.Builder addTarget(android.support.v7.graphics.Target);
+    method public android.support.v7.graphics.Palette.Builder clearFilters();
+    method public android.support.v7.graphics.Palette.Builder clearRegion();
+    method public android.support.v7.graphics.Palette.Builder clearTargets();
+    method public android.support.v7.graphics.Palette generate();
+    method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
+    method public android.support.v7.graphics.Palette.Builder resizeBitmapArea(int);
+    method public deprecated android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+    method public android.support.v7.graphics.Palette.Builder setRegion(int, int, int, int);
+  }
+
+  public static abstract interface Palette.Filter {
+    method public abstract boolean isAllowed(int, float[]);
+  }
+
+  public static abstract interface Palette.PaletteAsyncListener {
+    method public abstract void onGenerated(android.support.v7.graphics.Palette);
+  }
+
+  public static final class Palette.Swatch {
+    ctor public Palette.Swatch(int, int);
+    method public int getBodyTextColor();
+    method public float[] getHsl();
+    method public int getPopulation();
+    method public int getRgb();
+    method public int getTitleTextColor();
+  }
+
+  public final class Target {
+    method public float getLightnessWeight();
+    method public float getMaximumLightness();
+    method public float getMaximumSaturation();
+    method public float getMinimumLightness();
+    method public float getMinimumSaturation();
+    method public float getPopulationWeight();
+    method public float getSaturationWeight();
+    method public float getTargetLightness();
+    method public float getTargetSaturation();
+    method public boolean isExclusive();
+    field public static final android.support.v7.graphics.Target DARK_MUTED;
+    field public static final android.support.v7.graphics.Target DARK_VIBRANT;
+    field public static final android.support.v7.graphics.Target LIGHT_MUTED;
+    field public static final android.support.v7.graphics.Target LIGHT_VIBRANT;
+    field public static final android.support.v7.graphics.Target MUTED;
+    field public static final android.support.v7.graphics.Target VIBRANT;
+  }
+
+  public static final class Target.Builder {
+    ctor public Target.Builder();
+    ctor public Target.Builder(android.support.v7.graphics.Target);
+    method public android.support.v7.graphics.Target build();
+    method public android.support.v7.graphics.Target.Builder setExclusive(boolean);
+    method public android.support.v7.graphics.Target.Builder setLightnessWeight(float);
+    method public android.support.v7.graphics.Target.Builder setMaximumLightness(float);
+    method public android.support.v7.graphics.Target.Builder setMaximumSaturation(float);
+    method public android.support.v7.graphics.Target.Builder setMinimumLightness(float);
+    method public android.support.v7.graphics.Target.Builder setMinimumSaturation(float);
+    method public android.support.v7.graphics.Target.Builder setPopulationWeight(float);
+    method public android.support.v7.graphics.Target.Builder setSaturationWeight(float);
+    method public android.support.v7.graphics.Target.Builder setTargetLightness(float);
+    method public android.support.v7.graphics.Target.Builder setTargetSaturation(float);
+  }
+
+}
+
+package android.support.v7.graphics.drawable {
+
+  public class DrawerArrowDrawable extends android.graphics.drawable.Drawable {
+    ctor public DrawerArrowDrawable(android.content.Context);
+    method public void draw(android.graphics.Canvas);
+    method public float getArrowHeadLength();
+    method public float getArrowShaftLength();
+    method public float getBarLength();
+    method public float getBarThickness();
+    method public int getColor();
+    method public int getDirection();
+    method public float getGapSize();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public float getProgress();
+    method public boolean isSpinEnabled();
+    method public void setAlpha(int);
+    method public void setArrowHeadLength(float);
+    method public void setArrowShaftLength(float);
+    method public void setBarLength(float);
+    method public void setBarThickness(float);
+    method public void setColor(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDirection(int);
+    method public void setGapSize(float);
+    method public void setProgress(float);
+    method public void setSpinEnabled(boolean);
+    method public void setVerticalMirror(boolean);
+    field public static final int ARROW_DIRECTION_END = 3; // 0x3
+    field public static final int ARROW_DIRECTION_LEFT = 0; // 0x0
+    field public static final int ARROW_DIRECTION_RIGHT = 1; // 0x1
+    field public static final int ARROW_DIRECTION_START = 2; // 0x2
+  }
+
+}
+
+package android.support.v7.media {
+
+  public final class MediaControlIntent {
+    field public static final java.lang.String ACTION_END_SESSION = "android.media.intent.action.END_SESSION";
+    field public static final java.lang.String ACTION_ENQUEUE = "android.media.intent.action.ENQUEUE";
+    field public static final java.lang.String ACTION_GET_SESSION_STATUS = "android.media.intent.action.GET_SESSION_STATUS";
+    field public static final java.lang.String ACTION_GET_STATUS = "android.media.intent.action.GET_STATUS";
+    field public static final java.lang.String ACTION_PAUSE = "android.media.intent.action.PAUSE";
+    field public static final java.lang.String ACTION_PLAY = "android.media.intent.action.PLAY";
+    field public static final java.lang.String ACTION_REMOVE = "android.media.intent.action.REMOVE";
+    field public static final java.lang.String ACTION_RESUME = "android.media.intent.action.RESUME";
+    field public static final java.lang.String ACTION_SEEK = "android.media.intent.action.SEEK";
+    field public static final java.lang.String ACTION_SEND_MESSAGE = "android.media.intent.action.SEND_MESSAGE";
+    field public static final java.lang.String ACTION_START_SESSION = "android.media.intent.action.START_SESSION";
+    field public static final java.lang.String ACTION_STOP = "android.media.intent.action.STOP";
+    field public static final java.lang.String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+    field public static final java.lang.String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
+    field public static final java.lang.String CATEGORY_REMOTE_PLAYBACK = "android.media.intent.category.REMOTE_PLAYBACK";
+    field public static final int ERROR_INVALID_ITEM_ID = 3; // 0x3
+    field public static final int ERROR_INVALID_SESSION_ID = 2; // 0x2
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int ERROR_UNSUPPORTED_OPERATION = 1; // 0x1
+    field public static final java.lang.String EXTRA_ERROR_CODE = "android.media.intent.extra.ERROR_CODE";
+    field public static final java.lang.String EXTRA_ITEM_CONTENT_POSITION = "android.media.intent.extra.ITEM_POSITION";
+    field public static final java.lang.String EXTRA_ITEM_HTTP_HEADERS = "android.media.intent.extra.HTTP_HEADERS";
+    field public static final java.lang.String EXTRA_ITEM_ID = "android.media.intent.extra.ITEM_ID";
+    field public static final java.lang.String EXTRA_ITEM_METADATA = "android.media.intent.extra.ITEM_METADATA";
+    field public static final java.lang.String EXTRA_ITEM_STATUS = "android.media.intent.extra.ITEM_STATUS";
+    field public static final java.lang.String EXTRA_ITEM_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.ITEM_STATUS_UPDATE_RECEIVER";
+    field public static final java.lang.String EXTRA_MESSAGE = "android.media.intent.extra.MESSAGE";
+    field public static final java.lang.String EXTRA_MESSAGE_RECEIVER = "android.media.intent.extra.MESSAGE_RECEIVER";
+    field public static final java.lang.String EXTRA_SESSION_ID = "android.media.intent.extra.SESSION_ID";
+    field public static final java.lang.String EXTRA_SESSION_STATUS = "android.media.intent.extra.SESSION_STATUS";
+    field public static final java.lang.String EXTRA_SESSION_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.SESSION_STATUS_UPDATE_RECEIVER";
+  }
+
+  public final class MediaItemMetadata {
+    field public static final java.lang.String KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String KEY_ALBUM_TITLE = "android.media.metadata.ALBUM_TITLE";
+    field public static final java.lang.String KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String KEY_ARTWORK_URI = "android.media.metadata.ARTWORK_URI";
+    field public static final java.lang.String KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public final class MediaItemStatus {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaItemStatus fromBundle(android.os.Bundle);
+    method public long getContentDuration();
+    method public long getContentPosition();
+    method public android.os.Bundle getExtras();
+    method public int getPlaybackState();
+    method public long getTimestamp();
+    field public static final java.lang.String EXTRA_HTTP_RESPONSE_HEADERS = "android.media.status.extra.HTTP_RESPONSE_HEADERS";
+    field public static final java.lang.String EXTRA_HTTP_STATUS_CODE = "android.media.status.extra.HTTP_STATUS_CODE";
+    field public static final int PLAYBACK_STATE_BUFFERING = 3; // 0x3
+    field public static final int PLAYBACK_STATE_CANCELED = 5; // 0x5
+    field public static final int PLAYBACK_STATE_ERROR = 7; // 0x7
+    field public static final int PLAYBACK_STATE_FINISHED = 4; // 0x4
+    field public static final int PLAYBACK_STATE_INVALIDATED = 6; // 0x6
+    field public static final int PLAYBACK_STATE_PAUSED = 2; // 0x2
+    field public static final int PLAYBACK_STATE_PENDING = 0; // 0x0
+    field public static final int PLAYBACK_STATE_PLAYING = 1; // 0x1
+  }
+
+  public static final class MediaItemStatus.Builder {
+    ctor public MediaItemStatus.Builder(int);
+    ctor public MediaItemStatus.Builder(android.support.v7.media.MediaItemStatus);
+    method public android.support.v7.media.MediaItemStatus build();
+    method public android.support.v7.media.MediaItemStatus.Builder setContentDuration(long);
+    method public android.support.v7.media.MediaItemStatus.Builder setContentPosition(long);
+    method public android.support.v7.media.MediaItemStatus.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaItemStatus.Builder setPlaybackState(int);
+    method public android.support.v7.media.MediaItemStatus.Builder setTimestamp(long);
+  }
+
+  public final class MediaRouteDescriptor {
+    method public android.os.Bundle asBundle();
+    method public boolean canDisconnectAndKeepPlaying();
+    method public static android.support.v7.media.MediaRouteDescriptor fromBundle(android.os.Bundle);
+    method public int getConnectionState();
+    method public java.util.List<android.content.IntentFilter> getControlFilters();
+    method public java.lang.String getDescription();
+    method public int getDeviceType();
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getIconUri();
+    method public java.lang.String getId();
+    method public java.lang.String getName();
+    method public int getPlaybackStream();
+    method public int getPlaybackType();
+    method public int getPresentationDisplayId();
+    method public android.content.IntentSender getSettingsActivity();
+    method public int getVolume();
+    method public int getVolumeHandling();
+    method public int getVolumeMax();
+    method public deprecated boolean isConnecting();
+    method public boolean isEnabled();
+    method public boolean isValid();
+  }
+
+  public static final class MediaRouteDescriptor.Builder {
+    ctor public MediaRouteDescriptor.Builder(java.lang.String, java.lang.String);
+    ctor public MediaRouteDescriptor.Builder(android.support.v7.media.MediaRouteDescriptor);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilter(android.content.IntentFilter);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilters(java.util.Collection<android.content.IntentFilter>);
+    method public android.support.v7.media.MediaRouteDescriptor build();
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
+    method public deprecated android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setConnectionState(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setDescription(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setDeviceType(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setEnabled(boolean);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setIconUri(android.net.Uri);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setId(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setName(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackStream(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackType(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPresentationDisplayId(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setSettingsActivity(android.content.IntentSender);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolume(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeHandling(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeMax(int);
+  }
+
+  public final class MediaRouteDiscoveryRequest {
+    ctor public MediaRouteDiscoveryRequest(android.support.v7.media.MediaRouteSelector, boolean);
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaRouteDiscoveryRequest fromBundle(android.os.Bundle);
+    method public android.support.v7.media.MediaRouteSelector getSelector();
+    method public boolean isActiveScan();
+    method public boolean isValid();
+  }
+
+  public abstract class MediaRouteProvider {
+    ctor public MediaRouteProvider(android.content.Context);
+    method public final android.content.Context getContext();
+    method public final android.support.v7.media.MediaRouteProviderDescriptor getDescriptor();
+    method public final android.support.v7.media.MediaRouteDiscoveryRequest getDiscoveryRequest();
+    method public final android.os.Handler getHandler();
+    method public final android.support.v7.media.MediaRouteProvider.ProviderMetadata getMetadata();
+    method public android.support.v7.media.MediaRouteProvider.RouteController onCreateRouteController(java.lang.String);
+    method public void onDiscoveryRequestChanged(android.support.v7.media.MediaRouteDiscoveryRequest);
+    method public final void setCallback(android.support.v7.media.MediaRouteProvider.Callback);
+    method public final void setDescriptor(android.support.v7.media.MediaRouteProviderDescriptor);
+    method public final void setDiscoveryRequest(android.support.v7.media.MediaRouteDiscoveryRequest);
+  }
+
+  public static abstract class MediaRouteProvider.Callback {
+    ctor public MediaRouteProvider.Callback();
+    method public void onDescriptorChanged(android.support.v7.media.MediaRouteProvider, android.support.v7.media.MediaRouteProviderDescriptor);
+  }
+
+  public static final class MediaRouteProvider.ProviderMetadata {
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getPackageName();
+  }
+
+  public static abstract class MediaRouteProvider.RouteController {
+    ctor public MediaRouteProvider.RouteController();
+    method public boolean onControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+    method public void onRelease();
+    method public void onSelect();
+    method public void onSetVolume(int);
+    method public void onUnselect();
+    method public void onUnselect(int);
+    method public void onUpdateVolume(int);
+  }
+
+  public final class MediaRouteProviderDescriptor {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaRouteProviderDescriptor fromBundle(android.os.Bundle);
+    method public java.util.List<android.support.v7.media.MediaRouteDescriptor> getRoutes();
+    method public boolean isValid();
+  }
+
+  public static final class MediaRouteProviderDescriptor.Builder {
+    ctor public MediaRouteProviderDescriptor.Builder();
+    ctor public MediaRouteProviderDescriptor.Builder(android.support.v7.media.MediaRouteProviderDescriptor);
+    method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoute(android.support.v7.media.MediaRouteDescriptor);
+    method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoutes(java.util.Collection<android.support.v7.media.MediaRouteDescriptor>);
+    method public android.support.v7.media.MediaRouteProviderDescriptor build();
+  }
+
+  public abstract class MediaRouteProviderService extends android.app.Service {
+    ctor public MediaRouteProviderService();
+    method public android.support.v7.media.MediaRouteProvider getMediaRouteProvider();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.support.v7.media.MediaRouteProvider onCreateMediaRouteProvider();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaRouteProviderService";
+  }
+
+  public final class MediaRouteSelector {
+    method public android.os.Bundle asBundle();
+    method public boolean contains(android.support.v7.media.MediaRouteSelector);
+    method public static android.support.v7.media.MediaRouteSelector fromBundle(android.os.Bundle);
+    method public java.util.List<java.lang.String> getControlCategories();
+    method public boolean hasControlCategory(java.lang.String);
+    method public boolean isEmpty();
+    method public boolean isValid();
+    method public boolean matchesControlFilters(java.util.List<android.content.IntentFilter>);
+    field public static final android.support.v7.media.MediaRouteSelector EMPTY;
+  }
+
+  public static final class MediaRouteSelector.Builder {
+    ctor public MediaRouteSelector.Builder();
+    ctor public MediaRouteSelector.Builder(android.support.v7.media.MediaRouteSelector);
+    method public android.support.v7.media.MediaRouteSelector.Builder addControlCategories(java.util.Collection<java.lang.String>);
+    method public android.support.v7.media.MediaRouteSelector.Builder addControlCategory(java.lang.String);
+    method public android.support.v7.media.MediaRouteSelector.Builder addSelector(android.support.v7.media.MediaRouteSelector);
+    method public android.support.v7.media.MediaRouteSelector build();
+  }
+
+  public final class MediaRouter {
+    method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback);
+    method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback, int);
+    method public void addProvider(android.support.v7.media.MediaRouteProvider);
+    method public void addRemoteControlClient(java.lang.Object);
+    method public android.support.v7.media.MediaRouter.RouteInfo getBluetoothRoute();
+    method public android.support.v7.media.MediaRouter.RouteInfo getDefaultRoute();
+    method public static android.support.v7.media.MediaRouter getInstance(android.content.Context);
+    method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSessionToken();
+    method public java.util.List<android.support.v7.media.MediaRouter.ProviderInfo> getProviders();
+    method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+    method public android.support.v7.media.MediaRouter.RouteInfo getSelectedRoute();
+    method public boolean isRouteAvailable(android.support.v7.media.MediaRouteSelector, int);
+    method public void removeCallback(android.support.v7.media.MediaRouter.Callback);
+    method public void removeProvider(android.support.v7.media.MediaRouteProvider);
+    method public void removeRemoteControlClient(java.lang.Object);
+    method public void selectRoute(android.support.v7.media.MediaRouter.RouteInfo);
+    method public void setMediaSession(java.lang.Object);
+    method public void setMediaSessionCompat(android.support.v4.media.session.MediaSessionCompat);
+    method public void unselect(int);
+    method public android.support.v7.media.MediaRouter.RouteInfo updateSelectedRoute(android.support.v7.media.MediaRouteSelector);
+    field public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1; // 0x1
+    field public static final int AVAILABILITY_FLAG_REQUIRE_MATCH = 2; // 0x2
+    field public static final int CALLBACK_FLAG_FORCE_DISCOVERY = 8; // 0x8
+    field public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1; // 0x1
+    field public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 4; // 0x4
+    field public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 2; // 0x2
+    field public static final int UNSELECT_REASON_DISCONNECTED = 1; // 0x1
+    field public static final int UNSELECT_REASON_ROUTE_CHANGED = 3; // 0x3
+    field public static final int UNSELECT_REASON_STOPPED = 2; // 0x2
+    field public static final int UNSELECT_REASON_UNKNOWN = 0; // 0x0
+  }
+
+  public static abstract class MediaRouter.Callback {
+    ctor public MediaRouter.Callback();
+    method public void onProviderAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onProviderChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onProviderRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onRouteAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRoutePresentationDisplayChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteSelected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo, int);
+    method public void onRouteVolumeChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+  }
+
+  public static abstract class MediaRouter.ControlRequestCallback {
+    ctor public MediaRouter.ControlRequestCallback();
+    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onResult(android.os.Bundle);
+  }
+
+  public static final class MediaRouter.ProviderInfo {
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getPackageName();
+    method public android.support.v7.media.MediaRouteProvider getProviderInstance();
+    method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+  }
+
+  public static class MediaRouter.RouteInfo {
+    method public boolean canDisconnect();
+    method public int getConnectionState();
+    method public java.util.List<android.content.IntentFilter> getControlFilters();
+    method public java.lang.String getDescription();
+    method public int getDeviceType();
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getIconUri();
+    method public java.lang.String getId();
+    method public java.lang.String getName();
+    method public int getPlaybackStream();
+    method public int getPlaybackType();
+    method public android.view.Display getPresentationDisplay();
+    method public android.support.v7.media.MediaRouter.ProviderInfo getProvider();
+    method public android.content.IntentSender getSettingsIntent();
+    method public int getVolume();
+    method public int getVolumeHandling();
+    method public int getVolumeMax();
+    method public boolean isBluetooth();
+    method public boolean isConnecting();
+    method public boolean isDefault();
+    method public boolean isDeviceSpeaker();
+    method public boolean isEnabled();
+    method public boolean isSelected();
+    method public boolean matchesSelector(android.support.v7.media.MediaRouteSelector);
+    method public void requestSetVolume(int);
+    method public void requestUpdateVolume(int);
+    method public void select();
+    method public void sendControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+    method public boolean supportsControlAction(java.lang.String, java.lang.String);
+    method public boolean supportsControlCategory(java.lang.String);
+    method public boolean supportsControlRequest(android.content.Intent);
+    field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+    field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+    field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+    field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+    field public static final int DEVICE_TYPE_TV = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
+    field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
+    field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
+    field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1
+  }
+
+  public final class MediaSessionStatus {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaSessionStatus fromBundle(android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public int getSessionState();
+    method public long getTimestamp();
+    method public boolean isQueuePaused();
+    field public static final int SESSION_STATE_ACTIVE = 0; // 0x0
+    field public static final int SESSION_STATE_ENDED = 1; // 0x1
+    field public static final int SESSION_STATE_INVALIDATED = 2; // 0x2
+  }
+
+  public static final class MediaSessionStatus.Builder {
+    ctor public MediaSessionStatus.Builder(int);
+    ctor public MediaSessionStatus.Builder(android.support.v7.media.MediaSessionStatus);
+    method public android.support.v7.media.MediaSessionStatus build();
+    method public android.support.v7.media.MediaSessionStatus.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaSessionStatus.Builder setQueuePaused(boolean);
+    method public android.support.v7.media.MediaSessionStatus.Builder setSessionState(int);
+    method public android.support.v7.media.MediaSessionStatus.Builder setTimestamp(long);
+  }
+
+  public class RemotePlaybackClient {
+    ctor public RemotePlaybackClient(android.content.Context, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void endSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void enqueue(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public java.lang.String getSessionId();
+    method public void getSessionStatus(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void getStatus(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public boolean hasSession();
+    method public boolean isMessagingSupported();
+    method public boolean isQueuingSupported();
+    method public boolean isRemotePlaybackSupported();
+    method public boolean isSessionManagementSupported();
+    method public void pause(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void play(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void release();
+    method public void remove(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void resume(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void seek(java.lang.String, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void sendMessage(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void setOnMessageReceivedListener(android.support.v7.media.RemotePlaybackClient.OnMessageReceivedListener);
+    method public void setSessionId(java.lang.String);
+    method public void setStatusCallback(android.support.v7.media.RemotePlaybackClient.StatusCallback);
+    method public void startSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void stop(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+  }
+
+  public static abstract class RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.ActionCallback();
+    method public void onError(java.lang.String, int, android.os.Bundle);
+  }
+
+  public static abstract class RemotePlaybackClient.ItemActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.ItemActionCallback();
+    method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+  }
+
+  public static abstract interface RemotePlaybackClient.OnMessageReceivedListener {
+    method public abstract void onMessageReceived(java.lang.String, android.os.Bundle);
+  }
+
+  public static abstract class RemotePlaybackClient.SessionActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.SessionActionCallback();
+    method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+  }
+
+  public static abstract class RemotePlaybackClient.StatusCallback {
+    ctor public RemotePlaybackClient.StatusCallback();
+    method public void onItemStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+    method public void onSessionChanged(java.lang.String);
+    method public void onSessionStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+  }
+
+}
+
+package android.support.v7.preference {
+
+  public class CheckBoxPreference extends android.support.v7.preference.TwoStatePreference {
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
+    ctor public CheckBoxPreference(android.content.Context);
+  }
+
+  public abstract class DialogPreference extends android.support.v7.preference.Preference {
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet);
+    ctor public DialogPreference(android.content.Context);
+    method public android.graphics.drawable.Drawable getDialogIcon();
+    method public int getDialogLayoutResource();
+    method public java.lang.CharSequence getDialogMessage();
+    method public java.lang.CharSequence getDialogTitle();
+    method public java.lang.CharSequence getNegativeButtonText();
+    method public java.lang.CharSequence getPositiveButtonText();
+    method public void setDialogIcon(android.graphics.drawable.Drawable);
+    method public void setDialogIcon(int);
+    method public void setDialogLayoutResource(int);
+    method public void setDialogMessage(java.lang.CharSequence);
+    method public void setDialogMessage(int);
+    method public void setDialogTitle(java.lang.CharSequence);
+    method public void setDialogTitle(int);
+    method public void setNegativeButtonText(java.lang.CharSequence);
+    method public void setNegativeButtonText(int);
+    method public void setPositiveButtonText(java.lang.CharSequence);
+    method public void setPositiveButtonText(int);
+  }
+
+  public static abstract interface DialogPreference.TargetFragment {
+    method public abstract android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+  }
+
+  public class DropDownPreference extends android.support.v7.preference.ListPreference {
+    ctor public DropDownPreference(android.content.Context);
+    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet);
+    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet, int, int);
+    method protected android.widget.ArrayAdapter createAdapter();
+  }
+
+  public class EditTextPreference extends android.support.v7.preference.DialogPreference {
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet);
+    ctor public EditTextPreference(android.content.Context);
+    method public java.lang.String getText();
+    method public void setText(java.lang.String);
+  }
+
+  public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public EditTextPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class ListPreference extends android.support.v7.preference.DialogPreference {
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet);
+    ctor public ListPreference(android.content.Context);
+    method public int findIndexOfValue(java.lang.String);
+    method public java.lang.CharSequence[] getEntries();
+    method public java.lang.CharSequence getEntry();
+    method public java.lang.CharSequence[] getEntryValues();
+    method public java.lang.String getValue();
+    method public void setEntries(java.lang.CharSequence[]);
+    method public void setEntries(int);
+    method public void setEntryValues(java.lang.CharSequence[]);
+    method public void setEntryValues(int);
+    method public void setValue(java.lang.String);
+    method public void setValueIndex(int);
+  }
+
+  public class ListPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public ListPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.ListPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class MultiSelectListPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public MultiSelectListPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class Preference implements java.lang.Comparable {
+    ctor public Preference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public Preference(android.content.Context, android.util.AttributeSet, int);
+    ctor public Preference(android.content.Context, android.util.AttributeSet);
+    ctor public Preference(android.content.Context);
+    method public boolean callChangeListener(java.lang.Object);
+    method public int compareTo(android.support.v7.preference.Preference);
+    method protected android.support.v7.preference.Preference findPreferenceInHierarchy(java.lang.String);
+    method public android.content.Context getContext();
+    method public java.lang.String getDependency();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getFragment();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.String getKey();
+    method public final int getLayoutResource();
+    method public android.support.v7.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
+    method public android.support.v7.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
+    method public int getOrder();
+    method protected boolean getPersistedBoolean(boolean);
+    method protected float getPersistedFloat(float);
+    method protected int getPersistedInt(int);
+    method protected long getPersistedLong(long);
+    method protected java.lang.String getPersistedString(java.lang.String);
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.content.SharedPreferences getSharedPreferences();
+    method public boolean getShouldDisableView();
+    method public java.lang.CharSequence getSummary();
+    method public java.lang.CharSequence getTitle();
+    method public final int getWidgetLayoutResource();
+    method public boolean hasKey();
+    method public boolean isEnabled();
+    method public boolean isPersistent();
+    method public boolean isSelectable();
+    method public final boolean isVisible();
+    method protected void notifyChanged();
+    method public void notifyDependencyChange(boolean);
+    method protected void notifyHierarchyChanged();
+    method public void onAttached();
+    method protected void onAttachedToHierarchy(android.support.v7.preference.PreferenceManager);
+    method public void onBindViewHolder(android.support.v7.preference.PreferenceViewHolder);
+    method protected void onClick();
+    method public void onDependencyChanged(android.support.v7.preference.Preference, boolean);
+    method public void onDetached();
+    method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
+    method public void onInitializeAccessibilityNodeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onParentChanged(android.support.v7.preference.Preference, boolean);
+    method protected void onPrepareForRemoval();
+    method protected void onRestoreInstanceState(android.os.Parcelable);
+    method protected android.os.Parcelable onSaveInstanceState();
+    method protected void onSetInitialValue(boolean, java.lang.Object);
+    method public android.os.Bundle peekExtras();
+    method protected boolean persistBoolean(boolean);
+    method protected boolean persistFloat(float);
+    method protected boolean persistInt(int);
+    method protected boolean persistLong(long);
+    method protected boolean persistString(java.lang.String);
+    method public void restoreHierarchyState(android.os.Bundle);
+    method public void saveHierarchyState(android.os.Bundle);
+    method public void setDefaultValue(java.lang.Object);
+    method public void setDependency(java.lang.String);
+    method public void setEnabled(boolean);
+    method public void setFragment(java.lang.String);
+    method public void setIcon(android.graphics.drawable.Drawable);
+    method public void setIcon(int);
+    method public void setIntent(android.content.Intent);
+    method public void setKey(java.lang.String);
+    method public void setLayoutResource(int);
+    method public void setOnPreferenceChangeListener(android.support.v7.preference.Preference.OnPreferenceChangeListener);
+    method public void setOnPreferenceClickListener(android.support.v7.preference.Preference.OnPreferenceClickListener);
+    method public void setOrder(int);
+    method public void setPersistent(boolean);
+    method public void setSelectable(boolean);
+    method public void setShouldDisableView(boolean);
+    method public void setSummary(java.lang.CharSequence);
+    method public void setSummary(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitle(int);
+    method public void setViewId(int);
+    method public final void setVisible(boolean);
+    method public void setWidgetLayoutResource(int);
+    method public boolean shouldDisableDependents();
+    method protected boolean shouldPersist();
+    field public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
+  }
+
+  public static class Preference.BaseSavedState extends android.view.AbsSavedState {
+    ctor public Preference.BaseSavedState(android.os.Parcel);
+    ctor public Preference.BaseSavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v7.preference.Preference.BaseSavedState> CREATOR;
+  }
+
+  public static abstract interface Preference.OnPreferenceChangeListener {
+    method public abstract boolean onPreferenceChange(android.support.v7.preference.Preference, java.lang.Object);
+  }
+
+  public static abstract interface Preference.OnPreferenceClickListener {
+    method public abstract boolean onPreferenceClick(android.support.v7.preference.Preference);
+  }
+
+  public class PreferenceCategory extends android.support.v7.preference.PreferenceGroup {
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet);
+    ctor public PreferenceCategory(android.content.Context);
+  }
+
+  public abstract class PreferenceDialogFragmentCompat extends android.support.v4.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+    ctor public PreferenceDialogFragmentCompat();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    method protected void onBindDialogView(android.view.View);
+    method public void onClick(android.content.DialogInterface, int);
+    method protected android.view.View onCreateDialogView(android.content.Context);
+    method public abstract void onDialogClosed(boolean);
+    method protected void onPrepareDialogBuilder(android.support.v7.app.AlertDialog.Builder);
+    field protected static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class PreferenceFragmentCompat extends android.support.v4.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+    ctor public PreferenceFragmentCompat();
+    method public void addPreferencesFromResource(int);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public final android.support.v7.widget.RecyclerView getListView();
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void scrollToPreference(java.lang.String);
+    method public void scrollToPreference(android.support.v7.preference.Preference);
+    method public void setDivider(android.graphics.drawable.Drawable);
+    method public void setDividerHeight(int);
+    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+    method public void setPreferencesFromResource(int, java.lang.String);
+    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
+    method public abstract boolean onPreferenceDisplayDialog(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+    method public abstract boolean onPreferenceStartFragment(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
+    method public abstract boolean onPreferenceStartScreen(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.PreferenceScreen);
+  }
+
+  public abstract class PreferenceGroup extends android.support.v7.preference.Preference {
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet);
+    method public void addItemFromInflater(android.support.v7.preference.Preference);
+    method public boolean addPreference(android.support.v7.preference.Preference);
+    method protected void dispatchRestoreInstanceState(android.os.Bundle);
+    method protected void dispatchSaveInstanceState(android.os.Bundle);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public android.support.v7.preference.Preference getPreference(int);
+    method public int getPreferenceCount();
+    method protected boolean isOnSameScreenAsChildren();
+    method public boolean isOrderingAsAdded();
+    method protected boolean onPrepareAddPreference(android.support.v7.preference.Preference);
+    method public void removeAll();
+    method public boolean removePreference(android.support.v7.preference.Preference);
+    method public void setOrderingAsAdded(boolean);
+  }
+
+  public static abstract interface PreferenceGroup.PreferencePositionCallback {
+    method public abstract int getPreferenceAdapterPosition(java.lang.String);
+    method public abstract int getPreferenceAdapterPosition(android.support.v7.preference.Preference);
+  }
+
+  public class PreferenceManager {
+    method public android.support.v7.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public android.content.Context getContext();
+    method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
+    method public android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener();
+    method public android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener getOnNavigateToScreenListener();
+    method public android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener getOnPreferenceTreeClickListener();
+    method public android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback getPreferenceComparisonCallback();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method public android.content.SharedPreferences getSharedPreferences();
+    method public int getSharedPreferencesMode();
+    method public java.lang.String getSharedPreferencesName();
+    method public boolean isStorageDefault();
+    method public boolean isStorageDeviceProtected();
+    method public static void setDefaultValues(android.content.Context, int, boolean);
+    method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+    method public void setOnDisplayPreferenceDialogListener(android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener);
+    method public void setOnNavigateToScreenListener(android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener);
+    method public void setOnPreferenceTreeClickListener(android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener);
+    method public void setPreferenceComparisonCallback(android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback);
+    method public boolean setPreferences(android.support.v7.preference.PreferenceScreen);
+    method public void setSharedPreferencesMode(int);
+    method public void setSharedPreferencesName(java.lang.String);
+    method public void setStorageDefault();
+    method public void setStorageDeviceProtected();
+    method public void showDialog(android.support.v7.preference.Preference);
+    field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
+  }
+
+  public static abstract interface PreferenceManager.OnDisplayPreferenceDialogListener {
+    method public abstract void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceManager.OnNavigateToScreenListener {
+    method public abstract void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+  }
+
+  public static abstract interface PreferenceManager.OnPreferenceTreeClickListener {
+    method public abstract boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+  }
+
+  public static abstract class PreferenceManager.PreferenceComparisonCallback {
+    ctor public PreferenceManager.PreferenceComparisonCallback();
+    method public abstract boolean arePreferenceContentsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+    method public abstract boolean arePreferenceItemsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+  }
+
+  public static class PreferenceManager.SimplePreferenceComparisonCallback extends android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback {
+    ctor public PreferenceManager.SimplePreferenceComparisonCallback();
+    method public boolean arePreferenceContentsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+    method public boolean arePreferenceItemsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+  }
+
+  public final class PreferenceScreen extends android.support.v7.preference.PreferenceGroup {
+    method public void setShouldUseGeneratedIds(boolean);
+    method public boolean shouldUseGeneratedIds();
+  }
+
+  public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
+    method public android.view.View findViewById(int);
+    method public boolean isDividerAllowedAbove();
+    method public boolean isDividerAllowedBelow();
+    method public void setDividerAllowedAbove(boolean);
+    method public void setDividerAllowedBelow(boolean);
+  }
+
+  public class SeekBarPreference extends android.support.v7.preference.Preference {
+    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet);
+    ctor public SeekBarPreference(android.content.Context);
+    method public int getMax();
+    method public int getMin();
+    method public final int getSeekBarIncrement();
+    method public int getValue();
+    method public boolean isAdjustable();
+    method public void setAdjustable(boolean);
+    method public final void setMax(int);
+    method public void setMin(int);
+    method public final void setSeekBarIncrement(int);
+    method public void setValue(int);
+  }
+
+  public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchPreferenceCompat(android.content.Context);
+    method public java.lang.CharSequence getSwitchTextOff();
+    method public java.lang.CharSequence getSwitchTextOn();
+    method public void setSwitchTextOff(java.lang.CharSequence);
+    method public void setSwitchTextOff(int);
+    method public void setSwitchTextOn(java.lang.CharSequence);
+    method public void setSwitchTextOn(int);
+  }
+
+  public abstract class TwoStatePreference extends android.support.v7.preference.Preference {
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet);
+    ctor public TwoStatePreference(android.content.Context);
+    method public boolean getDisableDependentsState();
+    method public java.lang.CharSequence getSummaryOff();
+    method public java.lang.CharSequence getSummaryOn();
+    method public boolean isChecked();
+    method public void setChecked(boolean);
+    method public void setDisableDependentsState(boolean);
+    method public void setSummaryOff(java.lang.CharSequence);
+    method public void setSummaryOff(int);
+    method public void setSummaryOn(java.lang.CharSequence);
+    method public void setSummaryOn(int);
+    method protected void syncSummaryView(android.support.v7.preference.PreferenceViewHolder);
+    field protected boolean mChecked;
+  }
+
+}
+
+package android.support.v7.util {
+
+  public class AsyncListUtil<T> {
+    ctor public AsyncListUtil(java.lang.Class<T>, int, android.support.v7.util.AsyncListUtil.DataCallback<T>, android.support.v7.util.AsyncListUtil.ViewCallback);
+    method public T getItem(int);
+    method public int getItemCount();
+    method public void onRangeChanged();
+    method public void refresh();
+  }
+
+  public static abstract class AsyncListUtil.DataCallback<T> {
+    ctor public AsyncListUtil.DataCallback();
+    method public abstract void fillData(T[], int, int);
+    method public int getMaxCachedTiles();
+    method public void recycleData(T[], int);
+    method public abstract int refreshData();
+  }
+
+  public static abstract class AsyncListUtil.ViewCallback {
+    ctor public AsyncListUtil.ViewCallback();
+    method public void extendRangeInto(int[], int[], int);
+    method public abstract void getItemRangeInto(int[]);
+    method public abstract void onDataRefresh();
+    method public abstract void onItemLoaded(int);
+    field public static final int HINT_SCROLL_ASC = 2; // 0x2
+    field public static final int HINT_SCROLL_DESC = 1; // 0x1
+    field public static final int HINT_SCROLL_NONE = 0; // 0x0
+  }
+
+  public class BatchingListUpdateCallback implements android.support.v7.util.ListUpdateCallback {
+    ctor public BatchingListUpdateCallback(android.support.v7.util.ListUpdateCallback);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int, java.lang.Object);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public class DiffUtil {
+    method public static android.support.v7.util.DiffUtil.DiffResult calculateDiff(android.support.v7.util.DiffUtil.Callback);
+    method public static android.support.v7.util.DiffUtil.DiffResult calculateDiff(android.support.v7.util.DiffUtil.Callback, boolean);
+  }
+
+  public static abstract class DiffUtil.Callback {
+    ctor public DiffUtil.Callback();
+    method public abstract boolean areContentsTheSame(int, int);
+    method public abstract boolean areItemsTheSame(int, int);
+    method public java.lang.Object getChangePayload(int, int);
+    method public abstract int getNewListSize();
+    method public abstract int getOldListSize();
+  }
+
+  public static class DiffUtil.DiffResult {
+    method public void dispatchUpdatesTo(android.support.v7.widget.RecyclerView.Adapter);
+    method public void dispatchUpdatesTo(android.support.v7.util.ListUpdateCallback);
+  }
+
+  public abstract interface ListUpdateCallback {
+    method public abstract void onChanged(int, int, java.lang.Object);
+    method public abstract void onInserted(int, int);
+    method public abstract void onMoved(int, int);
+    method public abstract void onRemoved(int, int);
+  }
+
+  public class SortedList<T> {
+    ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>);
+    ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>, int);
+    method public int add(T);
+    method public void addAll(T[], boolean);
+    method public void addAll(T...);
+    method public void addAll(java.util.Collection<T>);
+    method public void beginBatchedUpdates();
+    method public void clear();
+    method public void endBatchedUpdates();
+    method public T get(int) throws java.lang.IndexOutOfBoundsException;
+    method public int indexOf(T);
+    method public void recalculatePositionOfItemAt(int);
+    method public boolean remove(T);
+    method public T removeItemAt(int);
+    method public int size();
+    method public void updateItemAt(int, T);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class SortedList.BatchedCallback<T2> extends android.support.v7.util.SortedList.Callback {
+    ctor public SortedList.BatchedCallback(android.support.v7.util.SortedList.Callback<T2>);
+    method public boolean areContentsTheSame(T2, T2);
+    method public boolean areItemsTheSame(T2, T2);
+    method public int compare(T2, T2);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public static abstract class SortedList.Callback<T2> implements java.util.Comparator android.support.v7.util.ListUpdateCallback {
+    ctor public SortedList.Callback();
+    method public abstract boolean areContentsTheSame(T2, T2);
+    method public abstract boolean areItemsTheSame(T2, T2);
+    method public abstract int compare(T2, T2);
+    method public abstract void onChanged(int, int);
+    method public void onChanged(int, int, java.lang.Object);
+  }
+
+}
+
+package android.support.v7.view {
+
+  public abstract class ActionMode {
+    ctor public ActionMode();
+    method public abstract void finish();
+    method public abstract android.view.View getCustomView();
+    method public abstract android.view.Menu getMenu();
+    method public abstract android.view.MenuInflater getMenuInflater();
+    method public abstract java.lang.CharSequence getSubtitle();
+    method public java.lang.Object getTag();
+    method public abstract java.lang.CharSequence getTitle();
+    method public boolean getTitleOptionalHint();
+    method public abstract void invalidate();
+    method public boolean isTitleOptional();
+    method public abstract void setCustomView(android.view.View);
+    method public abstract void setSubtitle(java.lang.CharSequence);
+    method public abstract void setSubtitle(int);
+    method public void setTag(java.lang.Object);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract void setTitle(int);
+    method public void setTitleOptionalHint(boolean);
+  }
+
+  public static abstract interface ActionMode.Callback {
+    method public abstract boolean onActionItemClicked(android.support.v7.view.ActionMode, android.view.MenuItem);
+    method public abstract boolean onCreateActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+    method public abstract void onDestroyActionMode(android.support.v7.view.ActionMode);
+    method public abstract boolean onPrepareActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+  }
+
+  public abstract interface CollapsibleActionView {
+    method public abstract void onActionViewCollapsed();
+    method public abstract void onActionViewExpanded();
+  }
+
+}
+
+package android.support.v7.widget {
+
+  public class ActionMenuView extends android.support.v7.widget.LinearLayoutCompat {
+    ctor public ActionMenuView(android.content.Context);
+    ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
+    method public void dismissPopupMenus();
+    method public android.view.Menu getMenu();
+    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method public int getPopupTheme();
+    method public boolean hideOverflowMenu();
+    method public boolean isOverflowMenuShowing();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDetachedFromWindow();
+    method public void setOnMenuItemClickListener(android.support.v7.widget.ActionMenuView.OnMenuItemClickListener);
+    method public void setOverflowIcon(android.graphics.drawable.Drawable);
+    method public void setPopupTheme(int);
+    method public boolean showOverflowMenu();
+  }
+
+  public static class ActionMenuView.LayoutParams extends android.support.v7.widget.LinearLayoutCompat.LayoutParams {
+    ctor public ActionMenuView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionMenuView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public ActionMenuView.LayoutParams(android.support.v7.widget.ActionMenuView.LayoutParams);
+    ctor public ActionMenuView.LayoutParams(int, int);
+    field public int cellsUsed;
+    field public boolean expandable;
+    field public int extraPixels;
+    field public boolean isOverflowButton;
+    field public boolean preventEdgeOffset;
+  }
+
+  public static abstract interface ActionMenuView.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public class AppCompatAutoCompleteTextView extends android.widget.AutoCompleteTextView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatAutoCompleteTextView(android.content.Context);
+    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatButton extends android.widget.Button implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatButton(android.content.Context);
+    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet, int);
+    method public void setSupportAllCaps(boolean);
+  }
+
+  public class AppCompatCheckBox extends android.widget.CheckBox implements android.support.v4.widget.TintableCompoundButton {
+    ctor public AppCompatCheckBox(android.content.Context);
+    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
+    ctor public AppCompatCheckedTextView(android.content.Context);
+    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatEditText extends android.widget.EditText implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatEditText(android.content.Context);
+    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageButton extends android.widget.ImageButton implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatImageButton(android.content.Context);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageView extends android.widget.ImageView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatImageView(android.content.Context);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatRadioButton extends android.widget.RadioButton implements android.support.v4.widget.TintableCompoundButton {
+    ctor public AppCompatRadioButton(android.content.Context);
+    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatRatingBar extends android.widget.RatingBar {
+    ctor public AppCompatRatingBar(android.content.Context);
+    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatSeekBar extends android.widget.SeekBar {
+    ctor public AppCompatSeekBar(android.content.Context);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatSpinner extends android.widget.Spinner implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatSpinner(android.content.Context);
+    ctor public AppCompatSpinner(android.content.Context, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
+  }
+
+  public class AppCompatTextView extends android.widget.TextView implements android.support.v4.view.TintableBackgroundView {
+    ctor public AppCompatTextView(android.content.Context);
+    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class CardView extends android.widget.FrameLayout {
+    ctor public CardView(android.content.Context);
+    ctor public CardView(android.content.Context, android.util.AttributeSet);
+    ctor public CardView(android.content.Context, android.util.AttributeSet, int);
+    method public android.content.res.ColorStateList getCardBackgroundColor();
+    method public float getCardElevation();
+    method public int getContentPaddingBottom();
+    method public int getContentPaddingLeft();
+    method public int getContentPaddingRight();
+    method public int getContentPaddingTop();
+    method public float getMaxCardElevation();
+    method public boolean getPreventCornerOverlap();
+    method public float getRadius();
+    method public boolean getUseCompatPadding();
+    method public void setCardBackgroundColor(int);
+    method public void setCardBackgroundColor(android.content.res.ColorStateList);
+    method public void setCardElevation(float);
+    method public void setContentPadding(int, int, int, int);
+    method public void setMaxCardElevation(float);
+    method public void setPreventCornerOverlap(boolean);
+    method public void setRadius(float);
+    method public void setUseCompatPadding(boolean);
+  }
+
+  public class DefaultItemAnimator extends android.support.v7.widget.SimpleItemAnimator {
+    ctor public DefaultItemAnimator();
+    method public boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void endAnimations();
+    method public boolean isRunning();
+    method public void runPendingAnimations();
+  }
+
+  public class DividerItemDecoration extends android.support.v7.widget.RecyclerView.ItemDecoration {
+    ctor public DividerItemDecoration(android.content.Context, int);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class GridLayout extends android.view.ViewGroup {
+    ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
+    ctor public GridLayout(android.content.Context, android.util.AttributeSet);
+    ctor public GridLayout(android.content.Context);
+    method public int getAlignmentMode();
+    method public int getColumnCount();
+    method public int getOrientation();
+    method public android.util.Printer getPrinter();
+    method public int getRowCount();
+    method public boolean getUseDefaultMargins();
+    method public boolean isColumnOrderPreserved();
+    method public boolean isRowOrderPreserved();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setAlignmentMode(int);
+    method public void setColumnCount(int);
+    method public void setColumnOrderPreserved(boolean);
+    method public void setOrientation(int);
+    method public void setPrinter(android.util.Printer);
+    method public void setRowCount(int);
+    method public void setRowOrderPreserved(boolean);
+    method public void setUseDefaultMargins(boolean);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int, android.support.v7.widget.GridLayout.Alignment, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, android.support.v7.widget.GridLayout.Alignment, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, float);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int, android.support.v7.widget.GridLayout.Alignment);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, android.support.v7.widget.GridLayout.Alignment);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int, int);
+    method public static android.support.v7.widget.GridLayout.Spec spec(int);
+    field public static final int ALIGN_BOUNDS = 0; // 0x0
+    field public static final int ALIGN_MARGINS = 1; // 0x1
+    field public static final android.support.v7.widget.GridLayout.Alignment BASELINE;
+    field public static final android.support.v7.widget.GridLayout.Alignment BOTTOM;
+    field public static final android.support.v7.widget.GridLayout.Alignment CENTER;
+    field public static final android.support.v7.widget.GridLayout.Alignment END;
+    field public static final android.support.v7.widget.GridLayout.Alignment FILL;
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final android.support.v7.widget.GridLayout.Alignment LEFT;
+    field public static final android.support.v7.widget.GridLayout.Alignment RIGHT;
+    field public static final android.support.v7.widget.GridLayout.Alignment START;
+    field public static final android.support.v7.widget.GridLayout.Alignment TOP;
+    field public static final int UNDEFINED = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static abstract class GridLayout.Alignment {
+  }
+
+  public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public GridLayout.LayoutParams(android.support.v7.widget.GridLayout.Spec, android.support.v7.widget.GridLayout.Spec);
+    ctor public GridLayout.LayoutParams();
+    ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public GridLayout.LayoutParams(android.support.v7.widget.GridLayout.LayoutParams);
+    ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    method public void setGravity(int);
+    field public android.support.v7.widget.GridLayout.Spec columnSpec;
+    field public android.support.v7.widget.GridLayout.Spec rowSpec;
+  }
+
+  public static class GridLayout.Spec {
+    method public android.support.v7.widget.GridLayout.Alignment getAbsoluteAlignment(boolean);
+  }
+
+  public class GridLayoutManager extends android.support.v7.widget.LinearLayoutManager {
+    ctor public GridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public GridLayoutManager(android.content.Context, int);
+    ctor public GridLayoutManager(android.content.Context, int, int, boolean);
+    method public int getSpanCount();
+    method public android.support.v7.widget.GridLayoutManager.SpanSizeLookup getSpanSizeLookup();
+    method public void setSpanCount(int);
+    method public void setSpanSizeLookup(android.support.v7.widget.GridLayoutManager.SpanSizeLookup);
+    field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
+  }
+
+  public static final class GridLayoutManager.DefaultSpanSizeLookup extends android.support.v7.widget.GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.DefaultSpanSizeLookup();
+    method public int getSpanSize(int);
+  }
+
+  public static class GridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+    ctor public GridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public GridLayoutManager.LayoutParams(int, int);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public GridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public int getSpanIndex();
+    method public int getSpanSize();
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public static abstract class GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.SpanSizeLookup();
+    method public int getSpanGroupIndex(int, int);
+    method public int getSpanIndex(int, int);
+    method public abstract int getSpanSize(int);
+    method public void invalidateSpanIndexCache();
+    method public boolean isSpanIndexCacheEnabled();
+    method public void setSpanIndexCacheEnabled(boolean);
+  }
+
+  public class LinearLayoutCompat extends android.view.ViewGroup {
+    ctor public LinearLayoutCompat(android.content.Context);
+    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet);
+    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet, int);
+    method public int getBaselineAlignedChildIndex();
+    method public android.graphics.drawable.Drawable getDividerDrawable();
+    method public int getDividerPadding();
+    method public int getGravity();
+    method public int getOrientation();
+    method public int getShowDividers();
+    method public float getWeightSum();
+    method public boolean isBaselineAligned();
+    method public boolean isMeasureWithLargestChildEnabled();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setBaselineAligned(boolean);
+    method public void setBaselineAlignedChildIndex(int);
+    method public void setDividerDrawable(android.graphics.drawable.Drawable);
+    method public void setDividerPadding(int);
+    method public void setGravity(int);
+    method public void setHorizontalGravity(int);
+    method public void setMeasureWithLargestChildEnabled(boolean);
+    method public void setOrientation(int);
+    method public void setShowDividers(int);
+    method public void setVerticalGravity(int);
+    method public void setWeightSum(float);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int SHOW_DIVIDER_BEGINNING = 1; // 0x1
+    field public static final int SHOW_DIVIDER_END = 4; // 0x4
+    field public static final int SHOW_DIVIDER_MIDDLE = 2; // 0x2
+    field public static final int SHOW_DIVIDER_NONE = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class LinearLayoutCompat.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public LinearLayoutCompat.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public LinearLayoutCompat.LayoutParams(int, int);
+    ctor public LinearLayoutCompat.LayoutParams(int, int, float);
+    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public LinearLayoutCompat.LayoutParams(android.support.v7.widget.LinearLayoutCompat.LayoutParams);
+    field public int gravity;
+    field public float weight;
+  }
+
+  public class LinearLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager implements android.support.v7.widget.helper.ItemTouchHelper.ViewDropHandler android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public LinearLayoutManager(android.content.Context);
+    ctor public LinearLayoutManager(android.content.Context, int, boolean);
+    ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
+    method public int findFirstCompletelyVisibleItemPosition();
+    method public int findFirstVisibleItemPosition();
+    method public int findLastCompletelyVisibleItemPosition();
+    method public int findLastVisibleItemPosition();
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method protected int getExtraLayoutSpace(android.support.v7.widget.RecyclerView.State);
+    method public int getInitialItemPrefetchCount();
+    method public int getOrientation();
+    method public boolean getRecycleChildrenOnDetach();
+    method public boolean getReverseLayout();
+    method public boolean getStackFromEnd();
+    method protected boolean isLayoutRTL();
+    method public boolean isSmoothScrollbarEnabled();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setInitialPrefetchItemCount(int);
+    method public void setOrientation(int);
+    method public void setRecycleChildrenOnDetach(boolean);
+    method public void setReverseLayout(boolean);
+    method public void setSmoothScrollbarEnabled(boolean);
+    method public void setStackFromEnd(boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  protected static class LinearLayoutManager.LayoutChunkResult {
+    ctor protected LinearLayoutManager.LayoutChunkResult();
+    field public int mConsumed;
+    field public boolean mFinished;
+    field public boolean mFocusable;
+    field public boolean mIgnoreConsumed;
+  }
+
+  public class LinearSmoothScroller extends android.support.v7.widget.RecyclerView.SmoothScroller {
+    ctor public LinearSmoothScroller(android.content.Context);
+    method public int calculateDtToFit(int, int, int, int, int);
+    method public int calculateDxToMakeVisible(android.view.View, int);
+    method public int calculateDyToMakeVisible(android.view.View, int);
+    method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
+    method protected int calculateTimeForDeceleration(int);
+    method protected int calculateTimeForScrolling(int);
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
+    method protected int getHorizontalSnapPreference();
+    method protected int getVerticalSnapPreference();
+    method protected void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected void onStart();
+    method protected void onStop();
+    method protected void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected void updateActionForInterimTarget(android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    field public static final int SNAP_TO_ANY = 0; // 0x0
+    field public static final int SNAP_TO_END = 1; // 0x1
+    field public static final int SNAP_TO_START = -1; // 0xffffffff
+    field protected final android.view.animation.DecelerateInterpolator mDecelerateInterpolator;
+    field protected int mInterimTargetDx;
+    field protected int mInterimTargetDy;
+    field protected final android.view.animation.LinearInterpolator mLinearInterpolator;
+    field protected android.graphics.PointF mTargetVector;
+  }
+
+  public class LinearSnapHelper extends android.support.v7.widget.SnapHelper {
+    ctor public LinearSnapHelper();
+    method public int[] calculateDistanceToFinalSnap(android.support.v7.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View findSnapView(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public int findTargetSnapPosition(android.support.v7.widget.RecyclerView.LayoutManager, int, int);
+  }
+
+  public class ListPopupWindow {
+    ctor public ListPopupWindow(android.content.Context);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int, int);
+    method public void clearListSelection();
+    method public android.view.View.OnTouchListener createDragToOpenListener(android.view.View);
+    method public void dismiss();
+    method public android.view.View getAnchorView();
+    method public int getAnimationStyle();
+    method public android.graphics.drawable.Drawable getBackground();
+    method public int getHeight();
+    method public int getHorizontalOffset();
+    method public int getInputMethodMode();
+    method public android.widget.ListView getListView();
+    method public int getPromptPosition();
+    method public java.lang.Object getSelectedItem();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public android.view.View getSelectedView();
+    method public int getSoftInputMode();
+    method public int getVerticalOffset();
+    method public int getWidth();
+    method public boolean isInputMethodNotNeeded();
+    method public boolean isModal();
+    method public boolean isShowing();
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyPreIme(int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public boolean performItemClick(int);
+    method public void postShow();
+    method public void setAdapter(android.widget.ListAdapter);
+    method public void setAnchorView(android.view.View);
+    method public void setAnimationStyle(int);
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setContentWidth(int);
+    method public void setDropDownGravity(int);
+    method public void setHeight(int);
+    method public void setHorizontalOffset(int);
+    method public void setInputMethodMode(int);
+    method public void setListSelector(android.graphics.drawable.Drawable);
+    method public void setModal(boolean);
+    method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
+    method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
+    method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public void setPromptPosition(int);
+    method public void setPromptView(android.view.View);
+    method public void setSelection(int);
+    method public void setSoftInputMode(int);
+    method public void setVerticalOffset(int);
+    method public void setWidth(int);
+    method public void setWindowLayoutType(int);
+    method public void show();
+    field public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; // 0x0
+    field public static final int INPUT_METHOD_NEEDED = 1; // 0x1
+    field public static final int INPUT_METHOD_NOT_NEEDED = 2; // 0x2
+    field public static final int MATCH_PARENT = -1; // 0xffffffff
+    field public static final int POSITION_PROMPT_ABOVE = 0; // 0x0
+    field public static final int POSITION_PROMPT_BELOW = 1; // 0x1
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public abstract class OrientationHelper {
+    method public static android.support.v7.widget.OrientationHelper createHorizontalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public static android.support.v7.widget.OrientationHelper createOrientationHelper(android.support.v7.widget.RecyclerView.LayoutManager, int);
+    method public static android.support.v7.widget.OrientationHelper createVerticalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public abstract int getDecoratedEnd(android.view.View);
+    method public abstract int getDecoratedMeasurement(android.view.View);
+    method public abstract int getDecoratedMeasurementInOther(android.view.View);
+    method public abstract int getDecoratedStart(android.view.View);
+    method public abstract int getEnd();
+    method public abstract int getEndAfterPadding();
+    method public abstract int getEndPadding();
+    method public abstract int getMode();
+    method public abstract int getModeInOther();
+    method public abstract int getStartAfterPadding();
+    method public abstract int getTotalSpace();
+    method public int getTotalSpaceChange();
+    method public abstract int getTransformedEndWithDecoration(android.view.View);
+    method public abstract int getTransformedStartWithDecoration(android.view.View);
+    method public abstract void offsetChild(android.view.View, int);
+    method public abstract void offsetChildren(int);
+    method public void onLayoutComplete();
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field protected final android.support.v7.widget.RecyclerView.LayoutManager mLayoutManager;
+  }
+
+  public class PagerSnapHelper extends android.support.v7.widget.SnapHelper {
+    ctor public PagerSnapHelper();
+    method public int[] calculateDistanceToFinalSnap(android.support.v7.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View findSnapView(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public int findTargetSnapPosition(android.support.v7.widget.RecyclerView.LayoutManager, int, int);
+  }
+
+  public class PopupMenu {
+    ctor public PopupMenu(android.content.Context, android.view.View);
+    ctor public PopupMenu(android.content.Context, android.view.View, int);
+    ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
+    method public void dismiss();
+    method public android.view.View.OnTouchListener getDragToOpenListener();
+    method public int getGravity();
+    method public android.view.Menu getMenu();
+    method public android.view.MenuInflater getMenuInflater();
+    method public void inflate(int);
+    method public void setGravity(int);
+    method public void setOnDismissListener(android.support.v7.widget.PopupMenu.OnDismissListener);
+    method public void setOnMenuItemClickListener(android.support.v7.widget.PopupMenu.OnMenuItemClickListener);
+    method public void show();
+  }
+
+  public static abstract interface PopupMenu.OnDismissListener {
+    method public abstract void onDismiss(android.support.v7.widget.PopupMenu);
+  }
+
+  public static abstract interface PopupMenu.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public class RecyclerView extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.ScrollingView {
+    ctor public RecyclerView(android.content.Context);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet, int);
+    method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration, int);
+    method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+    method public void addOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void addOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+    method public void addOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void clearOnChildAttachStateChangeListeners();
+    method public void clearOnScrollListeners();
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+    method public boolean drawChild(android.graphics.Canvas, android.view.View, long);
+    method public android.view.View findChildViewUnder(float, float);
+    method public android.view.View findContainingItemView(android.view.View);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findContainingViewHolder(android.view.View);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForAdapterPosition(int);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForItemId(long);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForLayoutPosition(int);
+    method public deprecated android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForPosition(int);
+    method public boolean fling(int, int);
+    method public android.support.v7.widget.RecyclerView.Adapter getAdapter();
+    method public int getChildAdapterPosition(android.view.View);
+    method public long getChildItemId(android.view.View);
+    method public int getChildLayoutPosition(android.view.View);
+    method public deprecated int getChildPosition(android.view.View);
+    method public android.support.v7.widget.RecyclerView.ViewHolder getChildViewHolder(android.view.View);
+    method public android.support.v7.widget.RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate();
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator getItemAnimator();
+    method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+    method public int getMaxFlingVelocity();
+    method public int getMinFlingVelocity();
+    method public android.support.v7.widget.RecyclerView.OnFlingListener getOnFlingListener();
+    method public boolean getPreserveFocusAfterLayout();
+    method public android.support.v7.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
+    method public int getScrollState();
+    method public boolean hasFixedSize();
+    method public boolean hasPendingAdapterUpdates();
+    method public void invalidateItemDecorations();
+    method public boolean isAnimating();
+    method public boolean isComputingLayout();
+    method public boolean isLayoutFrozen();
+    method public void offsetChildrenHorizontal(int);
+    method public void offsetChildrenVertical(int);
+    method public void onChildAttachedToWindow(android.view.View);
+    method public void onChildDetachedFromWindow(android.view.View);
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onScrollStateChanged(int);
+    method public void onScrolled(int, int);
+    method public void removeItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+    method public void removeOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void removeOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+    method public void removeOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void scrollToPosition(int);
+    method public void setAccessibilityDelegateCompat(android.support.v7.widget.RecyclerViewAccessibilityDelegate);
+    method public void setAdapter(android.support.v7.widget.RecyclerView.Adapter);
+    method public void setChildDrawingOrderCallback(android.support.v7.widget.RecyclerView.ChildDrawingOrderCallback);
+    method public void setHasFixedSize(boolean);
+    method public void setItemAnimator(android.support.v7.widget.RecyclerView.ItemAnimator);
+    method public void setItemViewCacheSize(int);
+    method public void setLayoutFrozen(boolean);
+    method public void setLayoutManager(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public void setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener);
+    method public deprecated void setOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void setPreserveFocusAfterLayout(boolean);
+    method public void setRecycledViewPool(android.support.v7.widget.RecyclerView.RecycledViewPool);
+    method public void setRecyclerListener(android.support.v7.widget.RecyclerView.RecyclerListener);
+    method public void setScrollingTouchSlop(int);
+    method public void setViewCacheExtension(android.support.v7.widget.RecyclerView.ViewCacheExtension);
+    method public void smoothScrollBy(int, int);
+    method public void smoothScrollBy(int, int, android.view.animation.Interpolator);
+    method public void smoothScrollToPosition(int);
+    method public void stopScroll();
+    method public void swapAdapter(android.support.v7.widget.RecyclerView.Adapter, boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_TYPE = -1; // 0xffffffff
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+    field public static final int NO_POSITION = -1; // 0xffffffff
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+    field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
+    field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static abstract class RecyclerView.Adapter<VH extends android.support.v7.widget.RecyclerView.ViewHolder> {
+    ctor public RecyclerView.Adapter();
+    method public final void bindViewHolder(VH, int);
+    method public final VH createViewHolder(android.view.ViewGroup, int);
+    method public abstract int getItemCount();
+    method public long getItemId(int);
+    method public int getItemViewType(int);
+    method public final boolean hasObservers();
+    method public final boolean hasStableIds();
+    method public final void notifyDataSetChanged();
+    method public final void notifyItemChanged(int);
+    method public final void notifyItemChanged(int, java.lang.Object);
+    method public final void notifyItemInserted(int);
+    method public final void notifyItemMoved(int, int);
+    method public final void notifyItemRangeChanged(int, int);
+    method public final void notifyItemRangeChanged(int, int, java.lang.Object);
+    method public final void notifyItemRangeInserted(int, int);
+    method public final void notifyItemRangeRemoved(int, int);
+    method public final void notifyItemRemoved(int);
+    method public void onAttachedToRecyclerView(android.support.v7.widget.RecyclerView);
+    method public abstract void onBindViewHolder(VH, int);
+    method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object>);
+    method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDetachedFromRecyclerView(android.support.v7.widget.RecyclerView);
+    method public boolean onFailedToRecycleView(VH);
+    method public void onViewAttachedToWindow(VH);
+    method public void onViewDetachedFromWindow(VH);
+    method public void onViewRecycled(VH);
+    method public void registerAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+    method public void setHasStableIds(boolean);
+    method public void unregisterAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+  }
+
+  public static abstract class RecyclerView.AdapterDataObserver {
+    ctor public RecyclerView.AdapterDataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeChanged(int, int, java.lang.Object);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeMoved(int, int, int);
+    method public void onItemRangeRemoved(int, int);
+  }
+
+  public static abstract interface RecyclerView.ChildDrawingOrderCallback {
+    method public abstract int onGetChildDrawingOrder(int, int);
+  }
+
+  public static abstract class RecyclerView.ItemAnimator {
+    ctor public RecyclerView.ItemAnimator();
+    method public abstract boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, java.util.List<java.lang.Object>);
+    method public final void dispatchAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationsFinished();
+    method public abstract void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public abstract void endAnimations();
+    method public long getAddDuration();
+    method public long getChangeDuration();
+    method public long getMoveDuration();
+    method public long getRemoveDuration();
+    method public abstract boolean isRunning();
+    method public final boolean isRunning(android.support.v7.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+    method public void onAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder, int, java.util.List<java.lang.Object>);
+    method public abstract void runPendingAnimations();
+    method public void setAddDuration(long);
+    method public void setChangeDuration(long);
+    method public void setMoveDuration(long);
+    method public void setRemoveDuration(long);
+    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+    field public static final int FLAG_CHANGED = 2; // 0x2
+    field public static final int FLAG_INVALIDATED = 4; // 0x4
+    field public static final int FLAG_MOVED = 2048; // 0x800
+    field public static final int FLAG_REMOVED = 8; // 0x8
+  }
+
+  public static abstract class RecyclerView.ItemAnimator.AdapterChanges implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
+    method public abstract void onAnimationsFinished();
+  }
+
+  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    field public int bottom;
+    field public int changeFlags;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public static abstract class RecyclerView.ItemDecoration {
+    ctor public RecyclerView.ItemDecoration();
+    method public deprecated void getItemOffsets(android.graphics.Rect, int, android.support.v7.widget.RecyclerView);
+    method public void getItemOffsets(android.graphics.Rect, android.view.View, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public deprecated void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+    method public void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public deprecated void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+  }
+
+  public static abstract class RecyclerView.LayoutManager {
+    ctor public RecyclerView.LayoutManager();
+    method public void addDisappearingView(android.view.View);
+    method public void addDisappearingView(android.view.View, int);
+    method public void addView(android.view.View);
+    method public void addView(android.view.View, int);
+    method public void assertInLayoutOrScroll(java.lang.String);
+    method public void assertNotInLayoutOrScroll(java.lang.String);
+    method public void attachView(android.view.View, int, android.support.v7.widget.RecyclerView.LayoutParams);
+    method public void attachView(android.view.View, int);
+    method public void attachView(android.view.View);
+    method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
+    method public boolean canScrollHorizontally();
+    method public boolean canScrollVertically();
+    method public boolean checkLayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public static int chooseSize(int, int, int);
+    method public void collectAdjacentPrefetchPositions(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public void collectInitialPrefetchPositions(int, android.support.v7.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public int computeHorizontalScrollExtent(android.support.v7.widget.RecyclerView.State);
+    method public int computeHorizontalScrollOffset(android.support.v7.widget.RecyclerView.State);
+    method public int computeHorizontalScrollRange(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollExtent(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollOffset(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollRange(android.support.v7.widget.RecyclerView.State);
+    method public void detachAndScrapAttachedViews(android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachAndScrapView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachAndScrapViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachView(android.view.View);
+    method public void detachViewAt(int);
+    method public void endAnimation(android.view.View);
+    method public android.view.View findContainingItemView(android.view.View);
+    method public android.view.View findViewByPosition(int);
+    method public abstract android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.content.Context, android.util.AttributeSet);
+    method public int getBaseline();
+    method public int getBottomDecorationHeight(android.view.View);
+    method public android.view.View getChildAt(int);
+    method public int getChildCount();
+    method public static deprecated int getChildMeasureSpec(int, int, int, boolean);
+    method public static int getChildMeasureSpec(int, int, int, int, boolean);
+    method public boolean getClipToPadding();
+    method public int getColumnCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getDecoratedBottom(android.view.View);
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public int getDecoratedLeft(android.view.View);
+    method public int getDecoratedMeasuredHeight(android.view.View);
+    method public int getDecoratedMeasuredWidth(android.view.View);
+    method public int getDecoratedRight(android.view.View);
+    method public int getDecoratedTop(android.view.View);
+    method public android.view.View getFocusedChild();
+    method public int getHeight();
+    method public int getHeightMode();
+    method public int getItemCount();
+    method public int getItemViewType(android.view.View);
+    method public int getLayoutDirection();
+    method public int getLeftDecorationWidth(android.view.View);
+    method public int getMinimumHeight();
+    method public int getMinimumWidth();
+    method public int getPaddingBottom();
+    method public int getPaddingEnd();
+    method public int getPaddingLeft();
+    method public int getPaddingRight();
+    method public int getPaddingStart();
+    method public int getPaddingTop();
+    method public int getPosition(android.view.View);
+    method public static android.support.v7.widget.RecyclerView.LayoutManager.Properties getProperties(android.content.Context, android.util.AttributeSet, int, int);
+    method public int getRightDecorationWidth(android.view.View);
+    method public int getRowCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getSelectionModeForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getTopDecorationHeight(android.view.View);
+    method public void getTransformedBoundingBox(android.view.View, boolean, android.graphics.Rect);
+    method public int getWidth();
+    method public int getWidthMode();
+    method public boolean hasFocus();
+    method public void ignoreView(android.view.View);
+    method public boolean isAttachedToWindow();
+    method public boolean isAutoMeasureEnabled();
+    method public boolean isFocused();
+    method public final boolean isItemPrefetchEnabled();
+    method public boolean isLayoutHierarchical(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public boolean isMeasurementCacheEnabled();
+    method public boolean isSmoothScrolling();
+    method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
+    method public void layoutDecorated(android.view.View, int, int, int, int);
+    method public void layoutDecoratedWithMargins(android.view.View, int, int, int, int);
+    method public void measureChild(android.view.View, int, int);
+    method public void measureChildWithMargins(android.view.View, int, int);
+    method public void moveView(int, int);
+    method public void offsetChildrenHorizontal(int);
+    method public void offsetChildrenVertical(int);
+    method public void onAdapterChanged(android.support.v7.widget.RecyclerView.Adapter, android.support.v7.widget.RecyclerView.Adapter);
+    method public boolean onAddFocusables(android.support.v7.widget.RecyclerView, java.util.ArrayList<android.view.View>, int, int);
+    method public void onAttachedToWindow(android.support.v7.widget.RecyclerView);
+    method public deprecated void onDetachedFromWindow(android.support.v7.widget.RecyclerView);
+    method public void onDetachedFromWindow(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.Recycler);
+    method public android.view.View onFocusSearchFailed(android.view.View, int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onInitializeAccessibilityNodeInfoForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public android.view.View onInterceptFocusSearch(android.view.View, int);
+    method public void onItemsAdded(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsChanged(android.support.v7.widget.RecyclerView);
+    method public void onItemsMoved(android.support.v7.widget.RecyclerView, int, int, int);
+    method public void onItemsRemoved(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int, java.lang.Object);
+    method public void onLayoutChildren(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void onLayoutCompleted(android.support.v7.widget.RecyclerView.State);
+    method public void onMeasure(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, int);
+    method public deprecated boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.view.View, android.view.View);
+    method public boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, android.view.View, android.view.View);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void onScrollStateChanged(int);
+    method public boolean performAccessibilityAction(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, android.os.Bundle);
+    method public boolean performAccessibilityActionForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, int, android.os.Bundle);
+    method public void postOnAnimation(java.lang.Runnable);
+    method public void removeAllViews();
+    method public void removeAndRecycleAllViews(android.support.v7.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+    method public boolean removeCallbacks(java.lang.Runnable);
+    method public void removeDetachedView(android.view.View);
+    method public void removeView(android.view.View);
+    method public void removeViewAt(int);
+    method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
+    method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean, boolean);
+    method public void requestLayout();
+    method public void requestSimpleAnimationsInNextLayout();
+    method public int scrollHorizontallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void scrollToPosition(int);
+    method public int scrollVerticallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void setAutoMeasureEnabled(boolean);
+    method public final void setItemPrefetchEnabled(boolean);
+    method public void setMeasuredDimension(android.graphics.Rect, int, int);
+    method public void setMeasuredDimension(int, int);
+    method public void setMeasurementCacheEnabled(boolean);
+    method public void smoothScrollToPosition(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, int);
+    method public void startSmoothScroll(android.support.v7.widget.RecyclerView.SmoothScroller);
+    method public void stopIgnoringView(android.view.View);
+    method public boolean supportsPredictiveItemAnimations();
+  }
+
+  public static abstract interface RecyclerView.LayoutManager.LayoutPrefetchRegistry {
+    method public abstract void addPosition(int, int);
+  }
+
+  public static class RecyclerView.LayoutManager.Properties {
+    ctor public RecyclerView.LayoutManager.Properties();
+    field public int orientation;
+    field public boolean reverseLayout;
+    field public int spanCount;
+    field public boolean stackFromEnd;
+  }
+
+  public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public RecyclerView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public RecyclerView.LayoutParams(int, int);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public RecyclerView.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public int getViewAdapterPosition();
+    method public int getViewLayoutPosition();
+    method public deprecated int getViewPosition();
+    method public boolean isItemChanged();
+    method public boolean isItemRemoved();
+    method public boolean isViewInvalid();
+    method public boolean viewNeedsUpdate();
+  }
+
+  public static abstract interface RecyclerView.OnChildAttachStateChangeListener {
+    method public abstract void onChildViewAttachedToWindow(android.view.View);
+    method public abstract void onChildViewDetachedFromWindow(android.view.View);
+  }
+
+  public static abstract class RecyclerView.OnFlingListener {
+    ctor public RecyclerView.OnFlingListener();
+    method public abstract boolean onFling(int, int);
+  }
+
+  public static abstract interface RecyclerView.OnItemTouchListener {
+    method public abstract boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+    method public abstract void onRequestDisallowInterceptTouchEvent(boolean);
+    method public abstract void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public static abstract class RecyclerView.OnScrollListener {
+    ctor public RecyclerView.OnScrollListener();
+    method public void onScrollStateChanged(android.support.v7.widget.RecyclerView, int);
+    method public void onScrolled(android.support.v7.widget.RecyclerView, int, int);
+  }
+
+  public static class RecyclerView.RecycledViewPool {
+    ctor public RecyclerView.RecycledViewPool();
+    method public void clear();
+    method public android.support.v7.widget.RecyclerView.ViewHolder getRecycledView(int);
+    method public int getRecycledViewCount(int);
+    method public void putRecycledView(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setMaxRecycledViews(int, int);
+  }
+
+  public final class RecyclerView.Recycler {
+    ctor public RecyclerView.Recycler();
+    method public void bindViewToPosition(android.view.View, int);
+    method public void clear();
+    method public int convertPreLayoutPositionToPostLayout(int);
+    method public java.util.List<android.support.v7.widget.RecyclerView.ViewHolder> getScrapList();
+    method public android.view.View getViewForPosition(int);
+    method public void recycleView(android.view.View);
+    method public void setViewCacheSize(int);
+  }
+
+  public static abstract interface RecyclerView.RecyclerListener {
+    method public abstract void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+  }
+
+  public static class RecyclerView.SimpleOnItemTouchListener implements android.support.v7.widget.RecyclerView.OnItemTouchListener {
+    ctor public RecyclerView.SimpleOnItemTouchListener();
+    method public boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public static abstract class RecyclerView.SmoothScroller {
+    ctor public RecyclerView.SmoothScroller();
+    method public android.view.View findViewByPosition(int);
+    method public int getChildCount();
+    method public int getChildPosition(android.view.View);
+    method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+    method public int getTargetPosition();
+    method public deprecated void instantScrollToPosition(int);
+    method public boolean isPendingInitialRun();
+    method public boolean isRunning();
+    method protected void normalize(android.graphics.PointF);
+    method protected void onChildAttachedToWindow(android.view.View);
+    method protected abstract void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected abstract void onStart();
+    method protected abstract void onStop();
+    method protected abstract void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method public void setTargetPosition(int);
+    method protected final void stop();
+  }
+
+  public static class RecyclerView.SmoothScroller.Action {
+    ctor public RecyclerView.SmoothScroller.Action(int, int);
+    ctor public RecyclerView.SmoothScroller.Action(int, int, int);
+    ctor public RecyclerView.SmoothScroller.Action(int, int, int, android.view.animation.Interpolator);
+    method public int getDuration();
+    method public int getDx();
+    method public int getDy();
+    method public android.view.animation.Interpolator getInterpolator();
+    method public void jumpTo(int);
+    method public void setDuration(int);
+    method public void setDx(int);
+    method public void setDy(int);
+    method public void setInterpolator(android.view.animation.Interpolator);
+    method public void update(int, int, int, android.view.animation.Interpolator);
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+  }
+
+  public static abstract interface RecyclerView.SmoothScroller.ScrollVectorProvider {
+    method public abstract android.graphics.PointF computeScrollVectorForPosition(int);
+  }
+
+  public static class RecyclerView.State {
+    ctor public RecyclerView.State();
+    method public boolean didStructureChange();
+    method public <T> T get(int);
+    method public int getItemCount();
+    method public int getTargetScrollPosition();
+    method public boolean hasTargetScrollPosition();
+    method public boolean isMeasuring();
+    method public boolean isPreLayout();
+    method public void put(int, java.lang.Object);
+    method public void remove(int);
+    method public boolean willRunPredictiveAnimations();
+    method public boolean willRunSimpleAnimations();
+  }
+
+  public static abstract class RecyclerView.ViewCacheExtension {
+    ctor public RecyclerView.ViewCacheExtension();
+    method public abstract android.view.View getViewForPositionAndType(android.support.v7.widget.RecyclerView.Recycler, int, int);
+  }
+
+  public static abstract class RecyclerView.ViewHolder {
+    ctor public RecyclerView.ViewHolder(android.view.View);
+    method public final int getAdapterPosition();
+    method public final long getItemId();
+    method public final int getItemViewType();
+    method public final int getLayoutPosition();
+    method public final int getOldPosition();
+    method public final deprecated int getPosition();
+    method public final boolean isRecyclable();
+    method public final void setIsRecyclable(boolean);
+    field public final android.view.View itemView;
+  }
+
+  public class RecyclerViewAccessibilityDelegate extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate(android.support.v7.widget.RecyclerView);
+    method public android.support.v4.view.AccessibilityDelegateCompat getItemDelegate();
+  }
+
+  public static class RecyclerViewAccessibilityDelegate.ItemDelegate extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate.ItemDelegate(android.support.v7.widget.RecyclerViewAccessibilityDelegate);
+  }
+
+  public class SearchView extends android.support.v7.widget.LinearLayoutCompat implements android.support.v7.view.CollapsibleActionView {
+    ctor public SearchView(android.content.Context);
+    ctor public SearchView(android.content.Context, android.util.AttributeSet);
+    ctor public SearchView(android.content.Context, android.util.AttributeSet, int);
+    method public int getImeOptions();
+    method public int getInputType();
+    method public int getMaxWidth();
+    method public java.lang.CharSequence getQuery();
+    method public java.lang.CharSequence getQueryHint();
+    method public android.support.v4.widget.CursorAdapter getSuggestionsAdapter();
+    method public boolean isIconfiedByDefault();
+    method public boolean isIconified();
+    method public boolean isQueryRefinementEnabled();
+    method public boolean isSubmitButtonEnabled();
+    method public void onActionViewCollapsed();
+    method public void onActionViewExpanded();
+    method public void setIconified(boolean);
+    method public void setIconifiedByDefault(boolean);
+    method public void setImeOptions(int);
+    method public void setInputType(int);
+    method public void setMaxWidth(int);
+    method public void setOnCloseListener(android.support.v7.widget.SearchView.OnCloseListener);
+    method public void setOnQueryTextFocusChangeListener(android.view.View.OnFocusChangeListener);
+    method public void setOnQueryTextListener(android.support.v7.widget.SearchView.OnQueryTextListener);
+    method public void setOnSearchClickListener(android.view.View.OnClickListener);
+    method public void setOnSuggestionListener(android.support.v7.widget.SearchView.OnSuggestionListener);
+    method public void setQuery(java.lang.CharSequence, boolean);
+    method public void setQueryHint(java.lang.CharSequence);
+    method public void setQueryRefinementEnabled(boolean);
+    method public void setSearchableInfo(android.app.SearchableInfo);
+    method public void setSubmitButtonEnabled(boolean);
+    method public void setSuggestionsAdapter(android.support.v4.widget.CursorAdapter);
+  }
+
+  public static abstract interface SearchView.OnCloseListener {
+    method public abstract boolean onClose();
+  }
+
+  public static abstract interface SearchView.OnQueryTextListener {
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public static abstract interface SearchView.OnSuggestionListener {
+    method public abstract boolean onSuggestionClick(int);
+    method public abstract boolean onSuggestionSelect(int);
+  }
+
+  public class ShareActionProvider extends android.support.v4.view.ActionProvider {
+    ctor public ShareActionProvider(android.content.Context);
+    method public android.view.View onCreateActionView();
+    method public void setOnShareTargetSelectedListener(android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener);
+    method public void setShareHistoryFileName(java.lang.String);
+    method public void setShareIntent(android.content.Intent);
+    field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+  }
+
+  public static abstract interface ShareActionProvider.OnShareTargetSelectedListener {
+    method public abstract boolean onShareTargetSelected(android.support.v7.widget.ShareActionProvider, android.content.Intent);
+  }
+
+  public abstract class SimpleItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+    ctor public SimpleItemAnimator();
+    method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean getSupportsChangeAnimations();
+    method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setSupportsChangeAnimations(boolean);
+  }
+
+  public abstract class SnapHelper extends android.support.v7.widget.RecyclerView.OnFlingListener {
+    ctor public SnapHelper();
+    method public void attachToRecyclerView(android.support.v7.widget.RecyclerView) throws java.lang.IllegalStateException;
+    method public abstract int[] calculateDistanceToFinalSnap(android.support.v7.widget.RecyclerView.LayoutManager, android.view.View);
+    method public int[] calculateScrollDistance(int, int);
+    method protected android.support.v7.widget.LinearSmoothScroller createSnapScroller(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public abstract android.view.View findSnapView(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public abstract int findTargetSnapPosition(android.support.v7.widget.RecyclerView.LayoutManager, int, int);
+    method public boolean onFling(int, int);
+  }
+
+  public class StaggeredGridLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager implements android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public StaggeredGridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public StaggeredGridLayoutManager(int, int);
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
+    method public int[] findFirstCompletelyVisibleItemPositions(int[]);
+    method public int[] findFirstVisibleItemPositions(int[]);
+    method public int[] findLastCompletelyVisibleItemPositions(int[]);
+    method public int[] findLastVisibleItemPositions(int[]);
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public int getGapStrategy();
+    method public int getOrientation();
+    method public boolean getReverseLayout();
+    method public int getSpanCount();
+    method public void invalidateSpanAssignments();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setGapStrategy(int);
+    method public void setOrientation(int);
+    method public void setReverseLayout(boolean);
+    method public void setSpanCount(int);
+    field public static final deprecated int GAP_HANDLING_LAZY = 1; // 0x1
+    field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
+    field public static final int GAP_HANDLING_NONE = 0; // 0x0
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class StaggeredGridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public final int getSpanIndex();
+    method public boolean isFullSpan();
+    method public void setFullSpan(boolean);
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public class SwitchCompat extends android.widget.CompoundButton {
+    ctor public SwitchCompat(android.content.Context);
+    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet, int);
+    method public boolean getShowText();
+    method public boolean getSplitTrack();
+    method public int getSwitchMinWidth();
+    method public int getSwitchPadding();
+    method public java.lang.CharSequence getTextOff();
+    method public java.lang.CharSequence getTextOn();
+    method public android.graphics.drawable.Drawable getThumbDrawable();
+    method public int getThumbTextPadding();
+    method public android.content.res.ColorStateList getThumbTintList();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
+    method public android.graphics.drawable.Drawable getTrackDrawable();
+    method public android.content.res.ColorStateList getTrackTintList();
+    method public android.graphics.PorterDuff.Mode getTrackTintMode();
+    method public void onMeasure(int, int);
+    method public void setShowText(boolean);
+    method public void setSplitTrack(boolean);
+    method public void setSwitchMinWidth(int);
+    method public void setSwitchPadding(int);
+    method public void setSwitchTextAppearance(android.content.Context, int);
+    method public void setSwitchTypeface(android.graphics.Typeface, int);
+    method public void setSwitchTypeface(android.graphics.Typeface);
+    method public void setTextOff(java.lang.CharSequence);
+    method public void setTextOn(java.lang.CharSequence);
+    method public void setThumbDrawable(android.graphics.drawable.Drawable);
+    method public void setThumbResource(int);
+    method public void setThumbTextPadding(int);
+    method public void setThumbTintList(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTrackDrawable(android.graphics.drawable.Drawable);
+    method public void setTrackResource(int);
+    method public void setTrackTintList(android.content.res.ColorStateList);
+    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
+  }
+
+  public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
+    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
+  public static final class ThemedSpinnerAdapter.Helper {
+    ctor public ThemedSpinnerAdapter.Helper(android.content.Context);
+    method public android.view.LayoutInflater getDropDownViewInflater();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
+  public class Toolbar extends android.view.ViewGroup {
+    ctor public Toolbar(android.content.Context);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
+    method public void collapseActionView();
+    method public void dismissPopupMenus();
+    method public int getContentInsetEnd();
+    method public int getContentInsetEndWithActions();
+    method public int getContentInsetLeft();
+    method public int getContentInsetRight();
+    method public int getContentInsetStart();
+    method public int getContentInsetStartWithNavigation();
+    method public int getCurrentContentInsetEnd();
+    method public int getCurrentContentInsetLeft();
+    method public int getCurrentContentInsetRight();
+    method public int getCurrentContentInsetStart();
+    method public android.graphics.drawable.Drawable getLogo();
+    method public java.lang.CharSequence getLogoDescription();
+    method public android.view.Menu getMenu();
+    method public java.lang.CharSequence getNavigationContentDescription();
+    method public android.graphics.drawable.Drawable getNavigationIcon();
+    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method public int getPopupTheme();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public int getTitleMarginBottom();
+    method public int getTitleMarginEnd();
+    method public int getTitleMarginStart();
+    method public int getTitleMarginTop();
+    method public boolean hasExpandedActionView();
+    method public boolean hideOverflowMenu();
+    method public void inflateMenu(int);
+    method public boolean isOverflowMenuShowing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setContentInsetEndWithActions(int);
+    method public void setContentInsetStartWithNavigation(int);
+    method public void setContentInsetsAbsolute(int, int);
+    method public void setContentInsetsRelative(int, int);
+    method public void setLogo(int);
+    method public void setLogo(android.graphics.drawable.Drawable);
+    method public void setLogoDescription(int);
+    method public void setLogoDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(int);
+    method public void setNavigationContentDescription(java.lang.CharSequence);
+    method public void setNavigationIcon(int);
+    method public void setNavigationIcon(android.graphics.drawable.Drawable);
+    method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setOnMenuItemClickListener(android.support.v7.widget.Toolbar.OnMenuItemClickListener);
+    method public void setOverflowIcon(android.graphics.drawable.Drawable);
+    method public void setPopupTheme(int);
+    method public void setSubtitle(int);
+    method public void setSubtitle(java.lang.CharSequence);
+    method public void setSubtitleTextAppearance(android.content.Context, int);
+    method public void setSubtitleTextColor(int);
+    method public void setTitle(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleMargin(int, int, int, int);
+    method public void setTitleMarginBottom(int);
+    method public void setTitleMarginEnd(int);
+    method public void setTitleMarginStart(int);
+    method public void setTitleMarginTop(int);
+    method public void setTitleTextAppearance(android.content.Context, int);
+    method public void setTitleTextColor(int);
+    method public boolean showOverflowMenu();
+  }
+
+  public static class Toolbar.LayoutParams extends android.support.v7.app.ActionBar.LayoutParams {
+    ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar.LayoutParams(int, int);
+    ctor public Toolbar.LayoutParams(int, int, int);
+    ctor public Toolbar.LayoutParams(int);
+    ctor public Toolbar.LayoutParams(android.support.v7.widget.Toolbar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
+  }
+
+  public static abstract interface Toolbar.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public static class Toolbar.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public Toolbar.SavedState(android.os.Parcel);
+    ctor public Toolbar.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public Toolbar.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v7.widget.Toolbar.SavedState> CREATOR;
+  }
+
+}
+
+package android.support.v7.widget.helper {
+
+  public class ItemTouchHelper extends android.support.v7.widget.RecyclerView.ItemDecoration implements android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener {
+    ctor public ItemTouchHelper(android.support.v7.widget.helper.ItemTouchHelper.Callback);
+    method public void attachToRecyclerView(android.support.v7.widget.RecyclerView);
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+    method public void startDrag(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void startSwipe(android.support.v7.widget.RecyclerView.ViewHolder);
+    field public static final int ACTION_STATE_DRAG = 2; // 0x2
+    field public static final int ACTION_STATE_IDLE = 0; // 0x0
+    field public static final int ACTION_STATE_SWIPE = 1; // 0x1
+    field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
+    field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
+    field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
+    field public static final int DOWN = 2; // 0x2
+    field public static final int END = 32; // 0x20
+    field public static final int LEFT = 4; // 0x4
+    field public static final int RIGHT = 8; // 0x8
+    field public static final int START = 16; // 0x10
+    field public static final int UP = 1; // 0x1
+  }
+
+  public static abstract class ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.Callback();
+    method public boolean canDropOver(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ViewHolder chooseDropTarget(android.support.v7.widget.RecyclerView.ViewHolder, java.util.List<android.support.v7.widget.RecyclerView.ViewHolder>, int, int);
+    method public void clearView(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int convertToAbsoluteDirection(int, int);
+    method public static int convertToRelativeDirection(int, int);
+    method public long getAnimationDuration(android.support.v7.widget.RecyclerView, int, float, float);
+    method public int getBoundingBoxMargin();
+    method public static android.support.v7.widget.helper.ItemTouchUIUtil getDefaultUIUtil();
+    method public float getMoveThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public abstract int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public float getSwipeEscapeVelocity(float);
+    method public float getSwipeThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public float getSwipeVelocityThreshold(float);
+    method public int interpolateOutOfBoundsScroll(android.support.v7.widget.RecyclerView, int, int, int, long);
+    method public boolean isItemViewSwipeEnabled();
+    method public boolean isLongPressDragEnabled();
+    method public static int makeFlag(int, int);
+    method public static int makeMovementFlags(int, int);
+    method public void onChildDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public void onChildDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public abstract boolean onMove(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onMoved(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int);
+    method public void onSelectedChanged(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    method public abstract void onSwiped(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
+    field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
+  }
+
+  public static abstract class ItemTouchHelper.SimpleCallback extends android.support.v7.widget.helper.ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.SimpleCallback(int, int);
+    method public int getDragDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int getSwipeDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setDefaultDragDirs(int);
+    method public void setDefaultSwipeDirs(int);
+  }
+
+  public static abstract interface ItemTouchHelper.ViewDropHandler {
+    method public abstract void prepareForDrop(android.view.View, android.view.View, int, int);
+  }
+
+  public abstract interface ItemTouchUIUtil {
+    method public abstract void clearView(android.view.View);
+    method public abstract void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public abstract void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public abstract void onSelected(android.view.View);
+  }
+
+}
+
+package android.support.v7.widget.util {
+
+  public abstract class SortedListAdapterCallback<T2> extends android.support.v7.util.SortedList.Callback {
+    ctor public SortedListAdapterCallback(android.support.v7.widget.RecyclerView.Adapter);
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+}
+
+package android.support.wearable.view {
+
+  public class BoxInsetLayout extends android.view.ViewGroup {
+    ctor public BoxInsetLayout(android.content.Context);
+    ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet);
+    ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected void onLayout(boolean, int, int, int, int);
+  }
+
+  public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public BoxInsetLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public BoxInsetLayout.LayoutParams(int, int);
+    ctor public BoxInsetLayout.LayoutParams(int, int, int);
+    ctor public BoxInsetLayout.LayoutParams(int, int, int, int);
+    ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    ctor public BoxInsetLayout.LayoutParams(android.support.wearable.view.BoxInsetLayout.LayoutParams);
+    field public static final int BOX_ALL = 15; // 0xf
+    field public static final int BOX_BOTTOM = 8; // 0x8
+    field public static final int BOX_LEFT = 1; // 0x1
+    field public static final int BOX_NONE = 0; // 0x0
+    field public static final int BOX_RIGHT = 4; // 0x4
+    field public static final int BOX_TOP = 2; // 0x2
+    field public int boxedEdges;
+  }
+
+}
+
diff --git a/api/26.0.0.txt b/api/26.0.0.txt
index 3d77c5b..205400c 100644
--- a/api/26.0.0.txt
+++ b/api/26.0.0.txt
@@ -1,3 +1,75 @@
+package android.support.animation {
+
+  public abstract class DynamicAnimation<T extends android.support.animation.DynamicAnimation<T>> {
+    method public T addEndListener(android.support.animation.DynamicAnimation.OnAnimationEndListener);
+    method public T addUpdateListener(android.support.animation.DynamicAnimation.OnAnimationUpdateListener);
+    method public void cancel();
+    method public boolean isRunning();
+    method public void removeEndListener(android.support.animation.DynamicAnimation.OnAnimationEndListener);
+    method public void removeUpdateListener(android.support.animation.DynamicAnimation.OnAnimationUpdateListener);
+    method public T setMaxValue(float);
+    method public T setMinValue(float);
+    method public T setStartValue(float);
+    method public T setStartVelocity(float);
+    method public void start();
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ALPHA;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty ROTATION_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCALE_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCALE_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCROLL_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty SCROLL_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty TRANSLATION_Z;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty X;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty Y;
+    field public static final android.support.animation.DynamicAnimation.ViewProperty Z;
+  }
+
+  public static abstract interface DynamicAnimation.OnAnimationEndListener {
+    method public abstract void onAnimationEnd(android.support.animation.DynamicAnimation, boolean, float, float);
+  }
+
+  public static abstract interface DynamicAnimation.OnAnimationUpdateListener {
+    method public abstract void onAnimationUpdate(android.support.animation.DynamicAnimation, float, float);
+  }
+
+  public static abstract class DynamicAnimation.ViewProperty {
+  }
+
+  public final class SpringAnimation extends android.support.animation.DynamicAnimation {
+    ctor public SpringAnimation(android.view.View, android.support.animation.DynamicAnimation.ViewProperty);
+    ctor public SpringAnimation(android.view.View, android.support.animation.DynamicAnimation.ViewProperty, float);
+    method public void animateToFinalPosition(float);
+    method public boolean canSkipToEnd();
+    method public android.support.animation.SpringForce getSpring();
+    method public android.support.animation.SpringAnimation setSpring(android.support.animation.SpringForce);
+    method public void skipToEnd();
+  }
+
+  public final class SpringForce {
+    ctor public SpringForce();
+    ctor public SpringForce(float);
+    method public float getDampingRatio();
+    method public float getFinalPosition();
+    method public float getStiffness();
+    method public android.support.animation.SpringForce setDampingRatio(float);
+    method public android.support.animation.SpringForce setFinalPosition(float);
+    method public android.support.animation.SpringForce setStiffness(float);
+    field public static final float DAMPING_RATIO_HIGH_BOUNCY = 0.2f;
+    field public static final float DAMPING_RATIO_LOW_BOUNCY = 0.75f;
+    field public static final float DAMPING_RATIO_MEDIUM_BOUNCY = 0.5f;
+    field public static final float DAMPING_RATIO_NO_BOUNCY = 1.0f;
+    field public static final float STIFFNESS_HIGH = 10000.0f;
+    field public static final float STIFFNESS_LOW = 200.0f;
+    field public static final float STIFFNESS_MEDIUM = 1500.0f;
+    field public static final float STIFFNESS_VERY_LOW = 50.0f;
+  }
+
+}
+
 package android.support.app.recommendation {
 
   public final class ContentRecommendation {
@@ -869,16 +941,34 @@
 
 package android.support.graphics.drawable {
 
-  public class AnimatedVectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon {
+  public abstract interface Animatable2Compat {
+    method public abstract void clearAnimationCallbacks();
+    method public abstract void registerAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public abstract boolean unregisterAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+  }
+
+  public static abstract class Animatable2Compat.AnimationCallback {
+    ctor public Animatable2Compat.AnimationCallback();
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
+  }
+
+  public class AnimatedVectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon implements android.support.graphics.drawable.Animatable2Compat {
+    method public void clearAnimationCallbacks();
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable);
     method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat create(android.content.Context, int);
     method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
+    method public void registerAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable, android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void start();
     method public void stop();
+    method public boolean unregisterAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable, android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
   }
 
    abstract class VectorDrawableCommon extends android.graphics.drawable.Drawable {
@@ -1102,7 +1192,6 @@
     method public android.net.Uri getAppLinkIntentUri();
     method public android.net.Uri getAppLinkPosterArtUri();
     method public java.lang.String getAppLinkText();
-    method public java.lang.String getChannelLogo();
     method public java.lang.String getDescription();
     method public java.lang.String getDisplayName();
     method public java.lang.String getDisplayNumber();
@@ -1135,7 +1224,6 @@
     method public android.support.media.tv.Channel.Builder setAppLinkIntentUri(android.net.Uri);
     method public android.support.media.tv.Channel.Builder setAppLinkPosterArtUri(android.net.Uri);
     method public android.support.media.tv.Channel.Builder setAppLinkText(java.lang.String);
-    method public android.support.media.tv.Channel.Builder setChannelLogo(java.lang.String);
     method public android.support.media.tv.Channel.Builder setDescription(java.lang.String);
     method public android.support.media.tv.Channel.Builder setDisplayName(java.lang.String);
     method public android.support.media.tv.Channel.Builder setDisplayNumber(java.lang.String);
@@ -1148,7 +1236,6 @@
     method public android.support.media.tv.Channel.Builder setInternalProviderFlag4(long);
     method public android.support.media.tv.Channel.Builder setNetworkAffiliation(java.lang.String);
     method public android.support.media.tv.Channel.Builder setOriginalNetworkId(int);
-    method public android.support.media.tv.Channel.Builder setPackageName(java.lang.String);
     method public android.support.media.tv.Channel.Builder setSearchable(boolean);
     method public android.support.media.tv.Channel.Builder setServiceId(int);
     method public android.support.media.tv.Channel.Builder setServiceType(java.lang.String);
@@ -1589,12 +1676,25 @@
 
 package android.support.transition {
 
+  public class ArcMotion extends android.support.transition.PathMotion {
+    ctor public ArcMotion();
+    method public float getMaximumAngle();
+    method public float getMinimumHorizontalAngle();
+    method public float getMinimumVerticalAngle();
+    method public android.graphics.Path getPath(float, float, float, float);
+    method public void setMaximumAngle(float);
+    method public void setMinimumHorizontalAngle(float);
+    method public void setMinimumVerticalAngle(float);
+  }
+
   public class AutoTransition extends android.support.transition.TransitionSet {
     ctor public AutoTransition();
+    ctor public AutoTransition(android.content.Context, android.util.AttributeSet);
   }
 
   public class ChangeBounds extends android.support.transition.Transition {
     ctor public ChangeBounds();
+    ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
     method public void captureEndValues(android.support.transition.TransitionValues);
     method public void captureStartValues(android.support.transition.TransitionValues);
     method public void setResizeClip(boolean);
@@ -1603,10 +1703,24 @@
   public class Fade extends android.support.transition.Visibility {
     ctor public Fade(int);
     ctor public Fade();
+    ctor public Fade(android.content.Context, android.util.AttributeSet);
     field public static final int IN = 1; // 0x1
     field public static final int OUT = 2; // 0x2
   }
 
+  public abstract class PathMotion {
+    ctor public PathMotion();
+    method public abstract android.graphics.Path getPath(float, float, float, float);
+  }
+
+  public class PatternPathMotion extends android.support.transition.PathMotion {
+    ctor public PatternPathMotion();
+    ctor public PatternPathMotion(android.graphics.Path);
+    method public android.graphics.Path getPath(float, float, float, float);
+    method public android.graphics.Path getPatternPath();
+    method public void setPatternPath(android.graphics.Path);
+  }
+
   public class Scene {
     ctor public Scene(android.view.ViewGroup);
     ctor public Scene(android.view.ViewGroup, android.view.View);
@@ -1620,6 +1734,7 @@
 
   public abstract class Transition {
     ctor public Transition();
+    ctor public Transition(android.content.Context, android.util.AttributeSet);
     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);
@@ -1639,6 +1754,7 @@
     method public long getDuration();
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.lang.String getName();
+    method public android.support.transition.PathMotion getPathMotion();
     method public long getStartDelay();
     method public java.util.List<java.lang.Integer> getTargetIds();
     method public java.util.List<java.lang.String> getTargetNames();
@@ -1654,6 +1770,7 @@
     method public android.support.transition.Transition setDuration(long);
     method public android.support.transition.Transition setInterpolator(android.animation.TimeInterpolator);
     method public void setMatchOrder(int...);
+    method public void setPathMotion(android.support.transition.PathMotion);
     method public android.support.transition.Transition setStartDelay(long);
     field public static final int MATCH_ID = 3; // 0x3
     field public static final int MATCH_INSTANCE = 1; // 0x1
@@ -1669,6 +1786,12 @@
     method public abstract void onTransitionStart(android.support.transition.Transition);
   }
 
+  public class TransitionInflater {
+    method public static android.support.transition.TransitionInflater from(android.content.Context);
+    method public android.support.transition.Transition inflateTransition(int);
+    method public android.support.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
+  }
+
   public class TransitionManager {
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -1682,6 +1805,7 @@
 
   public class TransitionSet extends android.support.transition.Transition {
     ctor public TransitionSet();
+    ctor public TransitionSet(android.content.Context, android.util.AttributeSet);
     method public android.support.transition.TransitionSet addTransition(android.support.transition.Transition);
     method public void captureEndValues(android.support.transition.TransitionValues);
     method public void captureStartValues(android.support.transition.TransitionValues);
@@ -1702,11 +1826,18 @@
 
   public abstract class Visibility extends android.support.transition.Transition {
     ctor public Visibility();
+    ctor public Visibility(android.content.Context, android.util.AttributeSet);
     method public void captureEndValues(android.support.transition.TransitionValues);
     method public void captureStartValues(android.support.transition.TransitionValues);
+    method public int getMode();
     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 onAppear(android.view.ViewGroup, android.view.View, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
     method public android.animation.Animator onDisappear(android.view.ViewGroup, android.support.transition.TransitionValues, int, android.support.transition.TransitionValues, int);
+    method public android.animation.Animator onDisappear(android.view.ViewGroup, android.view.View, android.support.transition.TransitionValues, android.support.transition.TransitionValues);
+    method public void setMode(int);
+    field public static final int MODE_IN = 1; // 0x1
+    field public static final int MODE_OUT = 2; // 0x2
   }
 
 }
@@ -2892,10 +3023,7 @@
   public class BoundsRule {
     ctor public BoundsRule();
     ctor public BoundsRule(android.support.v17.leanback.graphics.BoundsRule);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
     method public void calculateBounds(android.graphics.Rect, android.graphics.Rect);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule bottom;
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule left;
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule right;
@@ -2903,8 +3031,11 @@
   }
 
   public static final class BoundsRule.ValueRule {
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
     method public int getAbsoluteValue();
     method public float getFraction();
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
     method public void setAbsoluteValue(int);
     method public void setFraction(float);
   }
@@ -4010,111 +4141,79 @@
 
   public abstract class Parallax<PropertyT extends android.util.Property> {
     ctor public Parallax();
-    method public void addEffect(android.support.v17.leanback.widget.ParallaxEffect);
-    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue...);
-    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue...);
-    method public abstract PropertyT addProperty(java.lang.String);
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
+    method public final PropertyT addProperty(java.lang.String);
     method public abstract PropertyT createProperty(java.lang.String, int);
     method public java.util.List<android.support.v17.leanback.widget.ParallaxEffect> getEffects();
+    method public abstract float getMaxValue();
     method public final java.util.List<PropertyT> getProperties();
     method public void removeAllEffects();
     method public void removeEffect(android.support.v17.leanback.widget.ParallaxEffect);
     method public void updateValues();
-    method public abstract void verifyProperties() throws java.lang.IllegalStateException;
-  }
-
-  public static abstract class Parallax.FloatParallax<FloatPropertyT extends android.support.v17.leanback.widget.Parallax.FloatProperty> extends android.support.v17.leanback.widget.Parallax {
-    ctor public Parallax.FloatParallax();
-    method public final FloatPropertyT addProperty(java.lang.String);
-    method public abstract float getMaxValue();
-    method public final float getPropertyValue(int);
-    method public final void setPropertyValue(int, float);
-    method public final void verifyProperties() throws java.lang.IllegalStateException;
   }
 
   public static class Parallax.FloatProperty extends android.util.Property {
     ctor public Parallax.FloatProperty(java.lang.String, int);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue at(float, float);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atAbsolute(float);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atFraction(float);
-    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax.FloatParallax);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(float, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax);
     method public final int getIndex();
-    method public final void set(android.support.v17.leanback.widget.Parallax.FloatParallax, java.lang.Float);
+    method public final float getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Float);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, float);
     field public static final float UNKNOWN_AFTER = 3.4028235E38f;
     field public static final float UNKNOWN_BEFORE = -3.4028235E38f;
   }
 
-  public static class Parallax.FloatPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
-    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float);
-    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float, float);
-    method public final float getMarkerValue(android.support.v17.leanback.widget.Parallax.FloatParallax);
-  }
-
-  public static abstract class Parallax.IntParallax<IntPropertyT extends android.support.v17.leanback.widget.Parallax.IntProperty> extends android.support.v17.leanback.widget.Parallax {
-    ctor public Parallax.IntParallax();
-    method public final IntPropertyT addProperty(java.lang.String);
-    method public abstract int getMaxValue();
-    method public final int getPropertyValue(int);
-    method public final void setPropertyValue(int, int);
-    method public final void verifyProperties() throws java.lang.IllegalStateException;
-  }
-
   public static class Parallax.IntProperty extends android.util.Property {
     ctor public Parallax.IntProperty(java.lang.String, int);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue at(int, float);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atAbsolute(int);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atFraction(float);
-    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax.IntParallax);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(int, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(int);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax);
     method public final int getIndex();
-    method public final void set(android.support.v17.leanback.widget.Parallax.IntParallax, java.lang.Integer);
+    method public final int getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Integer);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, int);
     field public static final int UNKNOWN_AFTER = 2147483647; // 0x7fffffff
     field public static final int UNKNOWN_BEFORE = -2147483648; // 0x80000000
   }
 
-  public static class Parallax.IntPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
-    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int);
-    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int, float);
-    method public final int getMarkerValue(android.support.v17.leanback.widget.Parallax.IntParallax);
-  }
-
   public static class Parallax.PropertyMarkerValue<PropertyT> {
     ctor public Parallax.PropertyMarkerValue(PropertyT);
     method public PropertyT getProperty();
   }
 
-  public abstract class ParallaxEffect<ParallaxEffectT extends android.support.v17.leanback.widget.ParallaxEffect, PropertyMarkerValueT extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> {
-    ctor public ParallaxEffect();
+  public abstract class ParallaxEffect {
     method public final void addTarget(android.support.v17.leanback.widget.ParallaxTarget);
-    method protected abstract float calculateFraction(android.support.v17.leanback.widget.Parallax);
-    method public final java.util.List<PropertyMarkerValueT> getPropertyRanges();
+    method public final java.util.List<android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> getPropertyRanges();
     method public final java.util.List<android.support.v17.leanback.widget.ParallaxTarget> getTargets();
     method public final void performMapping(android.support.v17.leanback.widget.Parallax);
     method public final void removeTarget(android.support.v17.leanback.widget.ParallaxTarget);
-    method public final void setPropertyRanges(PropertyMarkerValueT...);
+    method public final void setPropertyRanges(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
     method public final android.support.v17.leanback.widget.ParallaxEffect target(android.support.v17.leanback.widget.ParallaxTarget);
     method public final android.support.v17.leanback.widget.ParallaxEffect target(java.lang.Object, android.animation.PropertyValuesHolder);
-  }
-
-  public static final class ParallaxEffect.FloatEffect extends android.support.v17.leanback.widget.ParallaxEffect {
-    ctor public ParallaxEffect.FloatEffect();
-    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
-  }
-
-  public static final class ParallaxEffect.IntEffect extends android.support.v17.leanback.widget.ParallaxEffect {
-    ctor public ParallaxEffect.IntEffect();
-    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
+    method public final <T, V extends java.lang.Number> android.support.v17.leanback.widget.ParallaxEffect target(T, android.util.Property<T, V>);
   }
 
   public abstract class ParallaxTarget {
     ctor public ParallaxTarget();
-    method public abstract float getFraction();
-    method public abstract void update(float);
+    method public void directUpdate(java.lang.Number);
+    method public boolean isDirectMapping();
+    method public void update(float);
+  }
+
+  public static final class ParallaxTarget.DirectPropertyTarget<T, V extends java.lang.Number> extends android.support.v17.leanback.widget.ParallaxTarget {
+    ctor public ParallaxTarget.DirectPropertyTarget(java.lang.Object, android.util.Property<T, V>);
   }
 
   public static final class ParallaxTarget.PropertyValuesHolderTarget extends android.support.v17.leanback.widget.ParallaxTarget {
     ctor public ParallaxTarget.PropertyValuesHolderTarget(java.lang.Object, android.animation.PropertyValuesHolder);
-    method public float getFraction();
-    method public void update(float);
   }
 
   public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
@@ -4306,10 +4405,10 @@
     method public void unselect();
   }
 
-  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax.IntParallax {
+  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax {
     ctor public RecyclerViewParallax();
     method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty createProperty(java.lang.String, int);
-    method public int getMaxValue();
+    method public float getMaxValue();
     method public android.support.v7.widget.RecyclerView getRecyclerView();
     method public void setRecyclerView(android.support.v7.widget.RecyclerView);
   }
@@ -6034,6 +6133,13 @@
   }
 
   public class ShortcutInfoCompat {
+    method public android.content.ComponentName getActivity();
+    method public java.lang.CharSequence getDisabledMessage();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public android.content.Intent[] getIntents();
+    method public java.lang.CharSequence getLongLabel();
+    method public java.lang.CharSequence getShortLabel();
   }
 
   public static class ShortcutInfoCompat.Builder {
@@ -6050,7 +6156,6 @@
   }
 
   public class ShortcutManagerCompat {
-    ctor public ShortcutManagerCompat();
     method public static android.content.Intent createShortcutResultIntent(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat);
     method public static boolean isRequestPinShortcutSupported(android.content.Context);
     method public static boolean requestPinShortcut(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat, android.content.IntentSender);
@@ -7391,14 +7496,19 @@
     method public static deprecated boolean expandActionView(android.view.MenuItem);
     method public static android.support.v4.view.ActionProvider getActionProvider(android.view.MenuItem);
     method public static deprecated android.view.View getActionView(android.view.MenuItem);
+    method public int getAlphabeticModifiers(android.view.MenuItem);
     method public static java.lang.CharSequence getContentDescription(android.view.MenuItem);
+    method public int getNumericModifiers(android.view.MenuItem);
     method public static java.lang.CharSequence getTooltipText(android.view.MenuItem);
     method public static deprecated boolean isActionViewExpanded(android.view.MenuItem);
     method public static android.view.MenuItem setActionProvider(android.view.MenuItem, android.support.v4.view.ActionProvider);
     method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
     method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, int);
+    method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
     method public static void setContentDescription(android.view.MenuItem, java.lang.CharSequence);
+    method public static void setNumericShortcut(android.view.MenuItem, char, int);
     method public static deprecated android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
+    method public static void setShortcut(android.view.MenuItem, char, char, int, int);
     method public static deprecated void setShowAsAction(android.view.MenuItem, int);
     method public static void setTooltipText(android.view.MenuItem, java.lang.CharSequence);
     field public static final deprecated int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
@@ -9023,6 +9133,7 @@
     method public android.support.v7.graphics.drawable.DrawerArrowDrawable getDrawerArrowDrawable();
     method public android.view.View.OnClickListener getToolbarNavigationClickListener();
     method public boolean isDrawerIndicatorEnabled();
+    method public boolean isDrawerSlideAnimationEnabled();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDrawerClosed(android.view.View);
     method public void onDrawerOpened(android.view.View);
@@ -9031,6 +9142,7 @@
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable);
     method public void setDrawerIndicatorEnabled(boolean);
+    method public void setDrawerSlideAnimationEnabled(boolean);
     method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
     method public void setHomeAsUpIndicator(int);
     method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
@@ -10689,7 +10801,8 @@
     method public int findLastVisibleItemPosition();
     method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
     method protected int getExtraLayoutSpace(android.support.v7.widget.RecyclerView.State);
-    method public int getInitialItemPrefetchCount();
+    method public deprecated int getInitialItemPrefetchCount();
+    method public int getInitialPrefetchItemCount();
     method public int getOrientation();
     method public boolean getRecycleChildrenOnDetach();
     method public boolean getReverseLayout();
diff --git a/api/current.txt b/api/current.txt
index 83d059c..2990bd1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1192,7 +1192,6 @@
     method public android.net.Uri getAppLinkIntentUri();
     method public android.net.Uri getAppLinkPosterArtUri();
     method public java.lang.String getAppLinkText();
-    method public java.lang.String getChannelLogo();
     method public java.lang.String getDescription();
     method public java.lang.String getDisplayName();
     method public java.lang.String getDisplayNumber();
@@ -1225,7 +1224,6 @@
     method public android.support.media.tv.Channel.Builder setAppLinkIntentUri(android.net.Uri);
     method public android.support.media.tv.Channel.Builder setAppLinkPosterArtUri(android.net.Uri);
     method public android.support.media.tv.Channel.Builder setAppLinkText(java.lang.String);
-    method public android.support.media.tv.Channel.Builder setChannelLogo(java.lang.String);
     method public android.support.media.tv.Channel.Builder setDescription(java.lang.String);
     method public android.support.media.tv.Channel.Builder setDisplayName(java.lang.String);
     method public android.support.media.tv.Channel.Builder setDisplayNumber(java.lang.String);
@@ -1238,7 +1236,6 @@
     method public android.support.media.tv.Channel.Builder setInternalProviderFlag4(long);
     method public android.support.media.tv.Channel.Builder setNetworkAffiliation(java.lang.String);
     method public android.support.media.tv.Channel.Builder setOriginalNetworkId(int);
-    method public android.support.media.tv.Channel.Builder setPackageName(java.lang.String);
     method public android.support.media.tv.Channel.Builder setSearchable(boolean);
     method public android.support.media.tv.Channel.Builder setServiceId(int);
     method public android.support.media.tv.Channel.Builder setServiceType(java.lang.String);
@@ -1677,6 +1674,125 @@
 
 }
 
+package android.support.text.emoji {
+
+  public class EmojiCompat {
+    method public static android.support.text.emoji.EmojiCompat get();
+    method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, int, int, boolean);
+    method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
+    method public boolean hasEmojiGlyph(java.lang.CharSequence);
+    method public boolean hasEmojiGlyph(java.lang.CharSequence, int);
+    method public static android.support.text.emoji.EmojiCompat init(android.support.text.emoji.EmojiCompat.Config);
+    method public boolean isInitialized();
+    method public java.lang.CharSequence process(java.lang.CharSequence);
+    method public java.lang.CharSequence process(java.lang.CharSequence, int, int);
+    method public void registerInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+    method public void unregisterInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+    field public static final java.lang.String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
+    field public static final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+  }
+
+  public static abstract class EmojiCompat.Config {
+    ctor protected EmojiCompat.Config(android.support.text.emoji.EmojiCompat.MetadataLoader);
+    method public android.support.text.emoji.EmojiCompat.Config registerInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+    method public android.support.text.emoji.EmojiCompat.Config setMaxEmojiPerText(int);
+    method public android.support.text.emoji.EmojiCompat.Config setReplaceAll(boolean);
+    method public android.support.text.emoji.EmojiCompat.Config unregisterInitCallback(android.support.text.emoji.EmojiCompat.InitCallback);
+  }
+
+  public static abstract class EmojiCompat.InitCallback {
+    ctor public EmojiCompat.InitCallback();
+    method public void onFailed(java.lang.Throwable);
+    method public void onInitialized();
+  }
+
+  public static abstract class EmojiCompat.LoaderCallback {
+    ctor public EmojiCompat.LoaderCallback();
+    method public abstract void onFailed(java.lang.Throwable);
+    method public abstract void onLoaded(android.support.text.emoji.MetadataRepo);
+  }
+
+  public static abstract interface EmojiCompat.MetadataLoader {
+    method public abstract void load(android.support.text.emoji.EmojiCompat.LoaderCallback);
+  }
+
+  public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
+    method public int getSize(android.graphics.Paint, java.lang.CharSequence, int, int, android.graphics.Paint.FontMetricsInt);
+  }
+
+  public final class MetadataRepo {
+    method public static android.support.text.emoji.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
+    method public static android.support.text.emoji.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
+    method public static android.support.text.emoji.MetadataRepo create(android.content.res.AssetManager, java.lang.String) throws java.io.IOException;
+  }
+
+}
+
+package android.support.text.emoji.bundled {
+
+  public class BundledEmojiCompatConfig extends android.support.text.emoji.EmojiCompat.Config {
+    ctor public BundledEmojiCompatConfig(android.content.Context);
+  }
+
+}
+
+package android.support.text.emoji.widget {
+
+  public class EmojiAppCompatButton extends android.support.v7.widget.AppCompatButton {
+    ctor public EmojiAppCompatButton(android.content.Context);
+    ctor public EmojiAppCompatButton(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiAppCompatButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class EmojiAppCompatEditText extends android.support.v7.widget.AppCompatEditText {
+    ctor public EmojiAppCompatEditText(android.content.Context);
+    ctor public EmojiAppCompatEditText(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiAppCompatEditText(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class EmojiAppCompatTextView extends android.support.v7.widget.AppCompatTextView {
+    ctor public EmojiAppCompatTextView(android.content.Context);
+    ctor public EmojiAppCompatTextView(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiAppCompatTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class EmojiButton extends android.widget.Button {
+    ctor public EmojiButton(android.content.Context);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet, int);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet, int, int);
+  }
+
+  public class EmojiEditText extends android.widget.EditText {
+    ctor public EmojiEditText(android.content.Context);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet, int);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet, int, int);
+  }
+
+  public final class EmojiEditTextHelper {
+    ctor public EmojiEditTextHelper(android.widget.EditText);
+    method public android.text.method.KeyListener getKeyListener(android.text.method.KeyListener);
+    method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+  }
+
+  public class EmojiTextView extends android.widget.TextView {
+    ctor public EmojiTextView(android.content.Context);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet, int);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet, int, int);
+  }
+
+  public final class EmojiTextViewHelper {
+    ctor public EmojiTextViewHelper(android.widget.TextView);
+    method public android.text.InputFilter[] getFilters(android.text.InputFilter[]);
+    method public android.text.method.TransformationMethod getTransformationMethod(android.text.method.TransformationMethod);
+    method public void setAllCaps(boolean);
+    method public void updateTransformationMethod();
+  }
+
+}
+
 package android.support.transition {
 
   public class ArcMotion extends android.support.transition.PathMotion {
@@ -3026,10 +3142,7 @@
   public class BoundsRule {
     ctor public BoundsRule();
     ctor public BoundsRule(android.support.v17.leanback.graphics.BoundsRule);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
     method public void calculateBounds(android.graphics.Rect, android.graphics.Rect);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
-    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule bottom;
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule left;
     field public android.support.v17.leanback.graphics.BoundsRule.ValueRule right;
@@ -3037,8 +3150,11 @@
   }
 
   public static final class BoundsRule.ValueRule {
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
     method public int getAbsoluteValue();
     method public float getFraction();
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
     method public void setAbsoluteValue(int);
     method public void setFraction(float);
   }
@@ -4144,111 +4260,79 @@
 
   public abstract class Parallax<PropertyT extends android.util.Property> {
     ctor public Parallax();
-    method public void addEffect(android.support.v17.leanback.widget.ParallaxEffect);
-    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue...);
-    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue...);
-    method public abstract PropertyT addProperty(java.lang.String);
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
+    method public final PropertyT addProperty(java.lang.String);
     method public abstract PropertyT createProperty(java.lang.String, int);
     method public java.util.List<android.support.v17.leanback.widget.ParallaxEffect> getEffects();
+    method public abstract float getMaxValue();
     method public final java.util.List<PropertyT> getProperties();
     method public void removeAllEffects();
     method public void removeEffect(android.support.v17.leanback.widget.ParallaxEffect);
     method public void updateValues();
-    method public abstract void verifyProperties() throws java.lang.IllegalStateException;
-  }
-
-  public static abstract class Parallax.FloatParallax<FloatPropertyT extends android.support.v17.leanback.widget.Parallax.FloatProperty> extends android.support.v17.leanback.widget.Parallax {
-    ctor public Parallax.FloatParallax();
-    method public final FloatPropertyT addProperty(java.lang.String);
-    method public abstract float getMaxValue();
-    method public final float getPropertyValue(int);
-    method public final void setPropertyValue(int, float);
-    method public final void verifyProperties() throws java.lang.IllegalStateException;
   }
 
   public static class Parallax.FloatProperty extends android.util.Property {
     ctor public Parallax.FloatProperty(java.lang.String, int);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue at(float, float);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atAbsolute(float);
-    method public final android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue atFraction(float);
-    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax.FloatParallax);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(float, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Float get(android.support.v17.leanback.widget.Parallax);
     method public final int getIndex();
-    method public final void set(android.support.v17.leanback.widget.Parallax.FloatParallax, java.lang.Float);
+    method public final float getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Float);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, float);
     field public static final float UNKNOWN_AFTER = 3.4028235E38f;
     field public static final float UNKNOWN_BEFORE = -3.4028235E38f;
   }
 
-  public static class Parallax.FloatPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
-    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float);
-    ctor public Parallax.FloatPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.FloatProperty, float, float);
-    method public final float getMarkerValue(android.support.v17.leanback.widget.Parallax.FloatParallax);
-  }
-
-  public static abstract class Parallax.IntParallax<IntPropertyT extends android.support.v17.leanback.widget.Parallax.IntProperty> extends android.support.v17.leanback.widget.Parallax {
-    ctor public Parallax.IntParallax();
-    method public final IntPropertyT addProperty(java.lang.String);
-    method public abstract int getMaxValue();
-    method public final int getPropertyValue(int);
-    method public final void setPropertyValue(int, int);
-    method public final void verifyProperties() throws java.lang.IllegalStateException;
-  }
-
   public static class Parallax.IntProperty extends android.util.Property {
     ctor public Parallax.IntProperty(java.lang.String, int);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue at(int, float);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atAbsolute(int);
-    method public final android.support.v17.leanback.widget.Parallax.IntPropertyMarkerValue atFraction(float);
-    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax.IntParallax);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue at(int, float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(int);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMax();
+    method public final android.support.v17.leanback.widget.Parallax.PropertyMarkerValue atMin();
+    method public final java.lang.Integer get(android.support.v17.leanback.widget.Parallax);
     method public final int getIndex();
-    method public final void set(android.support.v17.leanback.widget.Parallax.IntParallax, java.lang.Integer);
+    method public final int getValue(android.support.v17.leanback.widget.Parallax);
+    method public final void set(android.support.v17.leanback.widget.Parallax, java.lang.Integer);
+    method public final void setValue(android.support.v17.leanback.widget.Parallax, int);
     field public static final int UNKNOWN_AFTER = 2147483647; // 0x7fffffff
     field public static final int UNKNOWN_BEFORE = -2147483648; // 0x80000000
   }
 
-  public static class Parallax.IntPropertyMarkerValue extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue {
-    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int);
-    ctor public Parallax.IntPropertyMarkerValue(android.support.v17.leanback.widget.Parallax.IntProperty, int, float);
-    method public final int getMarkerValue(android.support.v17.leanback.widget.Parallax.IntParallax);
-  }
-
   public static class Parallax.PropertyMarkerValue<PropertyT> {
     ctor public Parallax.PropertyMarkerValue(PropertyT);
     method public PropertyT getProperty();
   }
 
-  public abstract class ParallaxEffect<ParallaxEffectT extends android.support.v17.leanback.widget.ParallaxEffect, PropertyMarkerValueT extends android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> {
-    ctor public ParallaxEffect();
+  public abstract class ParallaxEffect {
     method public final void addTarget(android.support.v17.leanback.widget.ParallaxTarget);
-    method protected abstract float calculateFraction(android.support.v17.leanback.widget.Parallax);
-    method public final java.util.List<PropertyMarkerValueT> getPropertyRanges();
+    method public final java.util.List<android.support.v17.leanback.widget.Parallax.PropertyMarkerValue> getPropertyRanges();
     method public final java.util.List<android.support.v17.leanback.widget.ParallaxTarget> getTargets();
     method public final void performMapping(android.support.v17.leanback.widget.Parallax);
     method public final void removeTarget(android.support.v17.leanback.widget.ParallaxTarget);
-    method public final void setPropertyRanges(PropertyMarkerValueT...);
+    method public final void setPropertyRanges(android.support.v17.leanback.widget.Parallax.PropertyMarkerValue...);
     method public final android.support.v17.leanback.widget.ParallaxEffect target(android.support.v17.leanback.widget.ParallaxTarget);
     method public final android.support.v17.leanback.widget.ParallaxEffect target(java.lang.Object, android.animation.PropertyValuesHolder);
-  }
-
-  public static final class ParallaxEffect.FloatEffect extends android.support.v17.leanback.widget.ParallaxEffect {
-    ctor public ParallaxEffect.FloatEffect();
-    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
-  }
-
-  public static final class ParallaxEffect.IntEffect extends android.support.v17.leanback.widget.ParallaxEffect {
-    ctor public ParallaxEffect.IntEffect();
-    method protected float calculateFraction(android.support.v17.leanback.widget.Parallax);
+    method public final <T, V extends java.lang.Number> android.support.v17.leanback.widget.ParallaxEffect target(T, android.util.Property<T, V>);
   }
 
   public abstract class ParallaxTarget {
     ctor public ParallaxTarget();
-    method public abstract float getFraction();
-    method public abstract void update(float);
+    method public void directUpdate(java.lang.Number);
+    method public boolean isDirectMapping();
+    method public void update(float);
+  }
+
+  public static final class ParallaxTarget.DirectPropertyTarget<T, V extends java.lang.Number> extends android.support.v17.leanback.widget.ParallaxTarget {
+    ctor public ParallaxTarget.DirectPropertyTarget(java.lang.Object, android.util.Property<T, V>);
   }
 
   public static final class ParallaxTarget.PropertyValuesHolderTarget extends android.support.v17.leanback.widget.ParallaxTarget {
     ctor public ParallaxTarget.PropertyValuesHolderTarget(java.lang.Object, android.animation.PropertyValuesHolder);
-    method public float getFraction();
-    method public void update(float);
   }
 
   public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
@@ -4440,10 +4524,10 @@
     method public void unselect();
   }
 
-  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax.IntParallax {
+  public class RecyclerViewParallax extends android.support.v17.leanback.widget.Parallax {
     ctor public RecyclerViewParallax();
     method public android.support.v17.leanback.widget.RecyclerViewParallax.ChildPositionProperty createProperty(java.lang.String, int);
-    method public int getMaxValue();
+    method public float getMaxValue();
     method public android.support.v7.widget.RecyclerView getRecyclerView();
     method public void setRecyclerView(android.support.v7.widget.RecyclerView);
   }
@@ -6168,6 +6252,13 @@
   }
 
   public class ShortcutInfoCompat {
+    method public android.content.ComponentName getActivity();
+    method public java.lang.CharSequence getDisabledMessage();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public android.content.Intent[] getIntents();
+    method public java.lang.CharSequence getLongLabel();
+    method public java.lang.CharSequence getShortLabel();
   }
 
   public static class ShortcutInfoCompat.Builder {
@@ -6184,7 +6275,6 @@
   }
 
   public class ShortcutManagerCompat {
-    ctor public ShortcutManagerCompat();
     method public static android.content.Intent createShortcutResultIntent(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat);
     method public static boolean isRequestPinShortcutSupported(android.content.Context);
     method public static boolean requestPinShortcut(android.content.Context, android.support.v4.content.pm.ShortcutInfoCompat, android.content.IntentSender);
@@ -6678,7 +6768,7 @@
     ctor public MediaButtonReceiver();
     method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, long);
     method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long);
-    method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
+    method public static deprecated android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
     method public void onReceive(android.content.Context, android.content.Intent);
   }
 
@@ -6704,6 +6794,7 @@
     method public android.app.PendingIntent getSessionActivity();
     method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
     method public android.support.v4.media.session.MediaControllerCompat.TransportControls getTransportControls();
+    method public boolean isCaptioningEnabled();
     method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
     method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
@@ -6719,6 +6810,7 @@
     ctor public MediaControllerCompat.Callback();
     method public void binderDied();
     method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo);
+    method public void onCaptioningEnabledChanged(boolean);
     method public void onExtrasChanged(android.os.Bundle);
     method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat);
     method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat);
@@ -6755,6 +6847,7 @@
     method public abstract void seekTo(long);
     method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction, android.os.Bundle);
     method public abstract void sendCustomAction(java.lang.String, android.os.Bundle);
+    method public abstract void setCaptioningEnabled(boolean);
     method public abstract void setRating(android.support.v4.media.RatingCompat);
     method public abstract void setRepeatMode(int);
     method public abstract void setShuffleModeEnabled(boolean);
@@ -6781,6 +6874,7 @@
     method public void setActive(boolean);
     method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback);
     method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback, android.os.Handler);
+    method public void setCaptioningEnabled(boolean);
     method public void setExtras(android.os.Bundle);
     method public void setFlags(int);
     method public void setMediaButtonReceiver(android.app.PendingIntent);
@@ -6794,6 +6888,8 @@
     method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
     method public void setShuffleModeEnabled(boolean);
+    field public static final java.lang.String ACTION_FLAG_AS_INAPPROPRIATE = "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
+    field public static final java.lang.String ACTION_SKIP_AD = "android.support.v4.media.session.action.SKIP_AD";
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
@@ -6820,6 +6916,7 @@
     method public void onRemoveQueueItemAt(int);
     method public void onRewind();
     method public void onSeekTo(long);
+    method public void onSetCaptioningEnabled(boolean);
     method public void onSetRating(android.support.v4.media.RatingCompat);
     method public void onSetRepeatMode(int);
     method public void onSetShuffleModeEnabled(boolean);
@@ -6898,6 +6995,7 @@
     field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_CAPTIONING_ENABLED = 1048576L; // 0x100000L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
     field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
     field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
@@ -7525,14 +7623,19 @@
     method public static deprecated boolean expandActionView(android.view.MenuItem);
     method public static android.support.v4.view.ActionProvider getActionProvider(android.view.MenuItem);
     method public static deprecated android.view.View getActionView(android.view.MenuItem);
+    method public int getAlphabeticModifiers(android.view.MenuItem);
     method public static java.lang.CharSequence getContentDescription(android.view.MenuItem);
+    method public int getNumericModifiers(android.view.MenuItem);
     method public static java.lang.CharSequence getTooltipText(android.view.MenuItem);
     method public static deprecated boolean isActionViewExpanded(android.view.MenuItem);
     method public static android.view.MenuItem setActionProvider(android.view.MenuItem, android.support.v4.view.ActionProvider);
     method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
     method public static deprecated android.view.MenuItem setActionView(android.view.MenuItem, int);
+    method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
     method public static void setContentDescription(android.view.MenuItem, java.lang.CharSequence);
+    method public static void setNumericShortcut(android.view.MenuItem, char, int);
     method public static deprecated android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
+    method public static void setShortcut(android.view.MenuItem, char, char, int, int);
     method public static deprecated void setShowAsAction(android.view.MenuItem, int);
     method public static void setTooltipText(android.view.MenuItem, java.lang.CharSequence);
     field public static final deprecated int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
@@ -11801,6 +11904,10 @@
     field public static final android.os.Parcelable.Creator<android.support.v7.widget.Toolbar.SavedState> CREATOR;
   }
 
+  public class TooltipCompat {
+    method public static void setTooltipText(android.view.View, java.lang.CharSequence);
+  }
+
 }
 
 package android.support.v7.widget.helper {
@@ -11917,6 +12024,12 @@
     field public int boxedEdges;
   }
 
+  public class CurvedOffsettingHelper extends android.support.wearable.view.WearableRecyclerView.OffsettingHelper {
+    ctor public CurvedOffsettingHelper();
+    method public void adjustAnchorOffsetXY(android.view.View, float[]);
+    method public void updateChild(android.view.View, android.support.wearable.view.WearableRecyclerView);
+  }
+
   public class SwipeDismissFrameLayout extends android.widget.FrameLayout {
     ctor public SwipeDismissFrameLayout(android.content.Context);
     ctor public SwipeDismissFrameLayout(android.content.Context, android.util.AttributeSet);
@@ -11934,5 +12047,27 @@
     method public void onSwipeStarted();
   }
 
+  public class WearableRecyclerView extends android.support.v7.widget.RecyclerView {
+    ctor public WearableRecyclerView(android.content.Context);
+    ctor public WearableRecyclerView(android.content.Context, android.util.AttributeSet);
+    ctor public WearableRecyclerView(android.content.Context, android.util.AttributeSet, int);
+    ctor public WearableRecyclerView(android.content.Context, android.util.AttributeSet, int, int);
+    method public float getBezelWidthFraction();
+    method public boolean getEdgeItemsCenteringEnabled();
+    method public android.support.wearable.view.WearableRecyclerView.OffsettingHelper getOffsettingHelper();
+    method public float getScrollDegreesPerScreen();
+    method public boolean isCircularScrollingGestureEnabled();
+    method public void setBezelWidthFraction(float);
+    method public void setCircularScrollingGestureEnabled(boolean);
+    method public void setEdgeItemsCenteringEnabled(boolean);
+    method public void setOffsettingHelper(android.support.wearable.view.WearableRecyclerView.OffsettingHelper);
+    method public void setScrollDegreesPerScreen(float);
+  }
+
+  public static abstract class WearableRecyclerView.OffsettingHelper {
+    ctor public WearableRecyclerView.OffsettingHelper();
+    method public abstract void updateChild(android.view.View, android.support.wearable.view.WearableRecyclerView);
+  }
+
 }
 
diff --git a/build.gradle b/build.gradle
index b3fcda7..98de82b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,14 +17,10 @@
 buildscript {
     ext.supportRootFolder = project.projectDir
     apply from: 'buildSrc/init.gradle'
+    init.loadDefaultVersions()
+    init.setSdkInLocalPropertiesFile()
     init.addMavenRepositories(repositories)
-    dependencies {
-        classpath libs.gradle
-    }
 }
-init.loadDefaultVersions()
-
-init.setSdkInLocalPropertiesFile()
 
 init.addMavenRepositories(repositories)
 
@@ -34,4 +30,8 @@
 
 init.setupRelease()
 
-init.enableDoclavaAndJDiff(this)
\ No newline at end of file
+init.enableDoclavaAndJDiff(this)
+
+///// FLATFOOT START
+
+///// FLATFOOT END
\ No newline at end of file
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index ae9582a..1041b12 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -10,4 +10,6 @@
 }
 dependencies {
     compile libs.gradle
+    compile libs.error_prone
+    compile libs.jarjar_gradle
 }
diff --git a/buildSrc/dependencies.gradle b/buildSrc/dependencies.gradle
index 284fe01..aa7f93e 100644
--- a/buildSrc/dependencies.gradle
+++ b/buildSrc/dependencies.gradle
@@ -31,5 +31,9 @@
 // Other dependencies
 libs.xml_parser_apis = 'xerces:xmlParserAPIs:2.6.2'
 libs.xerces_impl = 'xerces:xercesImpl:2.6.2'
+libs.error_prone = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.9'
+
+// jarjar plugin
+libs.jarjar_gradle = 'org.anarres.jarjar:jarjar-gradle:1.0.0'
 
 rootProject.ext['libs'] = libs
diff --git a/buildSrc/diff_and_docs.gradle b/buildSrc/diff_and_docs.gradle
index c6dda4f..9ad419d 100644
--- a/buildSrc/diff_and_docs.gradle
+++ b/buildSrc/diff_and_docs.gradle
@@ -59,7 +59,7 @@
 
     options {
         addStringOption "templatedir",
-                "${supportRootFolder}/../../build/tools/droiddoc/templates-sdk"
+                "${supportRootFolder}/../../external/doclava/res/assets/templates-sdk"
         addStringOption "federate Android", "http://developer.android.com"
         addStringOption "stubpackages", "android.support.*"
         addStringOption "samplesdir", "${supportRootFolder}/samples"
@@ -102,7 +102,7 @@
 
     options {
         addStringOption "templatedir",
-                "${supportRootFolder}/../../build/tools/droiddoc/templates-sdk"
+                "${supportRootFolder}/../../external/doclava/res/assets/templates-sdk"
         addStringOption "federate Android", "http://developer.android.com"
         addStringOption "stubpackages", "android.support.*"
     }
@@ -346,16 +346,18 @@
 
 subprojects { subProject ->
     subProject.afterEvaluate { p ->
-        if (p.hasProperty('android') && p.android.hasProperty('libraryVariants')) {
-            p.android.libraryVariants.all { v ->
-                if (v.name == 'release') {
-                    registerForDocsTask(rootProject.generateDocs, p, v)
-                    registerForDocsTask(rootProject.generateApi, p, v)
-                    registerForDocsTask(rootProject.generateDiffs, p, v)
+        if (!p.hasProperty("noDocs") || !p.noDocs) {
+            if (p.hasProperty('android') && p.android.hasProperty('libraryVariants')) {
+                p.android.libraryVariants.all { v ->
+                    if (v.name == 'release') {
+                        registerForDocsTask(rootProject.generateDocs, p, v)
+                        registerForDocsTask(rootProject.generateApi, p, v)
+                        registerForDocsTask(rootProject.generateDiffs, p, v)
+                    }
                 }
+            } else if (p.hasProperty("compileJava")) {
+                registerJavaProjectForDocsTask(rootProject.generateDocs, p, p.compileJava)
             }
-        } else if (p.hasProperty("compileJava")) {
-            registerJavaProjectForDocsTask(rootProject.generateDocs, p, p.compileJava)
         }
     }
 }
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index 988da6d..25281df 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -85,11 +85,13 @@
         System.setProperty('android.home', "${init.prebuiltsRoot}/fullsdk-${platform}")
         File props = file("local.properties")
         props.write "sdk.dir=${fullSdkPath}"
+        ext.usingFullSdk = true
     } else {
         gradle.ext.currentSdk = 'current'
         project.ext.androidJar = files("${init.prebuiltsRoot}/sdk/current/android.jar")
         File props = file("local.properties")
         props.write "android.dir=../../"
+        ext.usingFullSdk = false
     }
 }
 
@@ -325,7 +327,8 @@
                 if (junitReport.enabled) {
                     def zipTask = project.tasks.create(name : "zipResultsOf${task.name.capitalize()}", type : Zip) {
                         destinationDir(testResultsDistDir)
-                        archiveName("${project.name}.zip")
+                        // first one is always :, drop it.
+                        archiveName("${project.getPath().split(":").join("_").substring(1)}.zip")
                     }
                     if (project.rootProject.ext.runningInBuildServer) {
                         task.ignoreFailures = true
diff --git a/buildSrc/release.gradle b/buildSrc/release.gradle
index 7749f8d..83871b8 100644
--- a/buildSrc/release.gradle
+++ b/buildSrc/release.gradle
@@ -27,27 +27,42 @@
 // to the local repo.
 task(mainUpload)
 
+rootProject.ext.repoWithHistoryOut = new File(buildDir, 'support_repo_with_history')
+
 // repository creation task
 task createRepository(type: Zip, dependsOn: mainUpload) {
-    from project.ext.supportRepoOut
+    from rootProject.ext.supportRepoOut
+    from "${init.prebuiltsRoot}/maven_repo/android"
+    // if there are duplicates, pick the first one.
+    duplicatesStrategy "EXCLUDE"
     destinationDir project.ext.distDir
     into 'm2repository'
     baseName = String.format("sdk-repo-linux-m2repository-%s", project.ext.buildNumber)
 }
+
+task createTopOfTreeRepository(type : Zip) {
+    description "Creates a maven repository that includes just the libraries compiled in this" +
+            " project, without any history from prebuilts."
+    from rootProject.ext.supportRepoOut
+    destinationDir rootProject.ext.distDir
+    into 'm2repository'
+    baseName = String.format("top-of-tree-m2repository-%s", project.ext.buildNumber)
+    dependsOn mainUpload
+}
+
 createArchive.dependsOn createRepository
-
-// prepare repository with older versions
-task unzipRepo(type: Copy) {
-    from "${init.prebuiltsRoot}/maven_repo/android"
-    into project.ext.supportRepoOut
-}
-
-unzipRepo.doFirst {
-    project.ext.supportRepoOut.deleteDir()
-    project.ext.supportRepoOut.mkdirs()
-}
+createRepository.dependsOn createTopOfTreeRepository
 
 // anchor for prepare repo. This is post unzip + sourceProp.
+task nukeRepoOut() {
+    description "This task clears the repo folder to ensure that we run a fresh build every" +
+            " time we create arhives. Otherwise, snapshots will accumulate in the builds folder."
+    doFirst {
+        rootProject.ext.supportRepoOut.deleteDir()
+        rootProject.ext.supportRepoOut.mkdirs()
+    }
+}
+
 task(prepareRepo)
 
 task(createXml).doLast({
@@ -94,7 +109,7 @@
 
     Files.write(sourceProp, new File(project.ext.supportRepoOut, 'source.properties'), Charsets.UTF_8)
 })
-createSourceProp.dependsOn unzipRepo
+createSourceProp.dependsOn nukeRepoOut
 prepareRepo.dependsOn createSourceProp
 
 /**
@@ -107,4 +122,4 @@
     HashFunction hashFunction = Hashing.sha1()
     HashCode hashCode = hashFunction.hashString(inputFile.getAbsolutePath(), Charset.forName("UTF-8"))
     return hashCode.toString()
-}
\ No newline at end of file
+}
diff --git a/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
index f1f6a04..6cdf079 100644
--- a/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
@@ -21,6 +21,8 @@
 import com.android.build.gradle.api.LibraryVariant
 import com.android.builder.core.BuilderConstants
 import com.google.common.collect.ImmutableMap
+import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
+import net.ltgt.gradle.errorprone.ErrorProneToolChain
 import org.gradle.api.Action
 import org.gradle.api.JavaVersion
 import org.gradle.api.Plugin
@@ -43,6 +45,8 @@
                 project.getExtensions().create("supportLibrary", SupportLibraryExtension);
 
         project.apply(ImmutableMap.of("plugin", "com.android.library"));
+        project.apply(ImmutableMap.of("plugin", ErrorProneBasePlugin.class));
+
         LibraryExtension library =
                 project.getExtensions().findByType(LibraryExtension.class);
 
@@ -88,8 +92,10 @@
             error 'NewApi'
         }
 
-        // Library projects don't run lint by default, so set up dependency.
-        project.tasks.release.dependsOn project.tasks.lint
+        if (project.rootProject.ext.usingFullSdk) {
+            // Library projects don't run lint by default, so set up dependency.
+            project.tasks.release.dependsOn project.tasks.lint
+        }
 
         // Java 8 is only fully supported on API 24+ and not all Java 8 features are binary
         // compatible with API < 24, so use Java 7 for both source AND target.
@@ -151,5 +157,29 @@
                 }
             });
         }
+
+        final ErrorProneToolChain toolChain = ErrorProneToolChain.create(project);
+        library.getBuildTypes().create("errorProne")
+        library.getLibraryVariants().all(new Action<LibraryVariant>() {
+            @Override
+            void execute(LibraryVariant libraryVariant) {
+                if (libraryVariant.getBuildType().getName().equals("errorProne")) {
+                    libraryVariant.getJavaCompile().setToolChain(toolChain);
+
+                    // TODO(aurimas): remove this once all these warnings are fixed.
+                    libraryVariant.getJavaCompile().options.compilerArgs += [
+                            '-Xep:EqualsHashCode:OFF',
+                            '-Xep:MissingCasesInEnumSwitch:WARN',
+                            '-Xep:TypeParameterUnusedInFormals:WARN',
+                            '-Xep:MissingOverride:WARN',
+                            '-Xep:ArrayToString:WARN',
+                            '-Xep:MislabeledAndroidString:WARN',
+                            '-Xep:SelfEquals:WARN',
+                            '-Xep:RectIntersectReturnValueIgnored:WARN',
+                            '-Xep:FallThrough:WARN'
+                    ]
+                }
+            }
+        })
     }
 }
diff --git a/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java b/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java
index 8f2b2e8..0b04ba8 100644
--- a/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java
+++ b/compat/api21/android/support/v4/app/ActivityOptionsCompat21.java
@@ -55,9 +55,10 @@
                         sharedElementName));
     }
 
+    @SuppressWarnings("unchecked")
     public static ActivityOptionsCompat21 makeSceneTransitionAnimation(Activity activity,
             View[] sharedElements, String[] sharedElementNames) {
-        Pair[] pairs = null;
+        Pair<View, String>[] pairs = null;
         if (sharedElements != null) {
             pairs = new Pair[sharedElements.length];
             for (int i = 0; i < pairs.length; i++) {
diff --git a/compat/api21/android/support/v4/widget/PopupWindowCompatApi21.java b/compat/api21/android/support/v4/widget/PopupWindowCompatApi21.java
deleted file mode 100644
index f231722..0000000
--- a/compat/api21/android/support/v4/widget/PopupWindowCompatApi21.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 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.v4.widget;
-
-import android.support.annotation.RequiresApi;
-import android.util.Log;
-import android.widget.PopupWindow;
-
-import java.lang.reflect.Field;
-
-@RequiresApi(21)
-class PopupWindowCompatApi21 {
-
-    private static final String TAG = "PopupWindowCompatApi21";
-
-    private static Field sOverlapAnchorField;
-
-    static {
-        try {
-            sOverlapAnchorField = PopupWindow.class.getDeclaredField("mOverlapAnchor");
-            sOverlapAnchorField.setAccessible(true);
-        } catch (NoSuchFieldException e) {
-            Log.i(TAG, "Could not fetch mOverlapAnchor field from PopupWindow", e);
-        }
-    }
-
-    static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-        if (sOverlapAnchorField != null) {
-            try {
-                sOverlapAnchorField.set(popupWindow, overlapAnchor);
-            } catch (IllegalAccessException e) {
-                Log.i(TAG, "Could not set overlap anchor field in PopupWindow", e);
-            }
-        }
-    }
-
-    static boolean getOverlapAnchor(PopupWindow popupWindow) {
-        if (sOverlapAnchorField != null) {
-            try {
-                return (Boolean) sOverlapAnchorField.get(popupWindow);
-            } catch (IllegalAccessException e) {
-                Log.i(TAG, "Could not get overlap anchor field in PopupWindow", e);
-            }
-        }
-        return false;
-    }
-
-}
diff --git a/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java b/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java
index 08863a5..a5daaa7 100644
--- a/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java
+++ b/compat/api23/android/support/v4/app/ActivityOptionsCompat23.java
@@ -56,9 +56,10 @@
                         sharedElementName));
     }
 
+    @SuppressWarnings("unchecked")
     public static ActivityOptionsCompat23 makeSceneTransitionAnimation(Activity activity,
             View[] sharedElements, String[] sharedElementNames) {
-        Pair[] pairs = null;
+        Pair<View, String>[] pairs = null;
         if (sharedElements != null) {
             pairs = new Pair[sharedElements.length];
             for (int i = 0; i < pairs.length; i++) {
diff --git a/compat/api23/android/support/v4/widget/PopupWindowCompatApi23.java b/compat/api23/android/support/v4/widget/PopupWindowCompatApi23.java
deleted file mode 100644
index 9d30f61..0000000
--- a/compat/api23/android/support/v4/widget/PopupWindowCompatApi23.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.v4.widget;
-
-import android.support.annotation.RequiresApi;
-import android.widget.PopupWindow;
-
-@RequiresApi(23)
-class PopupWindowCompatApi23 {
-
-    static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-        popupWindow.setOverlapAnchor(overlapAnchor);
-    }
-
-    static boolean getOverlapAnchor(PopupWindow popupWindow) {
-        return popupWindow.getOverlapAnchor();
-    }
-
-    static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
-        popupWindow.setWindowLayoutType(layoutType);
-    }
-
-    static int getWindowLayoutType(PopupWindow popupWindow) {
-        return popupWindow.getWindowLayoutType();
-    }
-
-}
diff --git a/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java b/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java
index 8e0d520..608c017 100644
--- a/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java
+++ b/compat/api24/android/support/v4/app/ActivityOptionsCompat24.java
@@ -56,9 +56,10 @@
                         sharedElementName));
     }
 
+    @SuppressWarnings("unchecked")
     public static ActivityOptionsCompat24 makeSceneTransitionAnimation(Activity activity,
             View[] sharedElements, String[] sharedElementNames) {
-        Pair[] pairs = null;
+        Pair<View, String>[] pairs = null;
         if (sharedElements != null) {
             pairs = new Pair[sharedElements.length];
             for (int i = 0; i < pairs.length; i++) {
diff --git a/compat/ics/android/support/v4/graphics/PaintCompatApi14.java b/compat/ics/android/support/v4/graphics/PaintCompatApi14.java
index b459623..86e87d8 100644
--- a/compat/ics/android/support/v4/graphics/PaintCompatApi14.java
+++ b/compat/ics/android/support/v4/graphics/PaintCompatApi14.java
@@ -88,7 +88,7 @@
     private static Pair<Rect, Rect> obtainEmptyRects() {
         Pair<Rect, Rect> rects = sRectThreadLocal.get();
         if (rects == null) {
-            rects = new Pair(new Rect(), new Rect());
+            rects = new Pair<>(new Rect(), new Rect());
             sRectThreadLocal.set(rects);
         } else {
             rects.first.setEmpty();
diff --git a/compat/ics/android/support/v4/view/ViewCompatICS.java b/compat/ics/android/support/v4/view/ViewCompatICS.java
deleted file mode 100644
index 1c4c2e4..0000000
--- a/compat/ics/android/support/v4/view/ViewCompatICS.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2017 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.v4.view;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.support.annotation.RequiresApi;
-import android.support.v4.view.accessibility.AccessibilityManagerCompat;
-import android.text.TextUtils;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.Toast;
-
-@RequiresApi(14)
-class ViewCompatICS {
-
-    public static void setTooltipText(View view, CharSequence tooltipText) {
-        if (TextUtils.isEmpty(tooltipText)) {
-            view.setOnLongClickListener(null);
-            view.setLongClickable(false);
-            view.setOnHoverListener(null);
-        } else {
-            new TooltipHandler(view, tooltipText);
-        }
-    }
-
-    private static class TooltipHandler implements View.OnLongClickListener, View.OnHoverListener {
-        private final View mAnchor;
-        private final CharSequence mTooltipText;
-        private final Runnable mShowRunnable = new Runnable() {
-            @Override
-            public void run() {
-                show(Toast.LENGTH_LONG);
-            }
-        };
-        private Toast mTooltip;
-
-        TooltipHandler(View anchor, CharSequence tooltipText) {
-            mAnchor = anchor;
-            mTooltipText = tooltipText;
-
-            mAnchor.setOnLongClickListener(this);
-            mAnchor.setOnHoverListener(this);
-        }
-
-        @Override
-        public boolean onLongClick(View v) {
-            show(Toast.LENGTH_SHORT);
-            return true;
-        }
-
-        @Override
-        public boolean onHover(View v, MotionEvent event) {
-            AccessibilityManager manager = (AccessibilityManager)
-                    mAnchor.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-            if (manager.isEnabled()
-                    && AccessibilityManagerCompat.isTouchExplorationEnabled(manager)) {
-                return false;
-            }
-            final int action = event.getAction();
-            if (action == MotionEvent.ACTION_HOVER_MOVE) {
-                hide();
-                mAnchor.getHandler().postDelayed(
-                        mShowRunnable, ViewConfiguration.getLongPressTimeout());
-            } else if (action == MotionEvent.ACTION_HOVER_EXIT) {
-                hide();
-            }
-            return false;
-        }
-
-        private void show(int duration) {
-            final Context context = mAnchor.getContext();
-            final Resources resources = context.getResources();
-            final int screenWidth = resources.getDisplayMetrics().widthPixels;
-            final int screenHeight = resources.getDisplayMetrics().heightPixels;
-
-            final Rect displayFrame = new Rect();
-            mAnchor.getWindowVisibleDisplayFrame(displayFrame);
-            if (displayFrame.left < 0 && displayFrame.top < 0) {
-                // No meaningful display frame, the anchor view is probably in a subpanel
-                // (such as a popup window). Use the screen frame as a reasonable approximation.
-                final int statusBarHeight;
-                int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
-                if (resourceId > 0) {
-                    statusBarHeight = resources.getDimensionPixelSize(resourceId);
-                } else {
-                    statusBarHeight = 0;
-                }
-                displayFrame.set(0, statusBarHeight, screenWidth, screenHeight);
-            }
-
-            final int[] anchorPos = new int[2];
-            mAnchor.getLocationOnScreen(anchorPos);
-            int referenceX = anchorPos[0] + mAnchor.getWidth() / 2;
-            if (ViewCompat.getLayoutDirection(mAnchor) == ViewCompat.LAYOUT_DIRECTION_LTR) {
-                referenceX = screenWidth - referenceX; // mirror
-            }
-            final int anchorTop = anchorPos[1];
-            hide();
-            mTooltip = Toast.makeText(context, mTooltipText, duration);
-            if (anchorTop < displayFrame.height() * 0.8) {
-                // Show along the bottom of the anchor view.
-                mTooltip.setGravity(Gravity.TOP | GravityCompat.END, referenceX,
-                        anchorTop + mAnchor.getHeight() - displayFrame.top);
-            } else {
-                // Show along the top of the anchor view.
-                mTooltip.setGravity(Gravity.BOTTOM | GravityCompat.END, referenceX,
-                        displayFrame.bottom - anchorTop);
-            }
-            mTooltip.show();
-        }
-
-        private void hide() {
-            if (mTooltip != null) {
-                mTooltip.cancel();
-                mTooltip = null;
-            }
-            mAnchor.getHandler().removeCallbacks(mShowRunnable);
-        }
-    }
-}
diff --git a/compat/java/android/support/v4/app/NotificationManagerCompat.java b/compat/java/android/support/v4/app/NotificationManagerCompat.java
index 0cdd765..8b7841e 100644
--- a/compat/java/android/support/v4/app/NotificationManagerCompat.java
+++ b/compat/java/android/support/v4/app/NotificationManagerCompat.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.app;
 
-import android.support.annotation.RequiresApi;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.Service;
@@ -35,6 +34,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.provider.Settings;
+import android.support.annotation.RequiresApi;
 import android.support.v4.os.BuildCompat;
 import android.util.Log;
 
@@ -611,7 +611,7 @@
         final ComponentName componentName;
         final IBinder iBinder;
 
-        public ServiceConnectedEvent(ComponentName componentName,
+        ServiceConnectedEvent(ComponentName componentName,
                 final IBinder iBinder) {
             this.componentName = componentName;
             this.iBinder = iBinder;
@@ -619,7 +619,7 @@
     }
 
     private interface Task {
-        public void send(INotificationSideChannel service) throws RemoteException;
+        void send(INotificationSideChannel service) throws RemoteException;
     }
 
     private static class NotifyTask implements Task {
@@ -628,7 +628,7 @@
         final String tag;
         final Notification notif;
 
-        public NotifyTask(String packageName, int id, String tag, Notification notif) {
+        NotifyTask(String packageName, int id, String tag, Notification notif) {
             this.packageName = packageName;
             this.id = id;
             this.tag = tag;
@@ -640,6 +640,7 @@
             service.notify(packageName, id, tag, notif);
         }
 
+        @Override
         public String toString() {
             StringBuilder sb = new StringBuilder("NotifyTask[");
             sb.append("packageName:").append(packageName);
@@ -656,14 +657,14 @@
         final String tag;
         final boolean all;
 
-        public CancelTask(String packageName) {
+        CancelTask(String packageName) {
             this.packageName = packageName;
             this.id = 0;
             this.tag = null;
             this.all = true;
         }
 
-        public CancelTask(String packageName, int id, String tag) {
+        CancelTask(String packageName, int id, String tag) {
             this.packageName = packageName;
             this.id = id;
             this.tag = tag;
@@ -679,6 +680,7 @@
             }
         }
 
+        @Override
         public String toString() {
             StringBuilder sb = new StringBuilder("CancelTask[");
             sb.append("packageName:").append(packageName);
diff --git a/compat/java/android/support/v4/app/SharedElementCallback.java b/compat/java/android/support/v4/app/SharedElementCallback.java
index 5c64762..c218d86 100644
--- a/compat/java/android/support/v4/app/SharedElementCallback.java
+++ b/compat/java/android/support/v4/app/SharedElementCallback.java
@@ -190,9 +190,9 @@
         int bitmapHeight = Math.round(screenBounds.height());
         Bitmap bitmap = null;
         if (bitmapWidth > 0 && bitmapHeight > 0) {
-            float scale = Math.min(1f, ((float)MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
-            bitmapWidth *= scale;
-            bitmapHeight *= scale;
+            float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
+            bitmapWidth = (int) (bitmapWidth * scale);
+            bitmapHeight = (int) (bitmapHeight * scale);
             if (mTempMatrix == null) {
                 mTempMatrix = new Matrix();
             }
diff --git a/compat/java/android/support/v4/content/ModernAsyncTask.java b/compat/java/android/support/v4/content/ModernAsyncTask.java
index 306d334..db07ee5 100644
--- a/compat/java/android/support/v4/content/ModernAsyncTask.java
+++ b/compat/java/android/support/v4/content/ModernAsyncTask.java
@@ -47,7 +47,7 @@
  *
  * <p>Note that for now this is not publicly available because it is not a
  * complete implementation, only sufficient for the needs of
- * {@link AsyncTaskLoader}.
+ * {@link android.content.AsyncTaskLoader}.
  */
 abstract class ModernAsyncTask<Params, Progress, Result> {
     private static final String LOG_TAG = "AsyncTask";
@@ -436,6 +436,8 @@
                     throw new IllegalStateException("Cannot execute task:"
                             + " the task has already been executed "
                             + "(a task can be executed only once)");
+                default:
+                    throw new IllegalStateException("We should never reach this state");
             }
         }
 
diff --git a/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java b/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java
index b6ac319..bbb2568 100644
--- a/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java
+++ b/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java
@@ -15,7 +15,6 @@
  */
 package android.support.v4.content.pm;
 
-import android.support.annotation.RequiresApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -24,8 +23,12 @@
 import android.graphics.drawable.Icon;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.text.TextUtils;
 
+import java.util.Arrays;
+
 /**
  * Helper for accessing features in {@link android.content.pm.ShortcutInfo}
  * introduced after API level 25 in a backwards compatible fashion.
@@ -83,6 +86,84 @@
     }
 
     /**
+     * Returns the ID of a shortcut.
+     *
+     * <p>Shortcut IDs are unique within each publisher app and must be stable across
+     * devices so that shortcuts will still be valid when restored on a different device.
+     * See {@link android.content.pm.ShortcutManager} for details.
+     */
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
+    /**
+     * Return the target activity.
+     *
+     * <p>This has nothing to do with the activity that this shortcut will launch.
+     * Launcher apps should show the launcher icon for the returned activity alongside
+     * this shortcut.
+     *
+     * @see Builder#setActivity(ComponentName)
+     */
+    @Nullable
+    public ComponentName getActivity() {
+        return mActivity;
+    }
+
+    /**
+     * Return the short description of a shortcut.
+     *
+     * @see Builder#setShortLabel(CharSequence)
+     */
+    @NonNull
+    public CharSequence getShortLabel() {
+        return mLabel;
+    }
+
+    /**
+     * Return the long description of a shortcut.
+     *
+     * @see Builder#setLongLabel(CharSequence)
+     */
+    @Nullable
+    public CharSequence getLongLabel() {
+        return mLongLabel;
+    }
+
+    /**
+     * Return the message that should be shown when the user attempts to start a shortcut
+     * that is disabled.
+     *
+     * @see Builder#setDisabledMessage(CharSequence)
+     */
+    @Nullable
+    public CharSequence getDisabledMessage() {
+        return mDisabledMessage;
+    }
+
+    /**
+     * Returns the intent that is executed when the user selects this shortcut.
+     * If setIntents() was used, then return the last intent in the array.
+     *
+     * @see Builder#setIntent(Intent)
+     */
+    @NonNull
+    public Intent getIntent() {
+        return mIntents[mIntents.length - 1];
+    }
+
+    /**
+     * Return the intent set with {@link Builder#setIntents(Intent[])}.
+     *
+     * @see Builder#setIntents(Intent[])
+     */
+    @NonNull
+    public Intent[] getIntents() {
+        return Arrays.copyOf(mIntents, mIntents.length);
+    }
+
+    /**
      * Builder class for {@link ShortcutInfoCompat} objects.
      */
     public static class Builder {
@@ -194,7 +275,7 @@
         }
 
         /**
-         * Sets an icon of a shortcut.
+         * Creates a {@link ShortcutInfoCompat} instance.
          */
         @NonNull
         public ShortcutInfoCompat build() {
diff --git a/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java b/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java
index 732a14f..b421a1c 100644
--- a/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java
+++ b/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java
@@ -43,6 +43,10 @@
     @VisibleForTesting static final String INSTALL_SHORTCUT_PERMISSION =
             "com.android.launcher.permission.INSTALL_SHORTCUT";
 
+    private ShortcutManagerCompat() {
+        /* Hide constructor */
+    }
+
     /**
      * @return {@code true} if the launcher supports {@link #requestPinShortcut},
      * {@code false} otherwise
diff --git a/compat/java/android/support/v4/internal/view/SupportMenu.java b/compat/java/android/support/v4/internal/view/SupportMenu.java
index 55b8a95..c072151 100644
--- a/compat/java/android/support/v4/internal/view/SupportMenu.java
+++ b/compat/java/android/support/v4/internal/view/SupportMenu.java
@@ -19,6 +19,7 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.support.annotation.RestrictTo;
+import android.view.KeyEvent;
 
 /**
  * Interface for managing the items in a menu.
@@ -53,6 +54,13 @@
     int CATEGORY_SHIFT = 16;
 
     /**
+     * A mask of all supported modifiers for MenuItem's keyboard shortcuts
+     */
+    int SUPPORTED_MODIFIERS_MASK = KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON
+            | KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON
+            | KeyEvent.META_FUNCTION_ON;
+
+    /**
      * Flag which stops the Menu being closed when a sub menu is opened
      */
     int FLAG_KEEP_OPEN_ON_SUBMENU_OPENED = 4;
diff --git a/compat/java/android/support/v4/internal/view/SupportMenuItem.java b/compat/java/android/support/v4/internal/view/SupportMenuItem.java
index 504b579..109cdb0 100644
--- a/compat/java/android/support/v4/internal/view/SupportMenuItem.java
+++ b/compat/java/android/support/v4/internal/view/SupportMenuItem.java
@@ -249,4 +249,94 @@
      */
     @Override
     CharSequence getTooltipText();
+
+    /**
+     * Change both the numeric and alphabetic shortcut associated with this
+     * item. Note that the shortcut will be triggered when the key that
+     * generates the given character is pressed along with the corresponding
+     * modifier key. Also note that case is not significant and that alphabetic
+     * shortcut characters will be handled in lower case.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key. This is the shortcut when
+     *        using a numeric (e.g., 12-key) keyboard.
+     * @param numericModifiers The numeric modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The alphabetic modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    @Override
+    MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers);
+
+    /**
+     * Change the numeric shortcut and modifiers associated with this item.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key.  This is the shortcut when
+     *                 using a 12-key (numeric) keyboard.
+     * @param numericModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    @Override
+    MenuItem setNumericShortcut(char numericChar, int numericModifiers);
+
+    /**
+     * Return the modifiers for this menu item's numeric (12-key) shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the numeric shortcut.
+     */
+    @Override
+    int getNumericModifiers();
+
+    /**
+     * Change the alphabetic shortcut associated with this item. The shortcut
+     * will be triggered when the key that generates the given character is
+     * pressed along with the modifier keys. Case is not significant and shortcut
+     * characters will be displayed in lower case. Note that menu items with
+     * the characters '\b' or '\n' as shortcuts will get triggered by the
+     * Delete key or Carriage Return key, respectively.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    @Override
+    MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers);
+
+    /**
+     * Return the modifier for this menu item's alphabetic shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the keyboard shortcut.
+     */
+    @Override
+    int getAlphabeticModifiers();
 }
\ No newline at end of file
diff --git a/compat/java/android/support/v4/util/MapCollections.java b/compat/java/android/support/v4/util/MapCollections.java
index 441f338..1a0ab6b 100644
--- a/compat/java/android/support/v4/util/MapCollections.java
+++ b/compat/java/android/support/v4/util/MapCollections.java
@@ -20,6 +20,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -49,6 +50,7 @@
 
         @Override
         public T next() {
+            if (!hasNext()) throw new NoSuchElementException();
             Object res = colGetEntry(mIndex, mOffset);
             mIndex++;
             mCanRemove = true;
@@ -84,6 +86,7 @@
 
         @Override
         public Map.Entry<K, V> next() {
+            if (!hasNext()) throw new NoSuchElementException();
             mIndex++;
             mEntryValid = true;
             return this;
diff --git a/compat/java/android/support/v4/view/LayoutInflaterCompat.java b/compat/java/android/support/v4/view/LayoutInflaterCompat.java
index 1444b58..50f494b 100644
--- a/compat/java/android/support/v4/view/LayoutInflaterCompat.java
+++ b/compat/java/android/support/v4/view/LayoutInflaterCompat.java
@@ -56,6 +56,7 @@
             return mDelegateFactory.onCreateView(parent, name, context, attributeSet);
         }
 
+        @Override
         public String toString() {
             return getClass().getName() + "{" + mDelegateFactory + "}";
         }
diff --git a/compat/java/android/support/v4/view/MenuItemCompat.java b/compat/java/android/support/v4/view/MenuItemCompat.java
index d21be25..0c5ba63 100644
--- a/compat/java/android/support/v4/view/MenuItemCompat.java
+++ b/compat/java/android/support/v4/view/MenuItemCompat.java
@@ -20,6 +20,8 @@
 import android.support.v4.internal.view.SupportMenuItem;
 import android.support.v4.os.BuildCompat;
 import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 
@@ -90,6 +92,12 @@
         CharSequence getContentDescription(MenuItem item);
         void setTooltipText(MenuItem item, CharSequence tooltipText);
         CharSequence getTooltipText(MenuItem item);
+        void setShortcut(MenuItem item, char numericChar, char alphaChar, int numericModifiers,
+                int alphaModifiers);
+        void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers);
+        int getAlphabeticModifiers(MenuItem item);
+        void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers);
+        int getNumericModifiers(MenuItem item);
     }
 
     /**
@@ -142,6 +150,29 @@
         public CharSequence getTooltipText(MenuItem item) {
             return null;
         }
+
+        @Override
+        public void setShortcut(MenuItem item, char numericChar, char alphaChar,
+                int numericModifiers, int alphaModifiers) {
+        }
+
+        @Override
+        public void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers) {
+        }
+
+        @Override
+        public int getAlphabeticModifiers(MenuItem item) {
+            return 0;
+        }
+
+        @Override
+        public void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers) {
+        }
+
+        @Override
+        public int getNumericModifiers(MenuItem item) {
+            return 0;
+        }
     }
 
     @RequiresApi(26)
@@ -165,6 +196,32 @@
         public CharSequence getTooltipText(MenuItem item) {
             return item.getTooltipText();
         }
+
+        @Override
+        public void setShortcut(MenuItem item, char numericChar, char alphaChar,
+                int numericModifiers, int alphaModifiers) {
+            item.setShortcut(numericChar, alphaChar, numericModifiers, alphaModifiers);
+        }
+
+        @Override
+        public void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers) {
+            item.setAlphabeticShortcut(alphaChar, alphaModifiers);
+        }
+
+        @Override
+        public int getAlphabeticModifiers(MenuItem item) {
+            return item.getAlphabeticModifiers();
+        }
+
+        @Override
+        public void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers) {
+            item.setNumericShortcut(numericChar, numericModifiers);
+        }
+
+        @Override
+        public int getNumericModifiers(MenuItem item) {
+            return item.getNumericModifiers();
+        }
     }
 
     /**
@@ -426,5 +483,116 @@
         return IMPL.getTooltipText(item);
     }
 
+    /**
+     * Change both the numeric and alphabetic shortcut associated with this
+     * item. Note that the shortcut will be triggered when the key that
+     * generates the given character is pressed along with the corresponding
+     * modifier key. Also note that case is not significant and that alphabetic
+     * shortcut characters will be handled in lower case.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key. This is the shortcut when
+     *        using a numeric (e.g., 12-key) keyboard.
+     * @param numericModifiers The numeric modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The alphabetic modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     */
+    public static void setShortcut(MenuItem item, char numericChar, char alphaChar,
+            int numericModifiers, int alphaModifiers) {
+        if (item instanceof SupportMenuItem) {
+            ((SupportMenuItem) item).setShortcut(numericChar, alphaChar, numericModifiers,
+                    alphaModifiers);
+        } else {
+            IMPL.setShortcut(item, numericChar, alphaChar, numericModifiers, alphaModifiers);
+        }
+    }
+
+    /**
+     * Change the numeric shortcut and modifiers associated with this item.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key.  This is the shortcut when
+     *                 using a 12-key (numeric) keyboard.
+     * @param numericModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     */
+    public static void setNumericShortcut(MenuItem item, char numericChar, int numericModifiers) {
+        if (item instanceof SupportMenuItem) {
+            ((SupportMenuItem) item).setNumericShortcut(numericChar, numericModifiers);
+        } else {
+            IMPL.setNumericShortcut(item, numericChar, numericModifiers);
+        }
+    }
+
+    /**
+     * Return the modifiers for this menu item's numeric (12-key) shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the numeric shortcut.
+     */
+    public int getNumericModifiers(MenuItem item) {
+        if (item instanceof SupportMenuItem) {
+            return ((SupportMenuItem) item).getNumericModifiers();
+        }
+        return IMPL.getNumericModifiers(item);
+    }
+
+    /**
+     * Change the alphabetic shortcut associated with this item. The shortcut
+     * will be triggered when the key that generates the given character is
+     * pressed along with the modifier keys. Case is not significant and shortcut
+     * characters will be displayed in lower case. Note that menu items with
+     * the characters '\b' or '\n' as shortcuts will get triggered by the
+     * Delete key or Carriage Return key, respectively.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     */
+    public static void setAlphabeticShortcut(MenuItem item, char alphaChar, int alphaModifiers) {
+        if (item instanceof SupportMenuItem) {
+            ((SupportMenuItem) item).setAlphabeticShortcut(alphaChar, alphaModifiers);
+        } else {
+            IMPL.setAlphabeticShortcut(item, alphaChar, alphaModifiers);
+        }
+    }
+
+    /**
+     * Return the modifier for this menu item's alphabetic shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the keyboard shortcut.
+     */
+    public int getAlphabeticModifiers(MenuItem item) {
+        if (item instanceof SupportMenuItem) {
+            return ((SupportMenuItem) item).getAlphabeticModifiers();
+        }
+        return IMPL.getAlphabeticModifiers(item);
+    }
+
     private MenuItemCompat() {}
 }
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index 91311be..54c2730 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -922,7 +922,6 @@
         }
 
         public void setTooltipText(View view, CharSequence tooltipText) {
-            ViewCompatICS.setTooltipText(view, tooltipText);
         }
     }
 
@@ -3321,12 +3320,9 @@
 
     /**
      * Sets the tooltip for the view.
-     * <p>
-     * Compatibility:
-     * <ul>
-     * <li>API &lt; 26: Sets or clears (when tooltip is null) the view's OnLongClickListener and
-     * OnHoverListener. Creates a Toast on long click or mouse hover.
-     * </ul>
+     *
+     * <p>Prior to API 26 this does nothing. Use TooltipCompat class from v7 appcompat library
+     * for a compatible tooltip implementation.</p>
      *
      * @param tooltipText the tooltip text
      */
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
index 632eae9..6bd1031 100644
--- a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
+++ b/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
@@ -1439,6 +1439,7 @@
             return new AccessibilityNodeInfo.AccessibilityAction(actionId, label);
         }
 
+        @SuppressWarnings("unchecked")
         @Override
         public List<Object> getActionList(AccessibilityNodeInfo info) {
             Object result = info.getActionList();
diff --git a/compat/java/android/support/v4/widget/PopupWindowCompat.java b/compat/java/android/support/v4/widget/PopupWindowCompat.java
index 698e718..5018e04 100644
--- a/compat/java/android/support/v4/widget/PopupWindowCompat.java
+++ b/compat/java/android/support/v4/widget/PopupWindowCompat.java
@@ -16,43 +16,29 @@
 
 package android.support.v4.widget;
 
-import android.support.annotation.RequiresApi;
 import android.os.Build;
+import android.support.annotation.RequiresApi;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.PopupWindow;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
 /**
- * Helper for accessing features in PopupWindow introduced after API level 4
- * in a backwards compatible fashion.
+ * Helper for accessing features in PopupWindow in a backwards compatible fashion.
  */
 public final class PopupWindowCompat {
-    /**
-     * Interface for the full API.
-     */
-    interface PopupWindowImpl {
-        void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, int gravity);
-        void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor);
-        boolean getOverlapAnchor(PopupWindow popupWindow);
-        void setWindowLayoutType(PopupWindow popupWindow, int layoutType);
-        int getWindowLayoutType(PopupWindow popupWindow);
-    }
 
-    /**
-     * Interface implementation that doesn't use anything above v4 APIs.
-     */
-    static class BasePopupWindowImpl implements PopupWindowImpl {
+    static class PopupWindowCompatBaseImpl {
         private static Method sSetWindowLayoutTypeMethod;
         private static boolean sSetWindowLayoutTypeMethodAttempted;
         private static Method sGetWindowLayoutTypeMethod;
         private static boolean sGetWindowLayoutTypeMethodAttempted;
 
-        @Override
         public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
                 int gravity) {
             final int hgrav = GravityCompat.getAbsoluteGravity(gravity,
@@ -65,17 +51,14 @@
             popup.showAsDropDown(anchor, xoff, yoff);
         }
 
-        @Override
         public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
             // noop
         }
 
-        @Override
         public boolean getOverlapAnchor(PopupWindow popupWindow) {
             return false;
         }
 
-        @Override
         public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
             if (!sSetWindowLayoutTypeMethodAttempted) {
                 try {
@@ -97,7 +80,6 @@
             }
         }
 
-        @Override
         public int getWindowLayoutType(PopupWindow popupWindow) {
             if (!sGetWindowLayoutTypeMethodAttempted) {
                 try {
@@ -125,63 +107,89 @@
      * Interface implementation for devices with at least KitKat APIs.
      */
     @RequiresApi(19)
-    static class KitKatPopupWindowImpl extends BasePopupWindowImpl {
+    static class PopupWindowCompatApi19Impl extends PopupWindowCompatBaseImpl {
         @Override
         public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
                 int gravity) {
-            PopupWindowCompatKitKat.showAsDropDown(popup, anchor, xoff, yoff, gravity);
+            popup.showAsDropDown(anchor, xoff, yoff, gravity);
         }
     }
 
     @RequiresApi(21)
-    static class Api21PopupWindowImpl extends KitKatPopupWindowImpl {
+    static class PopupWindowCompatApi21Impl extends PopupWindowCompatApi19Impl {
+        private static final String TAG = "PopupWindowCompatApi21";
+
+        private static Field sOverlapAnchorField;
+
+        static {
+            try {
+                sOverlapAnchorField = PopupWindow.class.getDeclaredField("mOverlapAnchor");
+                sOverlapAnchorField.setAccessible(true);
+            } catch (NoSuchFieldException e) {
+                Log.i(TAG, "Could not fetch mOverlapAnchor field from PopupWindow", e);
+            }
+        }
+
         @Override
         public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-            PopupWindowCompatApi21.setOverlapAnchor(popupWindow, overlapAnchor);
+            if (sOverlapAnchorField != null) {
+                try {
+                    sOverlapAnchorField.set(popupWindow, overlapAnchor);
+                } catch (IllegalAccessException e) {
+                    Log.i(TAG, "Could not set overlap anchor field in PopupWindow", e);
+                }
+            }
         }
 
         @Override
         public boolean getOverlapAnchor(PopupWindow popupWindow) {
-            return PopupWindowCompatApi21.getOverlapAnchor(popupWindow);
+            if (sOverlapAnchorField != null) {
+                try {
+                    return (Boolean) sOverlapAnchorField.get(popupWindow);
+                } catch (IllegalAccessException e) {
+                    Log.i(TAG, "Could not get overlap anchor field in PopupWindow", e);
+                }
+            }
+            return false;
         }
     }
 
     @RequiresApi(23)
-    static class Api23PopupWindowImpl extends Api21PopupWindowImpl {
+    static class PopupWindowCompatApi23Impl extends PopupWindowCompatApi21Impl {
         @Override
         public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
-            PopupWindowCompatApi23.setOverlapAnchor(popupWindow, overlapAnchor);
+            popupWindow.setOverlapAnchor(overlapAnchor);
         }
 
         @Override
         public boolean getOverlapAnchor(PopupWindow popupWindow) {
-            return PopupWindowCompatApi23.getOverlapAnchor(popupWindow);
+            return popupWindow.getOverlapAnchor();
         }
 
         @Override
         public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
-            PopupWindowCompatApi23.setWindowLayoutType(popupWindow, layoutType);
+            popupWindow.setWindowLayoutType(layoutType);
         }
 
         @Override
         public int getWindowLayoutType(PopupWindow popupWindow) {
-            return PopupWindowCompatApi23.getWindowLayoutType(popupWindow);
+            return popupWindow.getWindowLayoutType();
         }
     }
 
     /**
      * Select the correct implementation to use for the current platform.
      */
-    static final PopupWindowImpl IMPL;
+    static final PopupWindowCompatBaseImpl IMPL;
     static {
         if (Build.VERSION.SDK_INT >= 23) {
-            IMPL = new Api23PopupWindowImpl();
+            IMPL = new PopupWindowCompatApi23Impl();
         } else if (Build.VERSION.SDK_INT >= 21) {
-            IMPL = new Api21PopupWindowImpl();
+            IMPL = new PopupWindowCompatApi21Impl();
         } else if (Build.VERSION.SDK_INT >= 19) {
-            IMPL = new KitKatPopupWindowImpl();
+            IMPL = new PopupWindowCompatApi19Impl();
         } else {
-            IMPL = new BasePopupWindowImpl();
+            IMPL = new PopupWindowCompatBaseImpl();
         }
     }
 
@@ -232,12 +240,12 @@
 
     /**
      * Set the layout type for this window. This value will be passed through to
-     * {@link WindowManager.LayoutParams#type} therefore the value should match any value
-     * {@link WindowManager.LayoutParams#type} accepts.
+     * {@link android.view.WindowManager.LayoutParams#type} therefore the value should match any
+     * value {@link android.view.WindowManager.LayoutParams#type} accepts.
      *
      * @param layoutType Layout type for this window.
      *
-     * @see WindowManager.LayoutParams#type
+     * @see android.view.WindowManager.LayoutParams#type
      */
     public static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
         IMPL.setWindowLayoutType(popupWindow, layoutType);
diff --git a/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java b/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
index feee689..d302175 100644
--- a/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
+++ b/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.app;
 
+import android.annotation.SuppressLint;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -347,13 +348,14 @@
         }
     }
 
+    @SuppressLint("NewApi") // Intentionally looking up Notification.Action using reflection.
     private static boolean ensureActionReflectionReadyLocked() {
         if (sActionsAccessFailed) {
             return false;
         }
         try {
             if (sActionsField == null) {
-                sActionClass = Class.forName("android.app.Notification$Action");
+                sActionClass = Class.forName(Notification.Action.class.getName());
                 sActionIconField = sActionClass.getDeclaredField("icon");
                 sActionTitleField = sActionClass.getDeclaredField("title");
                 sActionIntentField = sActionClass.getDeclaredField("actionIntent");
diff --git a/compat/kitkat/android/support/v4/widget/PopupWindowCompatKitKat.java b/compat/kitkat/android/support/v4/widget/PopupWindowCompatKitKat.java
deleted file mode 100644
index 887301f..0000000
--- a/compat/kitkat/android/support/v4/widget/PopupWindowCompatKitKat.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2013 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.v4.widget;
-
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.widget.PopupWindow;
-
-/**
- * Implementation of PopupWindow compatibility that can call KitKat APIs.
- */
-
-@RequiresApi(19)
-class PopupWindowCompatKitKat {
-    public static void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
-            int gravity) {
-        popup.showAsDropDown(anchor, xoff, yoff, gravity);
-    }
-}
diff --git a/compat/tests/java/android/support/v4/testutils/TestUtils.java b/compat/tests/java/android/support/v4/testutils/TestUtils.java
index e44448d..70be082 100644
--- a/compat/tests/java/android/support/v4/testutils/TestUtils.java
+++ b/compat/tests/java/android/support/v4/testutils/TestUtils.java
@@ -17,9 +17,6 @@
 
 package android.support.v4.testutils;
 
-import java.lang.IllegalArgumentException;
-import java.lang.RuntimeException;
-
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
diff --git a/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java b/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java
new file mode 100644
index 0000000..c00d264
--- /dev/null
+++ b/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 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.v4.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ArrayMapCompatTest {
+
+    @Test
+    public void testCanNotIteratePastEnd_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<Map.Entry<String, String>> expectedEntriesToIterate = new HashSet<>(Arrays.asList(
+                entryOf("key 1", "value 1"),
+                entryOf("key 2", "value 2")
+        ));
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+
+        // Assert iteration over the expected two entries in any order
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> firstEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(firstEntry));
+
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> secondEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(secondEntry));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    private static <K, V> Map.Entry<K, V> entryOf(K key, V value) {
+        return new AbstractMap.SimpleEntry<>(key, value);
+    }
+
+    private static <K, V> Map.Entry<K, V> copyOf(Map.Entry<K, V> entry) {
+        return entryOf(entry.getKey(), entry.getValue());
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_keySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedKeysToIterate = new HashSet<>(Arrays.asList("key 1", "key 2"));
+        Iterator<String> iterator = map.keySet().iterator();
+
+        // Assert iteration over the expected two keys in any order
+        assertTrue(iterator.hasNext());
+        String firstKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(firstKey));
+
+        assertTrue(iterator.hasNext());
+        String secondKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(secondKey));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_valuesIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedValuesToIterate = new HashSet<>(Arrays.asList("value 1", "value 2"));
+        Iterator<String> iterator = map.values().iterator();
+
+        // Assert iteration over the expected two values in any order
+        assertTrue(iterator.hasNext());
+        String firstValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(firstValue));
+
+        assertTrue(iterator.hasNext());
+        String secondValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(secondValue));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+}
diff --git a/compat/tests/java/android/support/v4/util/ArraySetCompatTest.java b/compat/tests/java/android/support/v4/util/ArraySetCompatTest.java
new file mode 100644
index 0000000..10a0b1b
--- /dev/null
+++ b/compat/tests/java/android/support/v4/util/ArraySetCompatTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.v4.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ArraySetCompatTest {
+    @Test
+    public void testCanNotIteratePastEnd() {
+        ArraySet<String> set = new ArraySet<>();
+        set.add("value");
+        Iterator<String> iterator = set.iterator();
+
+        assertTrue(iterator.hasNext());
+        assertEquals("value", iterator.next());
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+}
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index c40022d..03de595 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -14,6 +14,7 @@
     androidTestCompile libs.mockito_core
     androidTestCompile libs.dexmaker
     androidTestCompile libs.dexmaker_mockito
+    androidTestCompile project(':support-testutils')
 }
 
 android {
diff --git a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
index 840effb..7ca0054 100644
--- a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -48,8 +48,7 @@
  * support in custom {@link View}s that represent a collection of View-like
  * logical items. It extends {@link AccessibilityNodeProviderCompat} and
  * simplifies many aspects of providing information to accessibility services
- * and managing accessibility focus. This class does not currently support
- * hierarchies of logical items.
+ * and managing accessibility focus.
  * <p>
  * Clients should override abstract methods on this class and attach it to the
  * host view using {@link ViewCompat#setAccessibilityDelegate}:
diff --git a/core-ui/tests/java/android/support/v4/testutils/PollingCheck.java b/core-ui/tests/java/android/support/v4/testutils/PollingCheck.java
deleted file mode 100644
index b4271f4..0000000
--- a/core-ui/tests/java/android/support/v4/testutils/PollingCheck.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.v4.testutils;
-
-import java.util.concurrent.Callable;
-
-import junit.framework.Assert;
-
-public abstract class PollingCheck {
-    private static final long TIME_SLICE = 50;
-    private long mTimeout = 3000;
-
-    public static interface PollingCheckCondition {
-        boolean canProceed();
-    }
-
-    public PollingCheck() {
-    }
-
-    public PollingCheck(long timeout) {
-        mTimeout = timeout;
-    }
-
-    protected abstract boolean check();
-
-    public void run() {
-        if (check()) {
-            return;
-        }
-
-        long timeout = mTimeout;
-        while (timeout > 0) {
-            try {
-                Thread.sleep(TIME_SLICE);
-            } catch (InterruptedException e) {
-                Assert.fail("unexpected InterruptedException");
-            }
-
-            if (check()) {
-                return;
-            }
-
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail("unexpected timeout");
-    }
-
-    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
-            throws Exception {
-        while (timeout > 0) {
-            if (condition.call()) {
-                return;
-            }
-
-            Thread.sleep(TIME_SLICE);
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail(message.toString());
-    }
-
-    public static void waitFor(final PollingCheckCondition condition) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return condition.canProceed();
-            }
-        }.run();
-    }
-
-    public static void waitFor(long timeout, final PollingCheckCondition condition) {
-        new PollingCheck(timeout) {
-            @Override
-            protected boolean check() {
-                return condition.canProceed();
-            }
-        }.run();
-    }
-}
\ No newline at end of file
diff --git a/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java b/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java
index c6f07e5..3884e8f 100644
--- a/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java
+++ b/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java
@@ -16,14 +16,9 @@
 
 package android.support.v4.testutils;
 
-import java.lang.String;
-import java.util.List;
-
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.test.espresso.matcher.BoundedMatcher;
-import android.support.v4.testutils.TestUtils;
 import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.view.ViewGroup;
@@ -35,6 +30,8 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 
+import java.util.List;
+
 public class TestUtilsMatchers {
     /**
      * Returns a matcher that matches views which have specific background color.
diff --git a/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java b/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
index dfa7a22..a83a976 100644
--- a/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
+++ b/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
@@ -97,7 +97,7 @@
         protected ArrayList<Pair<String, Q>> mEntries = new ArrayList<>();
 
         public void add(String title, Q content) {
-            mEntries.add(new Pair(title, content));
+            mEntries.add(new Pair<>(title, content));
         }
 
         @Override
diff --git a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java b/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
index cdbc2cb..04a2835 100644
--- a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
+++ b/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
@@ -37,8 +37,8 @@
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
+import android.support.testutils.PollingCheck;
 import android.support.v4.BaseInstrumentationTestCase;
-import android.support.v4.testutils.PollingCheck;
 import android.view.View;
 
 import org.junit.Before;
diff --git a/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java b/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java
index cfaea83..90e0038 100644
--- a/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java
+++ b/core-utils/api21/android/support/v4/provider/DocumentsContractApi21.java
@@ -32,8 +32,12 @@
 
     public static Uri createFile(Context context, Uri self, String mimeType,
             String displayName) {
-        return DocumentsContract.createDocument(context.getContentResolver(), self, mimeType,
-                displayName);
+        try {
+            return DocumentsContract.createDocument(context.getContentResolver(), self, mimeType,
+                    displayName);
+        } catch (Exception e) {
+            return null;
+        }
     }
 
     public static Uri createDirectory(Context context, Uri self, String displayName) {
@@ -71,7 +75,12 @@
     }
 
     public static Uri renameTo(Context context, Uri self, String displayName) {
-        return DocumentsContract.renameDocument(context.getContentResolver(), self, displayName);
+        try {
+            return DocumentsContract.renameDocument(context.getContentResolver(), self,
+                    displayName);
+        } catch (Exception e) {
+            return null;
+        }
     }
 
     private static void closeQuietly(AutoCloseable closeable) {
diff --git a/core-utils/java/android/support/v4/app/AppLaunchChecker.java b/core-utils/java/android/support/v4/app/AppLaunchChecker.java
index 86219d4..f8beb91 100644
--- a/core-utils/java/android/support/v4/app/AppLaunchChecker.java
+++ b/core-utils/java/android/support/v4/app/AppLaunchChecker.java
@@ -19,7 +19,6 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
diff --git a/core-utils/java/android/support/v4/content/AsyncTaskLoader.java b/core-utils/java/android/support/v4/content/AsyncTaskLoader.java
index c31a8cd..faa13ad 100644
--- a/core-utils/java/android/support/v4/content/AsyncTaskLoader.java
+++ b/core-utils/java/android/support/v4/content/AsyncTaskLoader.java
@@ -157,6 +157,9 @@
     protected boolean onCancelLoad() {
         if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask);
         if (mTask != null) {
+            if (!mStarted) {
+                mContentChanged = true;
+            }
             if (mCancellingTask != null) {
                 // There was a pending task already waiting for a previous
                 // one being canceled; just drop it.
diff --git a/core-utils/java/android/support/v4/content/FileProvider.java b/core-utils/java/android/support/v4/content/FileProvider.java
index 9e82d63..c49fc12 100644
--- a/core-utils/java/android/support/v4/content/FileProvider.java
+++ b/core-utils/java/android/support/v4/content/FileProvider.java
@@ -32,6 +32,7 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.provider.OpenableColumns;
+import android.support.annotation.GuardedBy;
 import android.text.TextUtils;
 import android.webkit.MimeTypeMap;
 
@@ -339,7 +340,7 @@
 
     private static final File DEVICE_ROOT = new File("/");
 
-    // @GuardedBy("sCache")
+    @GuardedBy("sCache")
     private static HashMap<String, PathStrategy> sCache = new HashMap<String, PathStrategy>();
 
     private PathStrategy mStrategy;
diff --git a/core-utils/java/android/support/v4/content/MimeTypeFilter.java b/core-utils/java/android/support/v4/content/MimeTypeFilter.java
index 6d26dcb..8734c4d 100644
--- a/core-utils/java/android/support/v4/content/MimeTypeFilter.java
+++ b/core-utils/java/android/support/v4/content/MimeTypeFilter.java
@@ -27,14 +27,16 @@
  * <p>Wildcards are allowed only instead of the entire type or subtype with a tree prefix.
  * Eg. image\/*, *\/* is a valid filter and will match image/jpeg, but image/j* is invalid and
  * it will not match image/jpeg. Suffixes and parameters are not supported, and they are treated
- * as part of the subtype during matching.
+ * as part of the subtype during matching. Neither type nor subtype can be empty.
  *
  * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike the formal
  * RFC definitions. As a result, you should always write these elements with lower case letters,
  * or use {@link android.content.Intent#normalizeMimeType} to ensure that they are converted to
  * lower case.</em>
  *
- * <p>Null MIME type doesn't match anything.
+ * <p>MIME types can be null or ill-formatted. In such case they won't match anything.
+ *
+ * <p>MIME type filters must be correctly formatted, or an exception will be thrown.
  */
 public final class MimeTypeFilter {
 
@@ -42,8 +44,16 @@
     }
 
     private static boolean mimeTypeAgainstFilter(
-            @NonNull String[] mimeTypeParts, @NonNull String[]filterParts) {
-        if (mimeTypeParts.length != 2 || filterParts.length != 2) {
+            @NonNull String[] mimeTypeParts, @NonNull String[] filterParts) {
+        if (filterParts.length != 2) {
+            throw new IllegalArgumentException(
+                    "Ill-formatted MIME type filter. Must be type/subtype.");
+        }
+        if (filterParts[0].isEmpty() || filterParts[1].isEmpty()) {
+            throw new IllegalArgumentException(
+                    "Ill-formatted MIME type filter. Type or subtype empty.");
+        }
+        if (mimeTypeParts.length != 2) {
             return false;
         }
         if (!"*".equals(filterParts[0])
@@ -59,7 +69,7 @@
     }
 
     /**
-     * See the class description for the matching behavior details.
+     * Matches one nullable MIME type against one MIME type filter.
      * @return True if the {@code mimeType} matches the {@code filter}.
      */
     public static boolean matches(@Nullable String mimeType, @NonNull String filter) {
@@ -74,7 +84,7 @@
     }
 
     /**
-     * See the class description for the matching behavior details.
+     * Matches one nullable MIME type against an array of MIME type filters.
      * @return The first matching filter, or null if nothing matches.
      */
     public static String matches(
@@ -95,7 +105,7 @@
     }
 
     /**
-     * See the class description for the matching behavior details.
+     * Matches multiple MIME types against an array of MIME type filters.
      * @return The first matching MIME type, or null if nothing matches.
      */
     public static String matches(
@@ -116,8 +126,8 @@
     }
 
     /**
-     * See the class description for the matching behavior details.
-     * @return The list of matching MIME types, or empty list if nothing matches.
+     * Matches multiple MIME types against an array of MIME type filters.
+     * @return The list of matching MIME types, or empty array if nothing matches.
      */
     public static String[] matchesMany(
             @Nullable String[] mimeTypes, @NonNull String filter) {
diff --git a/core-utils/java/android/support/v4/provider/SingleDocumentFile.java b/core-utils/java/android/support/v4/provider/SingleDocumentFile.java
index 606c351..77c4e49 100644
--- a/core-utils/java/android/support/v4/provider/SingleDocumentFile.java
+++ b/core-utils/java/android/support/v4/provider/SingleDocumentFile.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.net.Uri;
 import android.support.annotation.RequiresApi;
-import android.support.v4.provider.DocumentsContractApi19;
 
 @RequiresApi(19)
 class SingleDocumentFile extends DocumentFile {
diff --git a/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java b/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
index 41ba0f0..a429d8d 100644
--- a/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
+++ b/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
@@ -137,7 +137,11 @@
     }
 
     public static boolean delete(Context context, Uri self) {
-        return DocumentsContract.deleteDocument(context.getContentResolver(), self);
+        try {
+            return DocumentsContract.deleteDocument(context.getContentResolver(), self);
+        } catch (Exception e) {
+            return false;
+        }
     }
 
     public static boolean exists(Context context, Uri self) {
diff --git a/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java b/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java
index 4fec6dd..21748ff 100644
--- a/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java
+++ b/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java
@@ -25,6 +25,8 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.test.MoreAsserts;
 
+import junit.framework.Assert;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -53,14 +55,11 @@
         assertFalse(MimeTypeFilter.matches((String) null, "image/"));
         assertFalse(MimeTypeFilter.matches((String) null, "image/jpeg"));
 
-        // Invalid MIME types, filters or swapped arguments.
-        assertFalse(MimeTypeFilter.matches((String) null, ""));
-        assertFalse(MimeTypeFilter.matches("", ""));
-        assertFalse(MimeTypeFilter.matches("", "*/"));
+        // Null and invalid MIME types.
+        assertFalse(MimeTypeFilter.matches((String) null, "*/*"));
         assertFalse(MimeTypeFilter.matches("", "*/*"));
         assertFalse(MimeTypeFilter.matches("image/", "*/*"));
-        assertFalse(MimeTypeFilter.matches("image/", "image/"));
-        assertFalse(MimeTypeFilter.matches("*/*", "image/jpeg"));
+        assertFalse(MimeTypeFilter.matches("*/", "*/*"));
     }
 
     @Test
@@ -83,7 +82,6 @@
                 "image/jpeg", new String[] {"*/png", "*/jpeg"}));
 
         assertNull(MimeTypeFilter.matches("image/jpeg", new String[] {}));
-        assertNull(MimeTypeFilter.matches("image/jpeg", new String[] {}));
 
         assertNull(MimeTypeFilter.matches("image/jpeg", new String[] {"image/png", "video/jpeg"}));
         assertNull(MimeTypeFilter.matches("image/jpeg", new String[] {"video/jpeg", "image/png"}));
@@ -92,14 +90,11 @@
         assertNull(MimeTypeFilter.matches(null, new String[] {"image/"}));
         assertNull(MimeTypeFilter.matches(null, new String[] {"image/jpeg"}));
 
-        // Invalid MIME types, filters or swapped arguments.
-        assertNull(MimeTypeFilter.matches(null, new String[] {""}));
-        assertNull(MimeTypeFilter.matches("", new String[] {""}));
-        assertNull(MimeTypeFilter.matches("", new String[] {"*/"}));
-        assertNull(MimeTypeFilter.matches("", new String[] {"*/*"}));
-        assertNull(MimeTypeFilter.matches("image/", new String[] {"*/*"}));
-        assertNull(MimeTypeFilter.matches("image/", new String[] {"image/"}));
-        assertNull(MimeTypeFilter.matches("*/*", new String[] {"image/jpeg"}));
+        // Null and invalid MIME types.
+        assertNull(MimeTypeFilter.matches((String) null, new String[] { "*/*" }));
+        assertNull(MimeTypeFilter.matches("", new String[] { "*/*" }));
+        assertNull(MimeTypeFilter.matches("image/", new String[] { "*/*" }));
+        assertNull(MimeTypeFilter.matches("*/", new String[] { "*/*" }));
     }
 
     @Test
@@ -112,10 +107,151 @@
                 MimeTypeFilter.matchesMany(new String[] {"image/jpeg", "image/png"}, "*/JpEg"));
 
         MoreAsserts.assertEquals(new String[] {},
-                MimeTypeFilter.matchesMany(new String[] {"image/jpeg", "image/png"}, "video/ogv"));
-        MoreAsserts.assertEquals(new String[] {},
-                MimeTypeFilter.matchesMany(new String[] {"image/jpeg", "image/png"}, ""));
+                MimeTypeFilter.matchesMany(new String[] {"*/", "image/"}, "*/*"));
         MoreAsserts.assertEquals(new String[] {},
                 MimeTypeFilter.matchesMany(new String[] {}, "*/*"));
     }
+
+    @Test
+    public void illegalFilters() throws Exception {
+        try {
+            MimeTypeFilter.matches("image/jpeg", "");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "*/");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", "*/*/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "*/");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches(new String[] { "image/jpeg" }, "*/*/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "*" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "*/" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "/*" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matches("image/jpeg", new String[] { "*/*/*" });
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "*/");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            MimeTypeFilter.matchesMany(new String[] { "image/jpeg" }, "*/*/*");
+            Assert.fail("Illegal filter, should throw.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
 }
diff --git a/core-utils/tests/java/android/support/v4/provider/GrantActivity.java b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
index c4dbb27..a354201 100644
--- a/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
+++ b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
@@ -20,7 +20,6 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.os.Bundle;
-import android.support.v4.provider.DocumentFileTest;
 
 /**
  * Stub activity used to request a permission grant for
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index 740b125..6bc7dd5 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -12,6 +12,8 @@
     androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
+
+    androidTestCompile project(':support-testutils')
 }
 
 android {
diff --git a/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java b/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java
index c0fadae..07d21a8 100644
--- a/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java
+++ b/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java
@@ -26,6 +26,7 @@
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.rule.ServiceTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.testutils.PollingCheck;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/customtabs/tests/src/android/support/customtabs/PostMessageTest.java b/customtabs/tests/src/android/support/customtabs/PostMessageTest.java
index d20a06d..e832b23 100644
--- a/customtabs/tests/src/android/support/customtabs/PostMessageTest.java
+++ b/customtabs/tests/src/android/support/customtabs/PostMessageTest.java
@@ -29,6 +29,7 @@
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.rule.ServiceTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.testutils.PollingCheck;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/design/base/android/support/design/widget/AnimationUtils.java b/design/base/android/support/design/widget/AnimationUtils.java
index 8ef1722..3613afd 100644
--- a/design/base/android/support/design/widget/AnimationUtils.java
+++ b/design/base/android/support/design/widget/AnimationUtils.java
@@ -19,7 +19,6 @@
 import android.support.v4.view.animation.FastOutLinearInInterpolator;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.support.v4.view.animation.LinearOutSlowInInterpolator;
-import android.view.animation.Animation;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
@@ -43,18 +42,4 @@
         return startValue + Math.round(fraction * (endValue - startValue));
     }
 
-    static class AnimationListenerAdapter implements Animation.AnimationListener {
-        @Override
-        public void onAnimationStart(Animation animation) {
-        }
-
-        @Override
-        public void onAnimationEnd(Animation animation) {
-        }
-
-        @Override
-        public void onAnimationRepeat(Animation animation) {
-        }
-    }
-
 }
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
index f764ffa..72b80bf 100644
--- a/design/src/android/support/design/internal/BottomNavigationItemView.java
+++ b/design/src/android/support/design/internal/BottomNavigationItemView.java
@@ -31,6 +31,7 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v7.view.menu.MenuItemImpl;
 import android.support.v7.view.menu.MenuView;
+import android.support.v7.widget.TooltipCompat;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -100,7 +101,7 @@
         setTitle(itemData.getTitle());
         setId(itemData.getItemId());
         setContentDescription(itemData.getContentDescription());
-        ViewCompat.setTooltipText(this, itemData.getTooltipText());
+        TooltipCompat.setTooltipText(this, itemData.getTooltipText());
     }
 
     public void setItemPosition(int position) {
diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java
index 18133be..bf33454 100644
--- a/design/src/android/support/design/internal/BottomNavigationMenuView.java
+++ b/design/src/android/support/design/internal/BottomNavigationMenuView.java
@@ -295,19 +295,25 @@
             return;
         }
         int previousSelectedId = mSelectedItemId;
+
         for (int i = 0; i < menuSize; i++) {
-            mPresenter.setUpdateSuspended(true);
             MenuItem item = mMenu.getItem(i);
             if (item.isChecked()) {
                 mSelectedItemId = item.getItemId();
                 mSelectedItemPosition = i;
             }
-            mButtons[i].initialize((MenuItemImpl) item, 0);
-            mPresenter.setUpdateSuspended(false);
         }
         if (previousSelectedId != mSelectedItemId) {
-            TransitionManager.beginDelayedTransition(this);
+            // Note: this has to be called before BottomNavigationItemView#initialize().
+            TransitionManager.beginDelayedTransition(this, mSet);
         }
+
+        for (int i = 0; i < menuSize; i++) {
+            mPresenter.setUpdateSuspended(true);
+            mButtons[i].initialize((MenuItemImpl) mMenu.getItem(i), 0);
+            mPresenter.setUpdateSuspended(false);
+        }
+
     }
 
     private BottomNavigationItemView getNewItem() {
diff --git a/design/src/android/support/design/internal/NavigationMenuItemView.java b/design/src/android/support/design/internal/NavigationMenuItemView.java
index 2a4367c..53ef24a 100644
--- a/design/src/android/support/design/internal/NavigationMenuItemView.java
+++ b/design/src/android/support/design/internal/NavigationMenuItemView.java
@@ -35,6 +35,7 @@
 import android.support.v4.widget.TextViewCompat;
 import android.support.v7.view.menu.MenuItemImpl;
 import android.support.v7.view.menu.MenuView;
+import android.support.v7.widget.TooltipCompat;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
@@ -117,7 +118,7 @@
         setIcon(itemData.getIcon());
         setActionView(itemData.getActionView());
         setContentDescription(itemData.getContentDescription());
-        ViewCompat.setTooltipText(this, itemData.getTooltipText());
+        TooltipCompat.setTooltipText(this, itemData.getTooltipText());
         adjustAppearance();
     }
 
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
index 6d664b5..e85c38d 100644
--- a/design/src/android/support/design/widget/BottomSheetBehavior.java
+++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
@@ -381,7 +381,8 @@
             setStateInternal(STATE_EXPANDED);
             return;
         }
-        if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) {
+        if (mNestedScrollingChildRef == null || target != mNestedScrollingChildRef.get()
+                || !mNestedScrolled) {
             return;
         }
         int top;
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 8d88bbb..909a9a8 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -27,7 +27,6 @@
 import android.graphics.Typeface;
 import android.os.Build;
 import android.support.annotation.ColorInt;
-import android.support.design.R;
 import android.support.v4.text.TextDirectionHeuristicsCompat;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
diff --git a/design/src/android/support/design/widget/DirectedAcyclicGraph.java b/design/src/android/support/design/widget/DirectedAcyclicGraph.java
index 189daf4..85a32cd 100644
--- a/design/src/android/support/design/widget/DirectedAcyclicGraph.java
+++ b/design/src/android/support/design/widget/DirectedAcyclicGraph.java
@@ -97,7 +97,7 @@
      * @return a list containing any outgoing edges, or null if there are none.
      */
     @Nullable
-    List getOutgoingEdges(@NonNull T node) {
+    List<T> getOutgoingEdges(@NonNull T node) {
         ArrayList<T> result = null;
         for (int i = 0, size = mGraph.size(); i < size; i++) {
             ArrayList<T> edges = mGraph.valueAt(i);
diff --git a/design/src/android/support/design/widget/DrawableUtils.java b/design/src/android/support/design/widget/DrawableUtils.java
index 1e2e6cf..df1c04b 100644
--- a/design/src/android/support/design/widget/DrawableUtils.java
+++ b/design/src/android/support/design/widget/DrawableUtils.java
@@ -18,10 +18,8 @@
 
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer;
-import android.os.Build;
 import android.util.Log;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
 /**
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 17b4cd5..9b81465 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -51,6 +51,7 @@
 import android.support.v4.widget.TextViewCompat;
 import android.support.v7.app.ActionBar;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.TooltipCompat;
 import android.text.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -1765,7 +1766,7 @@
                     iconView.requestLayout();
                 }
             }
-            ViewCompat.setTooltipText(this, hasText ? null : contentDesc);
+            TooltipCompat.setTooltipText(this, hasText ? null : contentDesc);
         }
 
         public Tab getTab() {
diff --git a/design/src/android/support/design/widget/ThemeUtils.java b/design/src/android/support/design/widget/ThemeUtils.java
index ffdc3f4..821dcb6 100644
--- a/design/src/android/support/design/widget/ThemeUtils.java
+++ b/design/src/android/support/design/widget/ThemeUtils.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.support.design.R;
 
 class ThemeUtils {
 
@@ -29,9 +28,7 @@
     static void checkAppCompatTheme(Context context) {
         TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);
         final boolean failed = !a.hasValue(0);
-        if (a != null) {
-            a.recycle();
-        }
+        a.recycle();
         if (failed) {
             throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "
                     + "(or descendant) with the design library.");
diff --git a/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java b/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
index 0c09e7b..e06fa0a 100644
--- a/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
+++ b/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
@@ -17,17 +17,18 @@
 package android.support.design.widget;
 
 import android.app.Activity;
-import android.support.test.rule.ActivityTestRule;
+import android.support.test.rule.BootlegActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+
 import org.junit.Rule;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
 public abstract class BaseInstrumentationTestCase<A extends Activity> {
     @Rule
-    public final ActivityTestRule<A> mActivityTestRule;
+    public final BootlegActivityTestRule<A> mActivityTestRule;
 
     protected BaseInstrumentationTestCase(Class<A> activityClass) {
-        mActivityTestRule = new ActivityTestRule<A>(activityClass);
+        mActivityTestRule = new BootlegActivityTestRule<>(activityClass);
     }
 }
diff --git a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java b/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
index 940eb5a..c434f9f 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
@@ -23,11 +23,10 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
diff --git a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
index c01b785..09bf43c 100755
--- a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
+++ b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
@@ -72,7 +72,7 @@
         protected ArrayList<Pair<String, Q>> mEntries = new ArrayList<>();
 
         public void add(String title, Q content) {
-            mEntries.add(new Pair(title, content));
+            mEntries.add(new Pair<>(title, content));
         }
 
         @Override
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java b/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
index 1ae3a29..613ae6e 100644
--- a/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
+++ b/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
@@ -16,7 +16,6 @@
 package android.support.design.widget;
 
 import android.support.design.test.R;
-import android.support.v7.widget.Toolbar;
 
 public class TextInputLayoutActivity extends BaseTestActivity {
     @Override
diff --git a/design/tests/src/android/support/test/rule/BootlegActivityTestRule.java b/design/tests/src/android/support/test/rule/BootlegActivityTestRule.java
new file mode 100644
index 0000000..b12edfa
--- /dev/null
+++ b/design/tests/src/android/support/test/rule/BootlegActivityTestRule.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.test.rule;
+
+import android.app.Activity;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.intercepting.SingleActivityFactory;
+
+/**
+ * An extension of existing {@link ActivityTestRule} that contains a fix for finishActivity()
+ * method (cr/138555678).
+ *
+ * Remove this once we move to Android Test Runner 0.7.
+ */
+public class BootlegActivityTestRule<T extends Activity> extends ActivityTestRule {
+    public BootlegActivityTestRule(Class activityClass) {
+        super(activityClass);
+    }
+
+    public BootlegActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
+        super(activityClass, initialTouchMode);
+    }
+
+    public BootlegActivityTestRule(Class<T> activityClass, boolean initialTouchMode,
+            boolean launchActivity) {
+        super(activityClass, initialTouchMode, launchActivity);
+    }
+
+    public BootlegActivityTestRule(
+            SingleActivityFactory activityFactory,
+            boolean initialTouchMode, boolean launchActivity) {
+        super(activityFactory, initialTouchMode, launchActivity);
+    }
+
+    public BootlegActivityTestRule(Class<T> activityClass,
+            @NonNull String targetPackage, int launchFlags,
+            boolean initialTouchMode, boolean launchActivity) {
+        super(activityClass, targetPackage, launchFlags, initialTouchMode, launchActivity);
+    }
+
+    @Override
+    public void finishActivity() {
+        super.finishActivity();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Override
+    public T getActivity() {
+        return (T) super.getActivity();
+    }
+}
diff --git a/dynamic-animation/Android.mk b/dynamic-animation/Android.mk
index b8ba139..1b33094 100644
--- a/dynamic-animation/Android.mk
+++ b/dynamic-animation/Android.mk
@@ -20,7 +20,6 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/dynamic-animation/src/android/support/animation/AnimationHandler.java b/dynamic-animation/src/android/support/animation/AnimationHandler.java
index 948b93e..fac9cd2 100644
--- a/dynamic-animation/src/android/support/animation/AnimationHandler.java
+++ b/dynamic-animation/src/android/support/animation/AnimationHandler.java
@@ -175,17 +175,6 @@
         }
     }
 
-    private int getCallbackSize() {
-        int count = 0;
-        int size = mAnimationCallbacks.size();
-        for (int i = size - 1; i >= 0; i--) {
-            if (mAnimationCallbacks.get(i) != null) {
-                count++;
-            }
-        }
-        return count;
-    }
-
     /**
      * Default provider of timing pulse that uses Choreographer for frame callbacks.
      */
diff --git a/dynamic-animation/src/android/support/animation/DynamicAnimation.java b/dynamic-animation/src/android/support/animation/DynamicAnimation.java
index ee90df2..7285943 100644
--- a/dynamic-animation/src/android/support/animation/DynamicAnimation.java
+++ b/dynamic-animation/src/android/support/animation/DynamicAnimation.java
@@ -527,9 +527,7 @@
         if (mLastFrameTime == 0) {
             // First frame.
             mLastFrameTime = frameTime;
-            if (mStartValueIsSet) {
-                setPropertyValue(mValue);
-            }
+            setPropertyValue(mValue);
             return false;
         }
         long deltaT = frameTime - mLastFrameTime;
@@ -555,39 +553,7 @@
      * @param deltaT time elapsed in millisecond since last frame
      * @return whether the animation has finished
      */
-    boolean updateValueAndVelocity(long deltaT) {
-        if (deltaT < 0) {
-            throw new UnsupportedOperationException("Cannot play animation backwards");
-        }
-        if (deltaT == 0) {
-            return false;
-        }
-
-        // Break down the deltaT into 4ms intervals.
-        long increment = Math.min(4, deltaT);
-
-        int totalT = (int) deltaT;
-        int i = 0;
-        float velocity = mVelocity;
-        float value = mValue;
-        for (i = 0; i <= totalT; i += increment) {
-            float acceleration = getAcceleration(value, velocity);
-            float newVelocity = acceleration * increment / 1000 + velocity;
-            value += (velocity + newVelocity) / 2 * increment / 1000;
-            velocity = newVelocity;
-            if (i == totalT) {
-                break;
-            } else if (i + increment > deltaT) {
-                increment = totalT - i;
-            }
-        }
-
-        mVelocity = (float) velocity;
-        mValue = (float) value;
-
-        // TODO: need to update values to end value if true, otherwise there'll be precision loss.
-        return isAtEquilibrium(mValue, mVelocity);
-    }
+    abstract boolean updateValueAndVelocity(long deltaT);
 
     /**
      * Internal method to reset the animation states when animation is finished/canceled.
diff --git a/dynamic-animation/tests/src/android/support/dynamicanimation/tests/SpringTests.java b/dynamic-animation/tests/src/android/support/dynamicanimation/tests/SpringTests.java
index 801ed39..ebceeea 100644
--- a/dynamic-animation/tests/src/android/support/dynamicanimation/tests/SpringTests.java
+++ b/dynamic-animation/tests/src/android/support/dynamicanimation/tests/SpringTests.java
@@ -16,6 +16,8 @@
 
 package android.support.dynamicanimation.tests;
 
+import static junit.framework.Assert.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -36,11 +38,13 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.AndroidRuntimeException;
 import android.view.View;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 
 @MediumTest
@@ -50,6 +54,9 @@
     public View mView1;
     public View mView2;
 
+    @Rule
+    public ExpectedException mExpectedException = ExpectedException.none();
+
     public SpringTests() {
         mActivityTestRule = new ActivityTestRule<>(AnimationActivity.class);
     }
@@ -273,6 +280,26 @@
     }
 
     /**
+     * Test negative stiffness and expect exception.
+     */
+    @Test
+    public void testInvalidStiffness() {
+        SpringForce spring = new SpringForce();
+        mExpectedException.expect(IllegalArgumentException.class);
+        spring.setStiffness(-5f);
+    }
+
+    /**
+     * Test negative dampingRatio and expect exception.
+     */
+    @Test
+    public void testInvalidDampingRatio() {
+        SpringForce spring = new SpringForce();
+        mExpectedException.expect(IllegalArgumentException.class);
+        spring.setDampingRatio(-5f);
+    }
+
+    /**
      * Remove an update listener and an end listener, and check that there are no interaction after
      * removal.
      */
@@ -427,6 +454,177 @@
         assertEquals(0, mView1.getScrollX());
     }
 
+    /**
+     * Makes sure all the properties getter works.
+     */
+    @Test
+    public void testAllProperties() {
+        final DynamicAnimation.ViewProperty[] properties = {
+                DynamicAnimation.ALPHA, DynamicAnimation.TRANSLATION_X,
+                DynamicAnimation.TRANSLATION_Y, DynamicAnimation.TRANSLATION_Z,
+                DynamicAnimation.SCALE_X, DynamicAnimation.SCALE_Y, DynamicAnimation.ROTATION,
+                DynamicAnimation.ROTATION_X, DynamicAnimation.ROTATION_Y,
+                DynamicAnimation.X, DynamicAnimation.Y, DynamicAnimation.Z,
+                DynamicAnimation.SCROLL_X, DynamicAnimation.SCROLL_Y,
+        };
+
+        mView1.setAlpha(0f);
+        mView1.setTranslationX(0f);
+        mView1.setTranslationY(0f);
+        mView1.setTranslationZ(0f);
+
+        mView1.setScaleX(0f);
+        mView1.setScaleY(0f);
+
+        mView1.setRotation(0f);
+        mView1.setRotationX(0f);
+        mView1.setRotationY(0f);
+
+        mView1.setX(0f);
+        mView1.setY(0f);
+        mView1.setZ(0f);
+
+        mView1.setScrollX(0);
+        mView1.setScrollY(0);
+
+        View mockView = mock(View.class);
+
+        final SpringAnimation[] anims = new SpringAnimation[properties.length];
+        final DynamicAnimation.OnAnimationUpdateListener[] mockListeners =
+                new DynamicAnimation.OnAnimationUpdateListener[properties.length];
+        for (int i = 0; i < properties.length; i++) {
+            anims[i] = new SpringAnimation(mView1, properties[i], 1);
+            final int finalI = i;
+            anims[i].addUpdateListener(
+                    new DynamicAnimation.OnAnimationUpdateListener() {
+                        boolean mIsFirstFrame = true;
+                        @Override
+                        public void onAnimationUpdate(DynamicAnimation animation, float value,
+                                float velocity) {
+                            if (mIsFirstFrame) {
+                                assertEquals(value, 0f, 0f);
+                            }
+                            mIsFirstFrame = false;
+                        }
+                    });
+            mockListeners[i] = mock(DynamicAnimation.OnAnimationUpdateListener.class);
+            anims[i].addUpdateListener(mockListeners[i]);
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = properties.length - 1; i >= 0; i--) {
+                    anims[i].start();
+                }
+            }
+        });
+
+        for (int i = 0; i < properties.length; i++) {
+            int timeout = i == 0 ? 100 : 0;
+            verify(mockListeners[i], timeout(timeout).atLeast(1)).onAnimationUpdate(
+                    any(SpringAnimation.class), any(float.class), any(float.class));
+        }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < properties.length; i++) {
+                    anims[i].cancel();
+                }
+            }
+        });
+    }
+
+    /**
+     * Test start() on a test thread.
+     */
+    @Test
+    public void testStartOnNonMainThread() {
+        mExpectedException.expect(AndroidRuntimeException.class);
+        SpringAnimation anim = new SpringAnimation(mView1, DynamicAnimation.ALPHA, 0f);
+        anim.start();
+    }
+
+    /**
+     * Test cancel() on a test thread.
+     */
+    @Test
+    public void testCancelOnNonMainThread() {
+        mExpectedException.expect(AndroidRuntimeException.class);
+        SpringAnimation anim = new SpringAnimation(mView1, DynamicAnimation.ALPHA, 0f);
+        anim.cancel();
+    }
+
+    /**
+     * Test skipToEnd() on a test thread.
+     */
+    @Test
+    public void testSkipToEndOnNonMainThread() {
+        mExpectedException.expect(AndroidRuntimeException.class);
+        SpringAnimation anim = new SpringAnimation(mView1, DynamicAnimation.ALPHA, 0f);
+        anim.skipToEnd();
+    }
+
+    /**
+     * Test invalid start condition: no spring position specified, final position > max value,
+     * and final position < min. Expect exception in all these cases.
+     */
+    @Test
+    public void testInvalidStartingCondition() {
+        final SpringAnimation anim = new SpringAnimation(mView1, DynamicAnimation.X);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                // Expect exception from not setting spring final position before calling start.
+                try {
+                    anim.start();
+                    fail("No exception is thrown when calling start() from non-main thread.");
+                } catch (UnsupportedOperationException e) {
+                }
+
+                // Expect exception from having a final position < min value
+                try {
+                    anim.setMinValue(50);
+                    // Final position < min value, expect exception.
+                    anim.setStartValue(50).animateToFinalPosition(40);
+                    fail("No exception is thrown when spring position is less than min value.");
+                } catch (UnsupportedOperationException e) {
+                }
+
+                // Expect exception from not setting spring final position before calling start.
+                try {
+                    anim.setMaxValue(60);
+                    // Final position < min value, expect exception.
+                    anim.setStartValue(60).animateToFinalPosition(70);
+                    fail("No exception is thrown when spring position is greater than max value.");
+                } catch (UnsupportedOperationException e) {
+                }
+            }
+        });
+    }
+
+    /**
+     * Try skipToEnd() on an undamped spring, and expect exception.
+     */
+    @Test
+    public void testUndampedSpring() {
+        final SpringAnimation anim = new SpringAnimation(mView1, DynamicAnimation.Y);
+        anim.setSpring(new SpringForce(10).setDampingRatio(0));
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                // Expect exception for ending an undamped spring.
+                try {
+                    anim.skipToEnd();
+                    fail("No exception is thrown when calling skipToEnd() on an undamped spring");
+                } catch (UnsupportedOperationException e) {
+                }
+            }
+        });
+
+    }
+
     static class MyEndListener implements DynamicAnimation.OnAnimationEndListener {
         public long endTime = -1;
 
diff --git a/emoji/appcompat/AndroidManifest.xml b/emoji/appcompat/AndroidManifest.xml
new file mode 100644
index 0000000..81bc0f8
--- /dev/null
+++ b/emoji/appcompat/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.text.emoji.appcompat">
+    <uses-sdk android:minSdkVersion="19"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    <application />
+</manifest>
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
new file mode 100644
index 0000000..6074e02
--- /dev/null
+++ b/emoji/appcompat/build.gradle
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'support-emoji-appcompat'
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    compile project(':support-emoji')
+    compile project(':support-appcompat-v7')
+
+    androidTestCompile (libs.test_runner) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile (libs.espresso_core) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+}
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 19
+    }
+
+    sourceSets {
+        main.java.srcDir 'src'
+    }
+}
+
+supportLibrary {
+    name 'Android Emoji AppCompat'
+    inceptionYear '2017'
+    description 'EmojiCompat Widgets for AppCompat integration'
+}
\ No newline at end of file
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java
new file mode 100644
index 0000000..8672beb
--- /dev/null
+++ b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatButton;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+
+/**
+ * AppCompatButton widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiAppCompatButton extends AppCompatButton {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiAppCompatButton(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiAppCompatButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiAppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java
new file mode 100644
index 0000000..2689294
--- /dev/null
+++ b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatEditText;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * AppCompatEditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}.
+ */
+public class EmojiAppCompatEditText extends AppCompatEditText {
+    private EmojiEditTextHelper mEmojiEditTextHelper;
+    private boolean mInitialized;
+
+    public EmojiAppCompatEditText(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiAppCompatEditText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiAppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            setKeyListener(getKeyListener());
+        }
+    }
+
+    @Override
+    public void setKeyListener(android.text.method.KeyListener input) {
+        super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+        return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
+    }
+
+    private EmojiEditTextHelper getEmojiEditTextHelper() {
+        if (mEmojiEditTextHelper == null) {
+            mEmojiEditTextHelper = new EmojiEditTextHelper(this);
+        }
+        return mEmojiEditTextHelper;
+    }
+}
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java
new file mode 100644
index 0000000..00c99ab
--- /dev/null
+++ b/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatTextView;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+
+/**
+ * AppCompatTextView widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiAppCompatTextView extends AppCompatTextView {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiAppCompatTextView(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiAppCompatTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiAppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/dynamic-animation/AndroidManifest-make.xml b/emoji/bundled-typeface/AndroidManifest.xml
similarity index 77%
copy from dynamic-animation/AndroidManifest-make.xml
copy to emoji/bundled-typeface/AndroidManifest.xml
index bfe97cc..2c5bc46 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/emoji/bundled-typeface/AndroidManifest.xml
@@ -14,6 +14,8 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+          package="android.support.text.emoji.typeface">
+    <uses-sdk android:minSdkVersion="19"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}"/>
+    <application/>
+</manifest>
\ No newline at end of file
diff --git a/emoji/bundled-typeface/assets/NotoColorEmojiCompat.ttf b/emoji/bundled-typeface/assets/NotoColorEmojiCompat.ttf
new file mode 100644
index 0000000..0c59d8e
--- /dev/null
+++ b/emoji/bundled-typeface/assets/NotoColorEmojiCompat.ttf
Binary files differ
diff --git a/emoji/bundled-typeface/build.gradle b/emoji/bundled-typeface/build.gradle
new file mode 100644
index 0000000..5014649
--- /dev/null
+++ b/emoji/bundled-typeface/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: android.support.SupportLibraryPlugin
+archivesBaseName = 'support-emoji-typeface'
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 19
+    }
+
+    sourceSets {
+        main.java.srcDir 'src'
+        main.assets.srcDirs 'assets'
+    }
+}
+
+dependencies {
+    compile project(path: ':support-emoji')
+}
+
+supportLibrary {
+    name 'Android Emoji Compat'
+    inceptionYear '2017'
+    description 'Library bundled with assets to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.'
+}
\ No newline at end of file
diff --git a/emoji/bundled-typeface/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java b/emoji/bundled-typeface/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java
new file mode 100644
index 0000000..5b0740d
--- /dev/null
+++ b/emoji/bundled-typeface/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.bundled;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.support.annotation.NonNull;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.MetadataRepo;
+import android.support.v4.util.Preconditions;
+
+/**
+ * {@link EmojiCompat.Config} implementation that loads the metadata using AssetManager and
+ * bundled resources.
+ * <p/>
+ * <pre><code>EmojiCompat.init(new BundledEmojiCompatConfig(context));</code></pre>
+ *
+ * @see EmojiCompat
+ */
+public class BundledEmojiCompatConfig extends EmojiCompat.Config {
+
+    /**
+     * Default constructor.
+     *
+     * @param context Context instance
+     */
+    public BundledEmojiCompatConfig(@NonNull Context context) {
+        super(new BundledMetadataLoader(context));
+    }
+
+    private static class BundledMetadataLoader implements EmojiCompat.MetadataLoader {
+        private final Context mContext;
+
+        private BundledMetadataLoader(@NonNull Context context) {
+            mContext = context.getApplicationContext();
+        }
+
+        @Override
+        public void load(@NonNull EmojiCompat.LoaderCallback loaderCallback) {
+            Preconditions.checkNotNull(loaderCallback, "loaderCallback cannot be null");
+            final InitRunnable runnable = new InitRunnable(mContext, loaderCallback);
+            final Thread thread = new Thread(runnable);
+            thread.setDaemon(false);
+            thread.start();
+        }
+
+    }
+
+    private static class InitRunnable implements Runnable {
+        private static final String FONT_NAME = "NotoColorEmojiCompat.ttf";
+        private final EmojiCompat.LoaderCallback mLoaderCallback;
+        private final Context mContext;
+
+        private InitRunnable(final Context context,
+                final EmojiCompat.LoaderCallback loaderCallback) {
+            mContext = context;
+            mLoaderCallback = loaderCallback;
+        }
+
+        @Override
+        public void run() {
+            try {
+                final AssetManager assetManager = mContext.getAssets();
+                final MetadataRepo resourceIndex = MetadataRepo.create(assetManager, FONT_NAME);
+                mLoaderCallback.onLoaded(resourceIndex);
+            } catch (Throwable t) {
+                mLoaderCallback.onFailed(t);
+            }
+        }
+    }
+}
diff --git a/dynamic-animation/AndroidManifest-make.xml b/emoji/core/AndroidManifest.xml
similarity index 78%
copy from dynamic-animation/AndroidManifest-make.xml
copy to emoji/core/AndroidManifest.xml
index bfe97cc..b288921 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/emoji/core/AndroidManifest.xml
@@ -14,6 +14,8 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
+          package="android.support.text.emoji">
+    <uses-sdk android:minSdkVersion="19"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    <application />
 </manifest>
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
new file mode 100644
index 0000000..cc389d1
--- /dev/null
+++ b/emoji/core/build.gradle
@@ -0,0 +1,41 @@
+apply plugin: android.support.SupportLibraryPlugin
+apply plugin: 'org.anarres.jarjar'
+archivesBaseName = 'support-emoji'
+
+dependencies {
+    compile project(':support-compat')
+
+    compile jarjar.repackage {
+        from files('third_party/flatbuffers/flatbuffers-java-1.6.0.jar')
+        destinationName 'flatbuffers-java-1.6.0-repacked.jar'
+        classRename 'com.google.flatbuffers.**', 'com.google.flatbuffers.emojicompat.@1'
+    }
+
+    androidTestCompile (libs.test_runner) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile (libs.espresso_core) {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
+}
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 19
+    }
+
+    sourceSets {
+        main.java.srcDir 'src'
+    }
+}
+
+supportLibrary {
+    name 'Android Emoji Compat'
+    inceptionYear '2017'
+    description 'Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.'
+}
\ No newline at end of file
diff --git a/emoji/core/src/android/support/text/emoji/EmojiCompat.java b/emoji/core/src/android/support/text/emoji/EmojiCompat.java
new file mode 100644
index 0000000..cd235a3
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiCompat.java
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.AnyThread;
+import android.support.annotation.GuardedBy;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.ArraySet;
+import android.support.v4.util.Preconditions;
+import android.text.Editable;
+import android.text.method.KeyListener;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Main class to keep Android devices up to date with the newest emojis by adding {@link EmojiSpan}s
+ * to a given {@link CharSequence}. It is a singleton class that can be configured using a {@link
+ * EmojiCompat.Config} instance.
+ * <p/>
+ * EmojiCompat has to be initialized using {@link #init(EmojiCompat.Config)} function before it can
+ * process a {@link CharSequence}.
+ * <pre><code>EmojiCompat.init(&#47;* a config instance *&#47;);</code></pre>
+ * <p/>
+ * It is suggested to make the initialization as early as possible in your app. Please check {@link
+ * EmojiCompat.Config} for more configuration parameters.
+ * <p/>
+ * During initialization information about emojis is loaded on a background thread. Before the
+ * EmojiCompat instance is initialized, calls to functions such as {@link
+ * EmojiCompat#process(CharSequence)} will throw an exception. You can use the {@link InitCallback}
+ * class to be informed about the state of initialization.
+ * <p/>
+ * After initialization the {@link #get()} function can be used to get the configured instance and
+ * the {@link #process(CharSequence)} function can be used to update a CharSequence with emoji
+ * EmojiSpans.
+ * <p/>
+ * <pre><code>CharSequence processedSequence = EmojiCompat.get().process("some string")</pre>
+ */
+@AnyThread
+public class EmojiCompat {
+    /**
+     * Key in {@link EditorInfo#extras} that represents the emoji metadata version used by the
+     * widget. The existence of the value means that the widget is using EmojiCompat.
+     * <p/>
+     * If exists, the value for the key is an {@code int} and can be used to query EmojiCompat to
+     * see whether the widget has the ability to display a certain emoji using
+     * {@link #hasEmojiGlyph(CharSequence, int)}.
+     */
+    public static final String EDITOR_INFO_METAVERSION_KEY =
+            "android.support.text.emoji.emojiCompat_metadataVersion";
+
+    /**
+     * Key in {@link EditorInfo#extras} that represents {@link
+     * EmojiCompat.Config#setReplaceAll(boolean)} configuration parameter. The key is added only if
+     * EmojiCompat is used by the widget. If exists, the value is a boolean.
+     */
+    public static final String EDITOR_INFO_REPLACE_ALL_KEY =
+            "android.support.text.emoji.emojiCompat_replaceAll";
+
+    private static final Object sInstanceLock = new Object();
+
+    @GuardedBy("sInstanceLock")
+    private static volatile EmojiCompat sInstance;
+
+    private final ReadWriteLock mInitLock;
+
+    @GuardedBy("mInitLock")
+    private final Set<InitCallback> mInitCallbacks;
+
+    @GuardedBy("mInitLock")
+    @LoadState
+    private int mLoadState;
+
+    private final Config mConfig;
+    private final Handler mMainHandler;
+
+    /**
+     * Responsible to process a CharSequence and add the spans. @{code Null} until the time the
+     * metadata is loaded.
+     */
+    private EmojiProcessor mProcessor;
+
+    /**
+     * Keeps the information about emojis. Null until the time the data is loaded.
+     */
+    private MetadataRepo mMetadataRepo;
+
+    private static final int LOAD_STATE_LOADING = 0;
+    private static final int LOAD_STATE_SUCCESS = 1;
+    private static final int LOAD_STATE_FAIL = 2;
+
+    @IntDef({LOAD_STATE_LOADING, LOAD_STATE_SUCCESS, LOAD_STATE_FAIL})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface LoadState {
+    }
+
+    /**
+     * Private constructor for singleton instance.
+     *
+     * @see #init(Config)
+     */
+    private EmojiCompat(@NonNull final Config config) {
+        mInitLock = new ReentrantReadWriteLock();
+        mConfig = config;
+        mMainHandler = new Handler(Looper.getMainLooper());
+        mInitCallbacks = new ArraySet<>();
+        if (mConfig.mInitCallbacks != null && !mConfig.mInitCallbacks.isEmpty()) {
+            mInitCallbacks.addAll(mConfig.mInitCallbacks);
+        }
+        loadMetadata();
+    }
+
+    /**
+     * Initialize the singleton instance with a configuration.
+     *
+     * @see EmojiCompat.Config
+     */
+    public static EmojiCompat init(@NonNull final Config config) {
+        if (sInstance == null) {
+            synchronized (sInstanceLock) {
+                if (sInstance == null) {
+                    sInstance = new EmojiCompat(config);
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    /**
+     * Used by the tests to reset EmojiCompat with a new configuration. Every time it is called a
+     * new instance is created with the new configuration.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    public static EmojiCompat reset(@NonNull final Config config) {
+        synchronized (sInstanceLock) {
+            sInstance = new EmojiCompat(config);
+        }
+        return sInstance;
+    }
+
+    /**
+     * Used by the tests to reset EmojiCompat with a new singleton instance.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    public static EmojiCompat reset(final EmojiCompat emojiCompat) {
+        synchronized (sInstanceLock) {
+            sInstance = emojiCompat;
+        }
+        return sInstance;
+    }
+
+    /**
+     * Return singleton EmojiCompat instance. Should be called after
+     * {@link #init(EmojiCompat.Config)} is called to initialize the singleton instance.
+     *
+     * @return EmojiCompat instance
+     *
+     * @throws IllegalStateException if called before {@link #init(EmojiCompat.Config)}
+     */
+    public static EmojiCompat get() {
+        synchronized (sInstanceLock) {
+            Preconditions.checkState(sInstance != null,
+                    "EmojiCompat is not initialized. Please call EmojiCompat.init() first");
+            return sInstance;
+        }
+    }
+
+    private void loadMetadata() {
+        mInitLock.writeLock().lock();
+        try {
+            mLoadState = LOAD_STATE_LOADING;
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+
+        try {
+            mConfig.mMetadataLoader.load(new LoaderCallback() {
+                @Override
+                public void onLoaded(@NonNull MetadataRepo metadataRepo) {
+                    onMetadataLoadSuccess(metadataRepo);
+                }
+
+                @Override
+                public void onFailed(@Nullable Throwable throwable) {
+                    onMetadataLoadFailed(throwable);
+                }
+            });
+        } catch (Throwable t) {
+            onMetadataLoadFailed(t);
+        }
+    }
+
+    private void onMetadataLoadSuccess(@NonNull final MetadataRepo metadataRepo) {
+        if (metadataRepo == null) {
+            onMetadataLoadFailed(new IllegalArgumentException("metadataRepo cannot be null"));
+            return;
+        }
+
+        mMetadataRepo = metadataRepo;
+        mProcessor = new EmojiProcessor(mMetadataRepo, new SpanFactory(),
+                mConfig.mReplaceAll, mConfig.mMaxEmojiPerText);
+
+        final Collection<InitCallback> initCallbacks = new ArrayList<>();
+        mInitLock.writeLock().lock();
+        try {
+            mLoadState = LOAD_STATE_SUCCESS;
+            initCallbacks.addAll(mInitCallbacks);
+            mInitCallbacks.clear();
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+
+        mMainHandler.post(new ListenerDispatcher(initCallbacks, mLoadState));
+    }
+
+    private void onMetadataLoadFailed(@Nullable final Throwable throwable) {
+        final Collection<InitCallback> initCallbacks = new ArrayList<>();
+        mInitLock.writeLock().lock();
+        try {
+            mLoadState = LOAD_STATE_FAIL;
+            initCallbacks.addAll(mInitCallbacks);
+            mInitCallbacks.clear();
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+        mMainHandler.post(new ListenerDispatcher(initCallbacks, mLoadState, throwable));
+    }
+
+    /**
+     * Registers an initialization callback. If the initialization is already completed by the time
+     * the listener is added, the callback functions are called immediately. Callbacks are called on
+     * the main looper.
+     *
+     * @param initCallback the initialization callback to register, cannot be {@code null}
+     *
+     * @see #unregisterInitCallback(InitCallback)
+     */
+    public void registerInitCallback(@NonNull InitCallback initCallback) {
+        Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+
+        mInitLock.writeLock().lock();
+        try {
+            if (mLoadState == LOAD_STATE_SUCCESS || mLoadState == LOAD_STATE_FAIL) {
+                mMainHandler.post(new ListenerDispatcher(initCallback, mLoadState));
+            } else {
+                mInitCallbacks.add(initCallback);
+            }
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Unregisters a callback that was added before.
+     *
+     * @param initCallback the callback to be removed, cannot be {@code null}
+     */
+    public void unregisterInitCallback(@NonNull InitCallback initCallback) {
+        Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+        mInitLock.writeLock().lock();
+        try {
+            mInitCallbacks.remove(initCallback);
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * @return {@code true} if EmojiCompat is successfully initialized
+     */
+    public boolean isInitialized() {
+        mInitLock.readLock().lock();
+        try {
+            return mLoadState == LOAD_STATE_SUCCESS;
+        } finally {
+            mInitLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Handles onKeyDown commands from a {@link KeyListener} and if {@code keyCode} is one of
+     * {@link KeyEvent#KEYCODE_DEL} or {@link KeyEvent#KEYCODE_FORWARD_DEL} it tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted with the characters it covers.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param editable Editable instance passed to {@link KeyListener#onKeyDown(android.view.View,
+     *                 Editable, int, KeyEvent)}
+     * @param keyCode keyCode passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *                int, KeyEvent)}
+     * @param event KeyEvent passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *              int, KeyEvent)}
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    public static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
+            final KeyEvent event) {
+        return EmojiProcessor.handleOnKeyDown(editable, keyCode, event);
+    }
+
+    /**
+     * Handles deleteSurroundingText commands from {@link InputConnection} and tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param inputConnection InputConnection instance
+     * @param editable TextView.Editable instance
+     * @param beforeLength the number of characters before the cursor to be deleted
+     * @param afterLength the number of characters after the cursor to be deleted
+     * @param inCodePoints {@code true} if length parameters are in codepoints
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    public static boolean handleDeleteSurroundingText(
+            @NonNull final InputConnection inputConnection, @NonNull final Editable editable,
+            @IntRange(from = 0) final int beforeLength, @IntRange(from = 0) final int afterLength,
+            final boolean inCodePoints) {
+        return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable, beforeLength,
+                afterLength, inCodePoints);
+    }
+
+    /**
+     * Returns {@code true} if EmojiCompat is capable of rendering an emoji.
+     *
+     * @param sequence CharSequence representing the emoji
+     *
+     * @return {@code true} if EmojiCompat can render given emoji, cannot be {@code null}
+     *
+     * @throws IllegalStateException if not initialized yet
+     */
+    public boolean hasEmojiGlyph(@NonNull final CharSequence sequence) {
+        Preconditions.checkState(isInitialized(), "Not initialized yet");
+        Preconditions.checkNotNull(sequence, "sequence cannot be null");
+        return mProcessor.getEmojiMetadata(sequence) != null;
+    }
+
+    /**
+     * Returns {@code true} if EmojiCompat is capable of rendering an emoji at the given metadata
+     * version.
+     *
+     * @param sequence CharSequence representing the emoji
+     * @param metadataVersion the metadata version to check against
+     *
+     * @return {@code true} if EmojiCompat can render given emoji, cannot be {@code null}
+     *
+     * @throws IllegalStateException if not initialized yet
+     */
+    public boolean hasEmojiGlyph(@NonNull final CharSequence sequence, final int metadataVersion) {
+        Preconditions.checkState(isInitialized(), "Not initialized yet");
+        Preconditions.checkNotNull(sequence, "sequence cannot be null");
+        final EmojiMetadata emojiMetadata = mProcessor.getEmojiMetadata(sequence);
+        return emojiMetadata != null && emojiMetadata.getCompatAdded() <= metadataVersion;
+    }
+
+    /**
+     * Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+     *
+     * @param charSequence CharSequence to add the EmojiSpans
+     *
+     * @throws IllegalStateException if not initialized yet
+     * @see #process(CharSequence, int, int)
+     */
+    public CharSequence process(@NonNull final CharSequence charSequence) {
+        // since charSequence might be null here we have to check it. Passing through here to the
+        // main function so that it can do all the checks including isInitialized. It will also
+        // be the main point that decides what to return.
+        @IntRange(from = 0) final int length = charSequence == null ? 0 : charSequence.length();
+        return process(charSequence, 0, length);
+    }
+
+    /**
+     * Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+     * <p>
+     * <ul>
+     * <li>If no emojis are found, {@code charSequence} given as the input is returned without
+     * any changes. i.e. charSequence is a String, and no emojis are found, the same String is
+     * returned.</li>
+     * <li>If the given input is not a Spannable (such as String), and at least one emoji is found
+     * a new {@link android.text.Spannable} instance is returned. </li>
+     * <li>If the given input is a Spannable, the same instance is returned. </li>
+     * </ul>
+     *
+     * @param charSequence CharSequence to add the EmojiSpans, cannot be {@code null}
+     * @param start start index in the charSequence to look for emojis, should be greater than or
+     *              equal to {@code 0}, also less than {@code charSequence.length()}
+     * @param end end index in the charSequence to look for emojis, should be greater than or
+     *            equal to {@code start} parameter, also less than {@code charSequence.length()}
+     *
+     * @throws IllegalStateException if not initialized yet
+     */
+    public CharSequence process(@NonNull final CharSequence charSequence,
+            @IntRange(from = 0) final int start, @IntRange(from = 0) final int end) {
+        Preconditions.checkState(isInitialized(), "Not initialized yet");
+        return mProcessor.process(charSequence, start, end);
+    }
+
+    /**
+     * Returns the Typeface instance that is created using the emoji font.
+     *
+     * @return {@link Typeface} instance that is created using the emoji font
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    Typeface getTypeface() {
+        if (mMetadataRepo != null) {
+            return mMetadataRepo.getTypeface();
+        }
+        return null;
+    }
+
+    /**
+     * Updates the EditorInfo attributes in order to communicate information to Keyboards.
+     *
+     * @param outAttrs EditorInfo instance passed to
+     *                 {@link android.widget.TextView#onCreateInputConnection(EditorInfo)}
+     *
+     * @see #EDITOR_INFO_METAVERSION_KEY
+     * @see #EDITOR_INFO_REPLACE_ALL_KEY
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void updateEditorInfoAttrs(@NonNull final EditorInfo outAttrs) {
+        if (isInitialized() && outAttrs != null && outAttrs.extras != null) {
+            outAttrs.extras.putInt(EDITOR_INFO_METAVERSION_KEY, mMetadataRepo.getMetadataVersion());
+            outAttrs.extras.putBoolean(EDITOR_INFO_REPLACE_ALL_KEY, mConfig.mReplaceAll);
+        }
+    }
+
+    /**
+     * Factory class that creates the EmojiSpans. By default it creates {@link TypefaceEmojiSpan}.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    static class SpanFactory {
+        /**
+         * Create EmojiSpan instance.
+         *
+         * @param metadata EmojiMetadata instance
+         *
+         * @return EmojiSpan instance
+         */
+        EmojiSpan createSpan(@NonNull final EmojiMetadata metadata) {
+            return new TypefaceEmojiSpan(metadata);
+        }
+    }
+
+    /**
+     * Listener class for the initialization of the EmojiCompat.
+     */
+    public abstract static class InitCallback {
+        /**
+         * Called when EmojiCompat is initialized and the emoji data is loaded.
+         */
+        public void onInitialized() {
+        }
+
+        /**
+         * Called when an unrecoverable error occurs during EmojiCompat initialization.
+         */
+        public void onFailed(@Nullable Throwable throwable) {
+        }
+    }
+
+    /**
+     * Interface to load emoji metadata.
+     */
+    public interface MetadataLoader {
+        /**
+         * Start loading the metadata. When the loading operation is finished {@link
+         * LoaderCallback#onLoaded(MetadataRepo)} or
+         * {@link LoaderCallback#onFailed(Throwable)}
+         * should be called.
+         *
+         * @param loaderCallback callback to signal the loading state
+         */
+        void load(@NonNull LoaderCallback loaderCallback);
+    }
+
+    /**
+     * Callback to inform EmojiCompat about the state of the metadata load. Passed to MetadataLoader
+     * during {@link MetadataLoader#load(LoaderCallback)} call.
+     */
+    public abstract static class LoaderCallback {
+        /**
+         * Called by {@link MetadataLoader} when metadata is loaded successfully.
+         *
+         * @param metadataRepo MetadataRepo instance, cannot be {@code null}
+         */
+        public abstract void onLoaded(@NonNull MetadataRepo metadataRepo);
+
+        /**
+         * Called by {@link MetadataLoader} if an error occurs while loading the metadata.
+         *
+         * @param throwable the exception that caused the failure, {@code nullable}
+         */
+        public abstract void onFailed(@Nullable Throwable throwable);
+    }
+
+    /**
+     * Configuration class for EmojiCompat.
+     *
+     * @see #init(EmojiCompat.Config)
+     */
+    public abstract static class Config {
+        private final MetadataLoader mMetadataLoader;
+        /**
+         * Measurements on Pixel XL, Android N MR2, EditText delete operation takes 7ms for
+         * 100 EmojiSpans.
+         */
+        private int mMaxEmojiPerText = 100;
+        private boolean mReplaceAll;
+        private Set<InitCallback> mInitCallbacks;
+
+        /**
+         * Default constructor.
+         *
+         * @param metadataLoader MetadataLoader instance, cannot be {@code null}
+         */
+        protected Config(@NonNull final MetadataLoader metadataLoader) {
+            Preconditions.checkNotNull(metadataLoader, "metadataLoader cannot be null.");
+            mMetadataLoader = metadataLoader;
+        }
+
+        /**
+         * Set the limit of EmojiSpans to be added to a CharSequence. The number of spans in a
+         * CharSequence affects the performance of the EditText, TextView.
+         * <p/>
+         * Default value is {@code 100}.
+         *
+         * @param maxEmojiPerText maximum number of EmojiSpans to be added to a single
+         *                        CharSequence, should be equal or greater than 0
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config setMaxEmojiPerText(@IntRange(from = 0) final int maxEmojiPerText) {
+            Preconditions.checkArgumentNonnegative(maxEmojiPerText,
+                    "maxEmojiPerText cannot be negative");
+            mMaxEmojiPerText = maxEmojiPerText;
+            return this;
+        }
+
+        /**
+         * Registers an initialization callback.
+         *
+         * @param initCallback the initialization callback to register, cannot be {@code null}
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config registerInitCallback(@NonNull InitCallback initCallback) {
+            Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+            if (mInitCallbacks == null) {
+                mInitCallbacks = new ArraySet<>();
+            }
+
+            mInitCallbacks.add(initCallback);
+
+            return this;
+        }
+
+        /**
+         * Unregisters a callback that was added before.
+         *
+         * @param initCallback the initialization callback to be removed, cannot be {@code null}
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config unregisterInitCallback(@NonNull InitCallback initCallback) {
+            Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
+            if (mInitCallbacks != null) {
+                mInitCallbacks.remove(initCallback);
+            }
+            return this;
+        }
+
+        /**
+         * Determines whether EmojiCompat should replace all the emojis it finds with the
+         * EmojiSpans. By default EmojiCompat tries its best to understand if the system already
+         * can render an emoji and do not replace those emojis.
+         *
+         * @param replaceAll replace all emojis found with EmojiSpans
+         *
+         * @return EmojiCompat.Config instance
+         */
+        public Config setReplaceAll(final boolean replaceAll) {
+            mReplaceAll = replaceAll;
+            return this;
+        }
+    }
+
+    /**
+     * Runnable to call success/failure case for the listeners.
+     */
+    private static class ListenerDispatcher implements Runnable {
+        private final List<InitCallback> mInitCallbacks;
+        private final Throwable mThrowable;
+        private final int mLoadState;
+
+        ListenerDispatcher(@NonNull final InitCallback initCallback,
+                @LoadState final int loadState) {
+            this(Arrays.asList(Preconditions.checkNotNull(initCallback,
+                    "initCallback cannot be null")), loadState, null);
+        }
+
+        ListenerDispatcher(@NonNull final Collection<InitCallback> initCallbacks,
+                @LoadState final int loadState) {
+            this(initCallbacks, loadState, null);
+        }
+
+        ListenerDispatcher(@NonNull final Collection<InitCallback> initCallbacks,
+                @LoadState final int loadState,
+                @Nullable final Throwable throwable) {
+            Preconditions.checkNotNull(initCallbacks, "initCallbacks cannot be null");
+            mInitCallbacks = new ArrayList<>(initCallbacks);
+            mLoadState = loadState;
+            mThrowable = throwable;
+        }
+
+        @Override
+        public void run() {
+            final int size = mInitCallbacks.size();
+            switch (mLoadState) {
+                case LOAD_STATE_SUCCESS:
+                    for (int i = 0; i < size; i++) {
+                        mInitCallbacks.get(i).onInitialized();
+                    }
+                    break;
+                case LOAD_STATE_FAIL:
+                default:
+                    for (int i = 0; i < size; i++) {
+                        mInitCallbacks.get(i).onFailed(mThrowable);
+                    }
+                    break;
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/EmojiMetadata.java b/emoji/core/src/android/support/text/emoji/EmojiMetadata.java
new file mode 100644
index 0000000..cdc916d
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiMetadata.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.flatbuffer.MetadataItem;
+import android.support.text.emoji.flatbuffer.MetadataList;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Information about a single emoji.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@AnyThread
+public class EmojiMetadata {
+    /**
+     * Defines whether the system can render the emoji.
+     */
+    @IntDef({HAS_GLYPH_UNKNOWN, HAS_GLYPH_ABSENT, HAS_GLYPH_EXISTS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface HasGlyph {
+    }
+
+    /**
+     * Not calculated on device yet.
+     */
+    public static final int HAS_GLYPH_UNKNOWN = 0;
+
+    /**
+     * Device cannot render the emoji.
+     */
+    public static final int HAS_GLYPH_ABSENT = 1;
+
+    /**
+     * Device can render the emoji.
+     */
+    public static final int HAS_GLYPH_EXISTS = 2;
+
+    /**
+     * @see #getMetadataItem()
+     */
+    private static final ThreadLocal<MetadataItem> sMetadataItem = new ThreadLocal<>();
+
+    /**
+     * Index of the EmojiMetadata in {@link MetadataList}.
+     */
+    private final int mIndex;
+
+    /**
+     * MetadataRepo that holds this instance.
+     */
+    private final MetadataRepo mMetadataRepo;
+
+    /**
+     * Whether the system can render the emoji. Calculated at runtime on the device.
+     */
+    @HasGlyph
+    private volatile int mHasGlyph = HAS_GLYPH_UNKNOWN;
+
+    EmojiMetadata(@NonNull final MetadataRepo metadataRepo, @IntRange(from = 0) final int index) {
+        mMetadataRepo = metadataRepo;
+        mIndex = index;
+    }
+
+    /**
+     * Draws the emoji represented by this EmojiMetadata onto a canvas with origin at (x,y), using
+     * the specified paint.
+     *
+     * @param canvas Canvas to be drawn
+     * @param x x-coordinate of the origin of the emoji being drawn
+     * @param y y-coordinate of the baseline of the emoji being drawn
+     * @param paint Paint used for the text (e.g. color, size, style)
+     */
+    public void draw(@NonNull final Canvas canvas, final float x, final float y,
+            @NonNull final Paint paint) {
+        // MetadataRepo.getEmojiCharArray() is a continous array of chars that is used to store the
+        // chars for emojis. since all emojis are mapped to a single codepoint, and since it is 2
+        // chars wide, we assume that the start index of the current emoji is mIndex * 2, and it is
+        // 2 chars long.
+        final int charArrayStartIndex = mIndex * 2;
+        canvas.drawText(mMetadataRepo.getEmojiCharArray(), charArrayStartIndex, 2, x, y, paint);
+    }
+
+    /**
+     * @return a ThreadLocal instance of MetadataItem for this EmojiMetadata
+     */
+    private MetadataItem getMetadataItem() {
+        MetadataItem result = sMetadataItem.get();
+        if (result == null) {
+            result = new MetadataItem();
+            sMetadataItem.set(result);
+        }
+        // MetadataList is a wrapper around the metadata ByteBuffer. MetadataItem is a wrapper with
+        // an index (pointer) on this ByteBuffer that represents a single emoji. Both are FlatBuffer
+        // classes that wraps a ByteBuffer and gives access to the information in it. In order not
+        // to create a wrapper class for each EmojiMetadata, we use mIndex as the index of the
+        // MetadataItem in the ByteBuffer. We need to reiniitalize the current thread local instance
+        // by executing the statement below. All the statement does is to set an int index in
+        // MetadataItem. the same instance is used by all EmojiMetadata classes in the same thread.
+        mMetadataRepo.getMetadataList().list(result, mIndex);
+        return result;
+    }
+
+    /**
+     * @return unique id for the emoji
+     */
+    public int getId() {
+        return getMetadataItem().id();
+    }
+
+    /**
+     * @return width of the emoji image
+     */
+    public short getWidth() {
+        return getMetadataItem().width();
+    }
+
+    /**
+     * @return height of the emoji image
+     */
+    public short getHeight() {
+        return getMetadataItem().height();
+    }
+
+    /**
+     * @return in which metadata version the emoji was added to metadata
+     */
+    public short getCompatAdded() {
+        return getMetadataItem().compatAdded();
+    }
+
+    /**
+     * @return first SDK that the support for this emoji was added
+     */
+    public short getSdkAdded() {
+        return getMetadataItem().sdkAdded();
+    }
+
+    /**
+     * @return whether the emoji is in Emoji Presentation by default (without emoji
+     * style selector 0xFE0F)
+     */
+    @HasGlyph
+    public int getHasGlyph() {
+        return mHasGlyph;
+    }
+
+    /**
+     * Set whether the system can render the emoji.
+     *
+     * @param hasGlyph {@code true} if system can render the emoji
+     */
+    public void setHasGlyph(boolean hasGlyph) {
+        mHasGlyph = hasGlyph ? HAS_GLYPH_EXISTS : HAS_GLYPH_ABSENT;
+    }
+
+    /**
+     * @return whether the emoji is in Emoji Presentation by default (without emoji
+     *         style selector 0xFE0F)
+     */
+    public boolean isDefaultEmoji() {
+        return getMetadataItem().emojiStyle();
+    }
+
+    /**
+     * @param index index of the codepoint
+     *
+     * @return the codepoint at index
+     */
+    public int getCodepointAt(int index) {
+        return getMetadataItem().codepoints(index);
+    }
+
+    /**
+     * @return the length of the codepoints for this emoji
+     */
+    public int getCodepointsLength() {
+        return getMetadataItem().codepointsLength();
+    }
+
+}
diff --git a/emoji/core/src/android/support/text/emoji/EmojiProcessor.java b/emoji/core/src/android/support/text/emoji/EmojiProcessor.java
new file mode 100644
index 0000000..9712b80
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiProcessor.java
@@ -0,0 +1,757 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.os.Build;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.widget.SpannableBuilder;
+import android.support.v4.graphics.PaintCompat;
+import android.support.v4.util.Preconditions;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.method.KeyListener;
+import android.text.method.MetaKeyKeyListener;
+import android.view.KeyEvent;
+import android.view.inputmethod.InputConnection;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Processes the CharSequence and adds the emojis.
+ *
+ * @hide
+ */
+@AnyThread
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiProcessor {
+
+    /**
+     * State transition commands.
+     */
+    @IntDef({ACTION_ADVANCE_BOTH, ACTION_ADVANCE_END, ACTION_FLUSH})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Action {
+    }
+
+    /**
+     * Advance the end pointer in CharSequence and reset the start to be the end.
+     */
+    private static final int ACTION_ADVANCE_BOTH = 1;
+
+    /**
+     * Advance end pointer in CharSequence.
+     */
+    private static final int ACTION_ADVANCE_END = 2;
+
+    /**
+     * Add a new emoji with the metadata in {@link ProcessorSm#getFlushMetadata()}. Advance end
+     * pointer in CharSequence and reset the start to be the end.
+     */
+    private static final int ACTION_FLUSH = 3;
+
+    /**
+     * Default text size for {@link #mTextPaint}.
+     */
+    private static final int PAINT_TEXT_SIZE = 10;
+
+    /**
+     * Used to create strings required by
+     * {@link PaintCompat#hasGlyph(android.graphics.Paint, String)}.
+     */
+    private static final ThreadLocal<StringBuilder> sStringBuilder = new ThreadLocal<>();
+
+    /**
+     * Factory used to create EmojiSpans.
+     */
+    private final EmojiCompat.SpanFactory mSpanFactory;
+
+    /**
+     * @see EmojiCompat.Config#setMaxEmojiPerText(int)
+     */
+    private final int mMaxEmojiPerText;
+
+    /**
+     * @see EmojiCompat.Config#setReplaceAll(boolean)
+     */
+    private final boolean mReplaceAll;
+
+    /**
+     * Emoji metadata repository.
+     */
+    private final MetadataRepo mMetadataRepo;
+
+    /**
+     * TextPaint used during {@link PaintCompat#hasGlyph(android.graphics.Paint, String)} check.
+     */
+    private final TextPaint mTextPaint;
+
+    EmojiProcessor(@NonNull final MetadataRepo metadataRepo,
+            @NonNull final EmojiCompat.SpanFactory spanFactory,
+            final boolean replaceAll, @IntRange(from = 0) final int maxEmojiPerText) {
+        mSpanFactory = spanFactory;
+        mMaxEmojiPerText = maxEmojiPerText;
+        mMetadataRepo = metadataRepo;
+        mReplaceAll = replaceAll;
+        mTextPaint = new TextPaint();
+        mTextPaint.setTextSize(PAINT_TEXT_SIZE);
+    }
+
+    EmojiMetadata getEmojiMetadata(@NonNull final CharSequence charSequence) {
+        final ProcessorSm sm = new ProcessorSm(mMetadataRepo.getRootNode());
+        final int end = charSequence.length();
+        int currentOffset = 0;
+
+        while (currentOffset < end) {
+            final int codePoint = Character.codePointAt(charSequence, currentOffset);
+            final int action = sm.check(codePoint);
+            if (action != ACTION_ADVANCE_END) {
+                return null;
+            }
+            currentOffset += Character.charCount(codePoint);
+        }
+
+        if (sm.isInFlushableState()) {
+            return sm.getCurrentMetadata();
+        }
+
+        return null;
+    }
+
+    /**
+     * Checks a given CharSequence for emojis, and adds EmojiSpans if any emojis are found.
+     * <p>
+     * <ul>
+     * <li>If no emojis are found, {@code charSequence} given as the input is returned without
+     * any changes. i.e. charSequence is a String, and no emojis are found, the same String is
+     * returned.</li>
+     * <li>If the given input is not a Spannable (such as String), and at least one emoji is found
+     * a new {@link android.text.Spannable} instance is returned. </li>
+     * <li>If the given input is a Spannable, the same instance is returned. </li>
+     * </ul>
+     *
+     * @param charSequence CharSequence to add the EmojiSpans, cannot be {@code null}
+     * @param start start index in the charSequence to look for emojis, should be greater than or
+     *              equal to {@code 0}, also less than {@code charSequence.length()}
+     * @param end end index in the charSequence to look for emojis, should be greater than or
+     *            equal to {@code start} parameter, also less than {@code charSequence.length()}
+     *
+     */
+    CharSequence process(@NonNull final CharSequence charSequence, @IntRange(from = 0) int start,
+            @IntRange(from = 0) int end) {
+        Preconditions.checkArgumentNonnegative(start, "start cannot be negative");
+        Preconditions.checkArgumentNonnegative(end, "end cannot be negative");
+        Preconditions.checkArgument(start <= end, "start should be <= than end");
+
+        // early return since there is nothing to do
+        if (charSequence == null) {
+            return charSequence;
+        }
+
+        Preconditions.checkArgument(start <= charSequence.length(),
+                "start should be < than charSequence length");
+        Preconditions.checkArgument(end <= charSequence.length(),
+                "end should be < than charSequence length");
+
+        // early return since there is nothing to do
+        if (charSequence.length() == 0 || start == end) {
+            return charSequence;
+        }
+
+        final boolean isSpannableBuilder = charSequence instanceof SpannableBuilder;
+        if (isSpannableBuilder) {
+            ((SpannableBuilder) charSequence).beginBatchEdit();
+        }
+
+        try {
+            Spannable spannable = null;
+            // if it is a spannable already, use the same instance to add/remove EmojiSpans.
+            // otherwise wait until the the first EmojiSpan found in order to change the result
+            // into a Spannable.
+            if (isSpannableBuilder || charSequence instanceof Spannable) {
+                spannable = (Spannable) charSequence;
+            }
+
+            if (spannable != null) {
+                final EmojiSpan[] spans = spannable.getSpans(start, end, EmojiSpan.class);
+                if (spans != null && spans.length > 0) {
+                    // remove existing spans, and realign the start, end according to spans
+                    // if start or end is in the middle of an emoji they should be aligned
+                    final int length = spans.length;
+                    for (int index = 0; index < length; index++) {
+                        final EmojiSpan span = spans[index];
+                        final int spanStart = spannable.getSpanStart(span);
+                        final int spanEnd = spannable.getSpanEnd(span);
+                        // Remove span only when its spanStart is NOT equal to current end.
+                        // During add operation an emoji at index 0 is added with 0-1 as start and
+                        // end indices. Therefore if there are emoji spans at [0-1] and [1-2]
+                        // and end is 1, the span between 0-1 should be deleted, not 1-2.
+                        if (spanStart != end) {
+                            spannable.removeSpan(span);
+                        }
+                        start = Math.min(spanStart, start);
+                        end = Math.max(spanEnd, end);
+                    }
+                }
+            }
+
+            if (start == end || start >= charSequence.length()) {
+                return charSequence;
+            }
+
+            // add new ones
+            int addedCount = 0;
+            final ProcessorSm sm = new ProcessorSm(mMetadataRepo.getRootNode());
+
+            int currentOffset = start;
+            int codePoint = Character.codePointAt(charSequence, currentOffset);
+
+            while (currentOffset < end && addedCount < mMaxEmojiPerText) {
+                final int action = sm.check(codePoint);
+
+                switch (action) {
+                    case ACTION_ADVANCE_BOTH:
+                        currentOffset += Character.charCount(codePoint);
+                        start = currentOffset;
+                        if (currentOffset < end) {
+                            codePoint = Character.codePointAt(charSequence, currentOffset);
+                        }
+                        break;
+                    case ACTION_ADVANCE_END:
+                        currentOffset += Character.charCount(codePoint);
+                        if (currentOffset < end) {
+                            codePoint = Character.codePointAt(charSequence, currentOffset);
+                        }
+                        break;
+                    case ACTION_FLUSH:
+                        if (mReplaceAll || !hasGlyph(charSequence, start, currentOffset,
+                                sm.getFlushMetadata())) {
+                            if (spannable == null) {
+                                spannable = new SpannableString(charSequence);
+                            }
+                            addEmoji(spannable, sm.getFlushMetadata(), start, currentOffset);
+                            addedCount++;
+                        }
+                        start = currentOffset;
+                        break;
+                }
+            }
+
+            // After the last codepoint is consumed the state machine might be in a state where it
+            // identified an emoji before. i.e. abc[women-emoji] when the last codepoint is consumed
+            // state machine is waiting to see if there is an emoji sequence (i.e. ZWJ).
+            // Need to check if it is in such a state.
+            if (sm.isInFlushableState() && addedCount < mMaxEmojiPerText) {
+                if (mReplaceAll || !hasGlyph(charSequence, start, currentOffset,
+                        sm.getCurrentMetadata())) {
+                    if (spannable == null) {
+                        spannable = new SpannableString(charSequence);
+                    }
+                    addEmoji(spannable, sm.getCurrentMetadata(), start, currentOffset);
+                    addedCount++;
+                }
+            }
+            return spannable == null ? charSequence : spannable;
+        } finally {
+            if (isSpannableBuilder) {
+                ((SpannableBuilder) charSequence).endBatchEdit();
+            }
+        }
+    }
+
+    /**
+     * Handles onKeyDown commands from a {@link KeyListener} and if {@code keyCode} is one of
+     * {@link KeyEvent#KEYCODE_DEL} or {@link KeyEvent#KEYCODE_FORWARD_DEL} it tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted with the characters it covers.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param editable Editable instance passed to {@link KeyListener#onKeyDown(android.view.View,
+     *                 Editable, int, KeyEvent)}
+     * @param keyCode keyCode passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *                int, KeyEvent)}
+     * @param event KeyEvent passed to {@link KeyListener#onKeyDown(android.view.View, Editable,
+     *              int, KeyEvent)}
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
+            final KeyEvent event) {
+        final boolean handled;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DEL:
+                handled = delete(editable, event, false /*forwardDelete*/);
+                break;
+            case KeyEvent.KEYCODE_FORWARD_DEL:
+                handled = delete(editable, event, true /*forwardDelete*/);
+                break;
+            default:
+                handled = false;
+                break;
+        }
+
+        if (handled) {
+            MetaKeyKeyListener.adjustMetaAfterKeypress(editable);
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean delete(final Editable content, final KeyEvent event,
+            final boolean forwardDelete) {
+        if (hasModifiers(event)) {
+            return false;
+        }
+
+        final int start = Selection.getSelectionStart(content);
+        final int end = Selection.getSelectionEnd(content);
+        if (hasInvalidSelection(start, end)) {
+            return false;
+        }
+
+        final EmojiSpan[] spans = content.getSpans(start, end, EmojiSpan.class);
+        if (spans != null && spans.length > 0) {
+            final int length = spans.length;
+            for (int index = 0; index < length; index++) {
+                final EmojiSpan span = spans[index];
+                final int spanStart = content.getSpanStart(span);
+                final int spanEnd = content.getSpanEnd(span);
+                if ((forwardDelete && spanStart == start)
+                        || (!forwardDelete && spanEnd == start)
+                        || (start > spanStart && start < spanEnd)) {
+                    content.delete(spanStart, spanEnd);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Handles deleteSurroundingText commands from {@link InputConnection} and tries to delete an
+     * {@link EmojiSpan} from an {@link Editable}. Returns {@code true} if an {@link EmojiSpan} is
+     * deleted.
+     * <p/>
+     * If there is a selection where selection start is not equal to selection end, does not
+     * delete.
+     *
+     * @param inputConnection InputConnection instance
+     * @param editable TextView.Editable instance
+     * @param beforeLength the number of characters before the cursor to be deleted
+     * @param afterLength the number of characters after the cursor to be deleted
+     * @param inCodePoints {@code true} if length parameters are in codepoints
+     *
+     * @return {@code true} if an {@link EmojiSpan} is deleted
+     */
+    static boolean handleDeleteSurroundingText(@NonNull final InputConnection inputConnection,
+            @NonNull final Editable editable, @IntRange(from = 0) final int beforeLength,
+            @IntRange(from = 0) final int afterLength, final boolean inCodePoints) {
+        if (editable == null || inputConnection == null) {
+            return false;
+        }
+
+        if (beforeLength < 0 || afterLength < 0) {
+            return false;
+        }
+
+        final int selectionStart = Selection.getSelectionStart(editable);
+        final int selectionEnd = Selection.getSelectionEnd(editable);
+
+        if (hasInvalidSelection(selectionStart, selectionEnd)) {
+            return false;
+        }
+
+        int start;
+        int end;
+        if (inCodePoints) {
+            // go backwards in terms of codepoints
+            start = CodepointIndexFinder.findIndexBackward(editable, selectionStart,
+                    Math.max(beforeLength, 0));
+            end = CodepointIndexFinder.findIndexForward(editable, selectionEnd,
+                    Math.max(afterLength, 0));
+
+            if (start == CodepointIndexFinder.INVALID_INDEX
+                    || end == CodepointIndexFinder.INVALID_INDEX) {
+                return false;
+            }
+        } else {
+            start = Math.max(selectionStart - beforeLength, 0);
+            end = Math.min(selectionEnd + afterLength, editable.length());
+        }
+
+        final EmojiSpan[] spans = editable.getSpans(start, end, EmojiSpan.class);
+        if (spans != null && spans.length > 0) {
+            final int length = spans.length;
+            for (int index = 0; index < length; index++) {
+                final EmojiSpan span = spans[index];
+                int spanStart = editable.getSpanStart(span);
+                int spanEnd = editable.getSpanEnd(span);
+                start = Math.min(spanStart, start);
+                end = Math.max(spanEnd, end);
+            }
+
+            start = Math.max(start, 0);
+            end = Math.min(end, editable.length());
+
+            inputConnection.beginBatchEdit();
+            editable.delete(start, end);
+            inputConnection.endBatchEdit();
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean hasInvalidSelection(final int start, final int end) {
+        return start == -1 || end == -1 || start != end;
+    }
+
+    private static boolean hasModifiers(KeyEvent event) {
+        return !KeyEvent.metaStateHasNoModifiers(event.getMetaState());
+    }
+
+    private void addEmoji(@NonNull final Spannable spannable, final EmojiMetadata metadata,
+            final int start, final int end) {
+        final EmojiSpan span = mSpanFactory.createSpan(metadata);
+        spannable.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+
+    /**
+     * Checks whether the current OS can render a given emoji. Used by the system to decide if an
+     * emoji span should be added. If the system cannot render it, an emoji span will be added.
+     * Used only for the case where replaceAll is set to {@code false}.
+     *
+     * @param charSequence the CharSequence that the emoji is in
+     * @param start start index of the emoji in the CharSequence
+     * @param end end index of the emoji in the CharSequence
+     * @param metadata EmojiMetadata instance for the emoji
+     *
+     * @return {@code true} if the OS can render emoji, {@code false} otherwise
+     */
+    private boolean hasGlyph(final CharSequence charSequence, int start, final int end,
+            final EmojiMetadata metadata) {
+        // if the emoji was added to OS at a later version we know that the system cannot render it.
+        // without this check pre M devices result in more false positives.
+        if (metadata.getSdkAdded() > Build.VERSION.SDK_INT) {
+            return false;
+        }
+
+        // if the existence is not calculated yet
+        if (metadata.getHasGlyph() == EmojiMetadata.HAS_GLYPH_UNKNOWN) {
+            final StringBuilder builder = getStringBuilder();
+            builder.setLength(0);
+
+            while (start < end) {
+                builder.append(charSequence.charAt(start));
+                start++;
+            }
+
+            final boolean hasGlyph = PaintCompat.hasGlyph(mTextPaint, builder.toString());
+            metadata.setHasGlyph(hasGlyph);
+        }
+
+        return metadata.getHasGlyph() == EmojiMetadata.HAS_GLYPH_EXISTS;
+    }
+
+    private static StringBuilder getStringBuilder() {
+        if (sStringBuilder.get() == null) {
+            sStringBuilder.set(new StringBuilder());
+        }
+        return sStringBuilder.get();
+    }
+
+    /**
+     * State machine for walking over the metadata trie.
+     */
+    static final class ProcessorSm {
+
+        private static final int STATE_DEFAULT = 1;
+        private static final int STATE_WALKING = 2;
+
+        private int mState = STATE_DEFAULT;
+
+        /**
+         * Root of the trie
+         */
+        private final MetadataRepo.Node mRootNode;
+
+        /**
+         * Pointer to the node after last codepoint.
+         */
+        private MetadataRepo.Node mCurrentNode;
+
+        /**
+         * The node where ACTION_FLUSH is called. Required since after flush action is
+         * returned mCurrentNode is reset to be the root.
+         */
+        private MetadataRepo.Node mFlushNode;
+
+        /**
+         * The code point that was checked.
+         */
+        private int mLastCodepoint;
+
+        /**
+         * Level for mCurrentNode. Root is 0.
+         */
+        private int mCurrentDepth;
+
+        ProcessorSm(MetadataRepo.Node rootNode) {
+            mRootNode = rootNode;
+            mCurrentNode = rootNode;
+        }
+
+        @Action
+        int check(final int codePoint) {
+            final int action;
+            MetadataRepo.Node node = mCurrentNode.get(codePoint);
+            switch (mState) {
+                case STATE_WALKING:
+                    if (node != null) {
+                        mCurrentNode = node;
+                        mCurrentDepth += 1;
+                        action = ACTION_ADVANCE_END;
+                    } else {
+                        if (isTextStyle(codePoint)) {
+                            action = reset();
+                        } else if (isEmojiStyle(codePoint)) {
+                            action = ACTION_ADVANCE_END;
+                        } else if (mCurrentNode.getData() != null) {
+                            if (mCurrentDepth == 1) {
+                                if (mCurrentNode.getData().isDefaultEmoji()
+                                        || isEmojiStyle(mLastCodepoint)) {
+                                    mFlushNode = mCurrentNode;
+                                    action = ACTION_FLUSH;
+                                    reset();
+                                } else {
+                                    action = reset();
+                                }
+                            } else {
+                                mFlushNode = mCurrentNode;
+                                action = ACTION_FLUSH;
+                                reset();
+                            }
+                        } else {
+                            action = reset();
+                        }
+                    }
+                    break;
+                case STATE_DEFAULT:
+                default:
+                    if (node == null) {
+                        action = reset();
+                    } else {
+                        mState = STATE_WALKING;
+                        mCurrentNode = node;
+                        mCurrentDepth = 1;
+                        action = ACTION_ADVANCE_END;
+                    }
+                    break;
+            }
+
+            mLastCodepoint = codePoint;
+            return action;
+        }
+
+        @Action
+        private int reset() {
+            mState = STATE_DEFAULT;
+            mCurrentNode = mRootNode;
+            mCurrentDepth = 0;
+            return ACTION_ADVANCE_BOTH;
+        }
+
+        /**
+         * @return the metadata node when ACTION_FLUSH is returned
+         */
+        EmojiMetadata getFlushMetadata() {
+            return mFlushNode.getData();
+        }
+
+        /**
+         * @return current pointer to the metadata node in the trie
+         */
+        EmojiMetadata getCurrentMetadata() {
+            return mCurrentNode.getData();
+        }
+
+        /**
+         * Need for the case where input is consumed, but action_flush was not called. For example
+         * when the char sequence has single codepoint character which is a default emoji. State
+         * machine will wait for the next.
+         *
+         * @return whether the current state requires an emoji to be added
+         */
+        boolean isInFlushableState() {
+            return mState == STATE_WALKING && mCurrentNode.getData() != null
+                    && (mCurrentNode.getData().isDefaultEmoji()
+                    || isEmojiStyle(mLastCodepoint)
+                    || mCurrentDepth > 1);
+        }
+
+        /**
+         * @param codePoint CodePoint to check
+         *
+         * @return {@code true} if the codepoint is a emoji style standardized variation selector
+         */
+        private static boolean isEmojiStyle(int codePoint) {
+            return codePoint == 0xFE0F;
+        }
+
+        /**
+         * @param codePoint CodePoint to check
+         *
+         * @return {@code true} if the codepoint is a text style standardized variation selector
+         */
+        private static boolean isTextStyle(int codePoint) {
+            return codePoint == 0xFE0E;
+        }
+    }
+
+    /**
+     * Copy of BaseInputConnection findIndexBackward and findIndexForward functions.
+     */
+    private static final class CodepointIndexFinder {
+        private static final int INVALID_INDEX = -1;
+
+        /**
+         * Find start index of the character in {@code cs} that is {@code numCodePoints} behind
+         * starting from {@code from}.
+         *
+         * @param cs CharSequence to work on
+         * @param from the index to start going backwards
+         * @param numCodePoints the number of codepoints
+         *
+         * @return start index of the character
+         */
+        private static int findIndexBackward(final CharSequence cs, final int from,
+                final int numCodePoints) {
+            int currentIndex = from;
+            boolean waitingHighSurrogate = false;
+            final int length = cs.length();
+            if (currentIndex < 0 || length < currentIndex) {
+                return INVALID_INDEX;  // The starting point is out of range.
+            }
+            if (numCodePoints < 0) {
+                return INVALID_INDEX;  // Basically this should not happen.
+            }
+            int remainingCodePoints = numCodePoints;
+            while (true) {
+                if (remainingCodePoints == 0) {
+                    return currentIndex;  // Reached to the requested length in code points.
+                }
+
+                --currentIndex;
+                if (currentIndex < 0) {
+                    if (waitingHighSurrogate) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    return 0;  // Reached to the beginning of the text w/o any invalid surrogate
+                    // pair.
+                }
+                final char c = cs.charAt(currentIndex);
+                if (waitingHighSurrogate) {
+                    if (!Character.isHighSurrogate(c)) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    waitingHighSurrogate = false;
+                    --remainingCodePoints;
+                    continue;
+                }
+                if (!Character.isSurrogate(c)) {
+                    --remainingCodePoints;
+                    continue;
+                }
+                if (Character.isHighSurrogate(c)) {
+                    return INVALID_INDEX;  // A invalid surrogate pair is found.
+                }
+                waitingHighSurrogate = true;
+            }
+        }
+
+        /**
+         * Find start index of the character in {@code cs} that is {@code numCodePoints} ahead
+         * starting from {@code from}.
+         *
+         * @param cs CharSequence to work on
+         * @param from the index to start going forward
+         * @param numCodePoints the number of codepoints
+         *
+         * @return start index of the character
+         */
+        private static int findIndexForward(final CharSequence cs, final int from,
+                final int numCodePoints) {
+            int currentIndex = from;
+            boolean waitingLowSurrogate = false;
+            final int length = cs.length();
+            if (currentIndex < 0 || length < currentIndex) {
+                return INVALID_INDEX;  // The starting point is out of range.
+            }
+            if (numCodePoints < 0) {
+                return INVALID_INDEX;  // Basically this should not happen.
+            }
+            int remainingCodePoints = numCodePoints;
+
+            while (true) {
+                if (remainingCodePoints == 0) {
+                    return currentIndex;  // Reached to the requested length in code points.
+                }
+
+                if (currentIndex >= length) {
+                    if (waitingLowSurrogate) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    return length;  // Reached to the end of the text w/o any invalid surrogate
+                    // pair.
+                }
+                final char c = cs.charAt(currentIndex);
+                if (waitingLowSurrogate) {
+                    if (!Character.isLowSurrogate(c)) {
+                        return INVALID_INDEX;  // An invalid surrogate pair is found.
+                    }
+                    --remainingCodePoints;
+                    waitingLowSurrogate = false;
+                    ++currentIndex;
+                    continue;
+                }
+                if (!Character.isSurrogate(c)) {
+                    --remainingCodePoints;
+                    ++currentIndex;
+                    continue;
+                }
+                if (Character.isLowSurrogate(c)) {
+                    return INVALID_INDEX;  // A invalid surrogate pair is found.
+                }
+                waitingLowSurrogate = true;
+                ++currentIndex;
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/EmojiSpan.java b/emoji/core/src/android/support/text/emoji/EmojiSpan.java
new file mode 100644
index 0000000..2510e2c
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/EmojiSpan.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Paint;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.Preconditions;
+import android.text.style.ReplacementSpan;
+
+/**
+ * Base span class for the emoji replacement. When an emoji is found and needs to be replaced in a
+ * CharSequence, an instance of this class is added to the CharSequence.
+ */
+public abstract class EmojiSpan extends ReplacementSpan {
+
+    /**
+     * Temporary object to calculate the size of the span.
+     */
+    private final Paint.FontMetricsInt mTmpFontMetrics = new Paint.FontMetricsInt();
+
+    /**
+     * Information about emoji. This is not parcelled since we do not want multiple objects
+     * representing same emoji to be in memory. When unparcelled, EmojiSpan tries to set it back
+     * using the singleton EmojiCompat instance.
+     */
+    private final EmojiMetadata mMetadata;
+
+    /**
+     * Cached width of the span. Width is calculated according to the font metrics.
+     */
+    private short mWidth = -1;
+
+    /**
+     * Cached height of the span. Height is calculated according to the font metrics.
+     */
+    private short mHeight = -1;
+
+    /**
+     * Cached ratio of current font height to emoji image height.
+     */
+    private float mRatio = 1.0f;
+
+    /**
+     * Default constructor.
+     *
+     * @param metadata information about the emoji, cannot be {@code null}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    EmojiSpan(@NonNull final EmojiMetadata metadata) {
+        Preconditions.checkNotNull(metadata, "metadata cannot be null");
+        mMetadata = metadata;
+    }
+
+    @Override
+    public int getSize(@NonNull final Paint paint, final CharSequence text, final int start,
+            final int end, final Paint.FontMetricsInt fm) {
+        paint.getFontMetricsInt(mTmpFontMetrics);
+        final int fontHeight = Math.abs(mTmpFontMetrics.descent - mTmpFontMetrics.ascent);
+
+        mRatio = fontHeight * 1.0f / mMetadata.getHeight();
+        mHeight = (short) (mMetadata.getHeight() * mRatio);
+        mWidth = (short) (mMetadata.getWidth() * mRatio);
+
+        if (fm != null) {
+            fm.ascent = mTmpFontMetrics.ascent;
+            fm.descent = mTmpFontMetrics.descent;
+            fm.top = mTmpFontMetrics.top;
+            fm.bottom = mTmpFontMetrics.bottom;
+        }
+
+        return mWidth;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final EmojiMetadata getMetadata() {
+        return mMetadata;
+    }
+
+    /**
+     * @return width of the span
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * @return height of the span
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    final float getRatio() {
+        return mRatio;
+    }
+
+    /**
+     * @return unique id for the emoji that this EmojiSpan is used for
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    public final int getId() {
+        return getMetadata().getId();
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/MetadataListReader.java b/emoji/core/src/android/support/text/emoji/MetadataListReader.java
new file mode 100644
index 0000000..364247b
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/MetadataListReader.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.res.AssetManager;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntRange;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.flatbuffer.MetadataList;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Reads the emoji metadata from a given InputStream or ByteBuffer.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@AnyThread
+class MetadataListReader {
+
+    /**
+     * Meta tag for emoji metadata. This string is used by the font update script to insert the
+     * emoji meta into the font. This meta table contains the list of all emojis which are stored in
+     * binary format using FlatBuffers. This flat list is later converted by the system into a trie.
+     * {@code int} representation for "emji"
+     *
+     * @see MetadataRepo
+     */
+    private static final int EMJI_TAG = 0x656D6A69;
+
+    /**
+     * The name of the meta table in the font. int representation for "meta"
+     */
+    private static final int META_TABLE_NAME = 0x6D657461;
+
+    /**
+     * Construct MetadataList from an input stream. Does not close the given InputStream, therefore
+     * it is caller's responsibility to properly close the stream.
+     *
+     * @param inputStream InputStream to read emoji metadata from
+     */
+    static MetadataList read(InputStream inputStream) throws IOException {
+        final OpenTypeReader openTypeReader = new InputStreamOpenTypeReader(inputStream);
+        final OffsetInfo offsetInfo = findOffsetInfo(openTypeReader);
+        // skip to where metadata is
+        openTypeReader.skip((int) (offsetInfo.getStartOffset() - openTypeReader.getPosition()));
+        // allocate a ByteBuffer and read into it since FlatBuffers can read only from a ByteBuffer
+        final ByteBuffer buffer = ByteBuffer.allocate((int) offsetInfo.getLength());
+        final int numRead = inputStream.read(buffer.array());
+        if (numRead != offsetInfo.getLength()) {
+            throw new IOException("Needed " + offsetInfo.getLength() + " bytes, got " + numRead);
+        }
+
+        return MetadataList.getRootAsMetadataList(buffer);
+    }
+
+    /**
+     * Construct MetadataList from a byte buffer.
+     *
+     * @param byteBuffer ByteBuffer to read emoji metadata from
+     */
+    static MetadataList read(final ByteBuffer byteBuffer) throws IOException {
+        final ByteBuffer newBuffer = byteBuffer.duplicate();
+        final OpenTypeReader reader = new ByteBufferReader(newBuffer);
+        final OffsetInfo offsetInfo = findOffsetInfo(reader);
+        // skip to where metadata is
+        newBuffer.position((int) offsetInfo.getStartOffset());
+        return MetadataList.getRootAsMetadataList(newBuffer);
+    }
+
+    /**
+     * Construct MetadataList from an asset.
+     *
+     * @param assetManager AssetManager instance
+     * @param assetPath asset manager path of the file that the Typeface and metadata will be
+     *                  created from
+     */
+    static MetadataList read(AssetManager assetManager, String assetPath)
+            throws IOException {
+        InputStream inputStream = null;
+        try {
+            inputStream = assetManager.open(assetPath);
+            return read(inputStream);
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Finds the start offset and length of the emoji metadata in the font.
+     *
+     * @return OffsetInfo which contains start offset and length of the emoji metadata in the font
+     *
+     * @throws IOException
+     */
+    private static OffsetInfo findOffsetInfo(OpenTypeReader reader) throws IOException {
+        // skip sfnt version
+        reader.skip(OpenTypeReader.UINT32_BYTE_COUNT);
+        // start of Table Count
+        final int tableCount = reader.readUnsignedShort();
+        if (tableCount > 100) {
+            //something is wrong quit
+            throw new IOException("Cannot read metadata.");
+        }
+        //skip to begining of tables data
+        reader.skip(OpenTypeReader.UINT16_BYTE_COUNT * 3);
+
+        long metaOffset = -1;
+        for (int i = 0; i < tableCount; i++) {
+            final int tag = reader.readTag();
+            // skip checksum
+            reader.skip(OpenTypeReader.UINT32_BYTE_COUNT);
+            final long offset = reader.readUnsignedInt();
+            // skip mLength
+            reader.skip(OpenTypeReader.UINT32_BYTE_COUNT);
+            if (META_TABLE_NAME == tag) {
+                metaOffset = offset;
+                break;
+            }
+        }
+
+        if (metaOffset != -1) {
+            // skip to the begining of meta tables.
+            reader.skip((int) (metaOffset - reader.getPosition()));
+            // skip minorVersion, majorVersion, flags, reserved,
+            reader.skip(
+                    OpenTypeReader.UINT16_BYTE_COUNT * 2 + OpenTypeReader.UINT32_BYTE_COUNT * 2);
+            final long mapsCount = reader.readUnsignedInt();
+            for (int i = 0; i < mapsCount; i++) {
+                final int tag = reader.readTag();
+                final long dataOffset = reader.readUnsignedInt();
+                final long dataLength = reader.readUnsignedInt();
+                if (EMJI_TAG == tag) {
+                    return new OffsetInfo(dataOffset + metaOffset, dataLength);
+                }
+            }
+        }
+
+        throw new IOException("Cannot read metadata.");
+    }
+
+    /**
+     * Start offset and length of the emoji metadata in the font.
+     */
+    private static class OffsetInfo {
+        private final long mStartOffset;
+        private final long mLength;
+
+        OffsetInfo(long startOffset, long length) {
+            mStartOffset = startOffset;
+            mLength = length;
+        }
+
+        long getStartOffset() {
+            return mStartOffset;
+        }
+
+        long getLength() {
+            return mLength;
+        }
+    }
+
+    static final int toUnsignedShort(final short value) {
+        return value & 0xFFFF;
+    }
+
+    static final long toUnsignedInt(final int value) {
+        return value & 0xFFFFFFFFL;
+    }
+
+    private interface OpenTypeReader {
+        int UINT16_BYTE_COUNT = 2;
+        int UINT32_BYTE_COUNT = 4;
+
+        /**
+         * Reads an {@code OpenType uint16}.
+         *
+         * @throws IOException
+         */
+        int readUnsignedShort() throws IOException;
+
+        /**
+         * Reads an {@code OpenType uint32}.
+         *
+         * @throws IOException
+         */
+        long readUnsignedInt() throws IOException;
+
+        /**
+         * Reads an {@code OpenType Tag}.
+         *
+         * @throws IOException
+         */
+        int readTag() throws IOException;
+
+        /**
+         * Skip the given amount of numOfBytes
+         *
+         * @throws IOException
+         */
+        void skip(int numOfBytes) throws IOException;
+
+        /**
+         * @return the position of the reader
+         */
+        long getPosition();
+    }
+
+    /**
+     * Reads {@code OpenType} data from an {@link InputStream}.
+     */
+    private static class InputStreamOpenTypeReader implements OpenTypeReader {
+
+        private final byte[] mByteArray;
+        private final ByteBuffer mByteBuffer;
+        private final InputStream mInputStream;
+        private long mPosition = 0;
+
+        /**
+         * Constructs the reader with the given InputStream. Does not close the InputStream, it is
+         * caller's responsibility to close it.
+         *
+         * @param inputStream InputStream to read from
+         */
+        InputStreamOpenTypeReader(final InputStream inputStream) {
+            mInputStream = inputStream;
+            mByteArray = new byte[UINT32_BYTE_COUNT];
+            mByteBuffer = ByteBuffer.wrap(mByteArray);
+            mByteBuffer.order(ByteOrder.BIG_ENDIAN);
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            mByteBuffer.position(0);
+            read(UINT16_BYTE_COUNT);
+            return toUnsignedShort(mByteBuffer.getShort());
+        }
+
+        @Override
+        public long readUnsignedInt() throws IOException {
+            mByteBuffer.position(0);
+            read(UINT32_BYTE_COUNT);
+            return toUnsignedInt(mByteBuffer.getInt());
+        }
+
+        @Override
+        public int readTag() throws IOException {
+            mByteBuffer.position(0);
+            read(UINT32_BYTE_COUNT);
+            return mByteBuffer.getInt();
+        }
+
+        @Override
+        public void skip(int numOfBytes) throws IOException {
+            while (numOfBytes > 0) {
+                long skipped = mInputStream.skip(numOfBytes);
+                if (skipped < 1) {
+                    throw new IOException("Skip didn't move at least 1 byte forward");
+                }
+                numOfBytes -= skipped;
+                mPosition += skipped;
+            }
+        }
+
+        @Override
+        public long getPosition() {
+            return mPosition;
+        }
+
+        private void read(@IntRange(from = 0, to = UINT32_BYTE_COUNT) final int numOfBytes)
+                throws IOException {
+            if (mInputStream.read(mByteArray, 0, numOfBytes) != numOfBytes) {
+                throw new IOException("read failed");
+            }
+            mPosition += numOfBytes;
+        }
+    }
+
+    /**
+     * Reads OpenType data from a ByteBuffer.
+     */
+    private static class ByteBufferReader implements OpenTypeReader {
+
+        private final ByteBuffer mByteBuffer;
+
+        /**
+         * Constructs the reader with the given ByteBuffer.
+         *
+         * @param byteBuffer ByteBuffer to read from
+         */
+        ByteBufferReader(final ByteBuffer byteBuffer) {
+            mByteBuffer = byteBuffer;
+            mByteBuffer.order(ByteOrder.BIG_ENDIAN);
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            return toUnsignedShort(mByteBuffer.getShort());
+        }
+
+        @Override
+        public long readUnsignedInt() throws IOException {
+            return toUnsignedInt(mByteBuffer.getInt());
+        }
+
+        @Override
+        public int readTag() throws IOException {
+            return mByteBuffer.getInt();
+        }
+
+        @Override
+        public void skip(final int numOfBytes) throws IOException {
+            mByteBuffer.position(mByteBuffer.position() + numOfBytes);
+        }
+
+        @Override
+        public long getPosition() {
+            return mByteBuffer.position();
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/MetadataRepo.java b/emoji/core/src/android/support/text/emoji/MetadataRepo.java
new file mode 100644
index 0000000..f192f09
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/MetadataRepo.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.res.AssetManager;
+import android.graphics.Typeface;
+import android.support.annotation.AnyThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.text.emoji.flatbuffer.MetadataList;
+import android.support.v4.util.Preconditions;
+import android.util.SparseArray;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * Class to hold the emoji metadata required to process and draw emojis.
+ */
+@AnyThread
+public final class MetadataRepo {
+    /**
+     * The default children size of the root node.
+     */
+    private static final int DEFAULT_ROOT_SIZE = 1024;
+
+    /**
+     * MetadataList that contains the emoji metadata.
+     */
+    private final MetadataList mMetadataList;
+
+    /**
+     * char presentation of all EmojiMetadata's in a single array.
+     */
+    private final char[] mEmojiCharArray;
+
+    /**
+     * Empty root node of the trie.
+     */
+    private final Node mRootNode;
+
+    /**
+     * Typeface to be used to render emojis.
+     */
+    private final Typeface mTypeface;
+
+    /**
+     * Constructor used for tests.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    MetadataRepo() {
+        mTypeface = null;
+        mMetadataList = null;
+        mRootNode = new Node(DEFAULT_ROOT_SIZE);
+        mEmojiCharArray = new char[0];
+    }
+
+    /**
+     * Private constructor that is called by one of {@code create} methods.
+     *
+     * @param typeface Typeface to be used to render emojis
+     * @param metadataList MetadataList that contains the emoji metadata
+     */
+    private MetadataRepo(@NonNull final Typeface typeface,
+            @NonNull final MetadataList metadataList) {
+        mTypeface = typeface;
+        mMetadataList = metadataList;
+        mRootNode = new Node(DEFAULT_ROOT_SIZE);
+        mEmojiCharArray = new char[mMetadataList.listLength() * 2];
+        constructIndex(mMetadataList);
+    }
+
+    /**
+     * Construct MetadataRepo from an input stream. The library does not close the given
+     * InputStream, therefore it is caller's responsibility to properly close the stream.
+     *
+     * @param typeface Typeface to be used to render emojis
+     * @param inputStream InputStream to read emoji metadata from
+     */
+    public static MetadataRepo create(@NonNull final Typeface typeface,
+            @NonNull final InputStream inputStream) throws IOException {
+        return new MetadataRepo(typeface, MetadataListReader.read(inputStream));
+    }
+
+    /**
+     * Construct MetadataRepo from a byte buffer. The position of the ByteBuffer will change, it is
+     * caller's responsibility to reposition the buffer if required.
+     *
+     * @param typeface Typeface to be used to render emojis
+     * @param byteBuffer ByteBuffer to read emoji metadata from
+     */
+    public static MetadataRepo create(@NonNull final Typeface typeface,
+            @NonNull final ByteBuffer byteBuffer) throws IOException {
+        return new MetadataRepo(typeface, MetadataListReader.read(byteBuffer));
+    }
+
+    /**
+     * Construct MetadataRepo from an asset.
+     *
+     * @param assetManager AssetManager instance
+     * @param assetPath asset manager path of the file that the Typeface and metadata will be
+     *                  created from
+     */
+    public static MetadataRepo create(@NonNull final AssetManager assetManager,
+            final String assetPath) throws IOException {
+        final Typeface typeface = Typeface.createFromAsset(assetManager, assetPath);
+        return new MetadataRepo(typeface, MetadataListReader.read(assetManager, assetPath));
+    }
+
+    /**
+     * Read emoji metadata list and construct the trie.
+     */
+    private void constructIndex(final MetadataList metadataList) {
+        int length = metadataList.listLength();
+        for (int i = 0; i < length; i++) {
+            final EmojiMetadata metadata = new EmojiMetadata(this, i);
+            Character.toChars(metadata.getId(), mEmojiCharArray, i * 2);
+            put(metadata);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    Typeface getTypeface() {
+        return mTypeface;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    int getMetadataVersion() {
+        return mMetadataList.version();
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    Node getRootNode() {
+        return mRootNode;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public char[] getEmojiCharArray() {
+        return mEmojiCharArray;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public MetadataList getMetadataList() {
+        return mMetadataList;
+    }
+
+    /**
+     * Add an EmojiMetadata to the index.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @VisibleForTesting
+    void put(@NonNull final EmojiMetadata data) {
+        Preconditions.checkNotNull(data, "emoji metadata cannot be null");
+        Preconditions.checkArgument(data.getCodepointsLength() > 0,
+                "invalid metadata codepoint length");
+
+        mRootNode.put(data, 0, data.getCodepointsLength() - 1);
+    }
+
+    /**
+     * Trie node that holds mapping from emoji codepoint(s) to EmojiMetadata. A single codepoint
+     * emoji is represented by a child of the root node.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    static class Node {
+        private SparseArray<Node> mChildren;
+        private EmojiMetadata mData;
+
+        private Node() {
+        }
+
+        private Node(final int defaultChildrenSize) {
+            mChildren = new SparseArray<>(defaultChildrenSize);
+        }
+
+        Node get(final int key) {
+            return mChildren == null ? null : mChildren.get(key);
+        }
+
+        final EmojiMetadata getData() {
+            return mData;
+        }
+
+        private void put(@NonNull final EmojiMetadata data, final int start, final int end) {
+            Node node = get(data.getCodepointAt(start));
+            if (node == null) {
+                if (mChildren == null) {
+                    mChildren = new SparseArray<>(1);
+                }
+                node = new Node();
+                mChildren.put(data.getCodepointAt(start), node);
+            }
+
+            if (end > start) {
+                node.put(data, start + 1, end);
+            } else {
+                node.mData = data;
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java b/emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java
new file mode 100644
index 0000000..acc4784
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+/**
+ * EmojiSpan subclass used to render emojis using Typeface.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public final class TypefaceEmojiSpan extends EmojiSpan {
+
+    /**
+     * Default constructor.
+     *
+     * @param metadata metadata representing the emoji that this span will draw
+     */
+    public TypefaceEmojiSpan(final EmojiMetadata metadata) {
+        super(metadata);
+    }
+
+    @Override
+    public void draw(@NonNull final Canvas canvas, final CharSequence text, final int start,
+            final int end, final float x, final int top, final int y, final int bottom,
+            @NonNull final Paint paint) {
+        final Typeface typeface = EmojiCompat.get().getTypeface();
+        final Typeface oldTypeface = paint.getTypeface();
+        paint.setTypeface(typeface);
+        getMetadata().draw(canvas, x, y, paint);
+        paint.setTypeface(oldTypeface);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataItem.java b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataItem.java
new file mode 100644
index 0000000..f0466ea
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataItem.java
@@ -0,0 +1,166 @@
+// CHECKSTYLE:OFF Generated code
+/*
+ * Copyright (C) 2017 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.text.emoji.flatbuffer;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+
+import com.google.flatbuffers.emojicompat.FlatBufferBuilder;
+import com.google.flatbuffers.emojicompat.Table;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Automatically generated by the FlatBuffers compiler, do not modify.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@SuppressWarnings("unused")
+public final class MetadataItem extends Table {
+    public static MetadataItem getRootAsMetadataItem(ByteBuffer _bb) {
+        return getRootAsMetadataItem(_bb, new MetadataItem());
+    }
+
+    public static MetadataItem getRootAsMetadataItem(ByteBuffer _bb, MetadataItem obj) {
+        _bb.order(ByteOrder.LITTLE_ENDIAN);
+        return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb));
+    }
+
+    public void __init(int _i, ByteBuffer _bb) {
+        bb_pos = _i;
+        bb = _bb;
+    }
+
+    public MetadataItem __assign(int _i, ByteBuffer _bb) {
+        __init(_i, _bb);
+        return this;
+    }
+
+    public int id() {
+        int o = __offset(4);
+        return o != 0 ? bb.getInt(o + bb_pos) : 0;
+    }
+
+    public boolean emojiStyle() {
+        int o = __offset(6);
+        return o != 0 ? 0 != bb.get(o + bb_pos) : false;
+    }
+
+    public short sdkAdded() {
+        int o = __offset(8);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public short compatAdded() {
+        int o = __offset(10);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public short width() {
+        int o = __offset(12);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public short height() {
+        int o = __offset(14);
+        return o != 0 ? bb.getShort(o + bb_pos) : 0;
+    }
+
+    public int codepoints(int j) {
+        int o = __offset(16);
+        return o != 0 ? bb.getInt(__vector(o) + j * 4) : 0;
+    }
+
+    public int codepointsLength() {
+        int o = __offset(16);
+        return o != 0 ? __vector_len(o) : 0;
+    }
+
+    public ByteBuffer codepointsAsByteBuffer() {
+        return __vector_as_bytebuffer(16, 4);
+    }
+
+    public static int createMetadataItem(FlatBufferBuilder builder,
+            int id,
+            boolean emojiStyle,
+            short sdkAdded,
+            short compatAdded,
+            short width,
+            short height,
+            int codepointsOffset) {
+        builder.startObject(7);
+        MetadataItem.addCodepoints(builder, codepointsOffset);
+        MetadataItem.addId(builder, id);
+        MetadataItem.addHeight(builder, height);
+        MetadataItem.addWidth(builder, width);
+        MetadataItem.addCompatAdded(builder, compatAdded);
+        MetadataItem.addSdkAdded(builder, sdkAdded);
+        MetadataItem.addEmojiStyle(builder, emojiStyle);
+        return MetadataItem.endMetadataItem(builder);
+    }
+
+    public static void startMetadataItem(FlatBufferBuilder builder) {
+        builder.startObject(7);
+    }
+
+    public static void addId(FlatBufferBuilder builder, int id) {
+        builder.addInt(0, id, 0);
+    }
+
+    public static void addEmojiStyle(FlatBufferBuilder builder, boolean emojiStyle) {
+        builder.addBoolean(1, emojiStyle, false);
+    }
+
+    public static void addSdkAdded(FlatBufferBuilder builder, short sdkAdded) {
+        builder.addShort(2, sdkAdded, 0);
+    }
+
+    public static void addCompatAdded(FlatBufferBuilder builder, short compatAdded) {
+        builder.addShort(3, compatAdded, 0);
+    }
+
+    public static void addWidth(FlatBufferBuilder builder, short width) {
+        builder.addShort(4, width, 0);
+    }
+
+    public static void addHeight(FlatBufferBuilder builder, short height) {
+        builder.addShort(5, height, 0);
+    }
+
+    public static void addCodepoints(FlatBufferBuilder builder, int codepointsOffset) {
+        builder.addOffset(6, codepointsOffset, 0);
+    }
+
+    public static int createCodepointsVector(FlatBufferBuilder builder, int[] data) {
+        builder.startVector(4, data.length, 4);
+        for (int i = data.length - 1; i >= 0; i--) builder.addInt(data[i]);
+        return builder.endVector();
+    }
+
+    public static void startCodepointsVector(FlatBufferBuilder builder, int numElems) {
+        builder.startVector(4, numElems, 4);
+    }
+
+    public static int endMetadataItem(FlatBufferBuilder builder) {
+        int o = builder.endObject();
+        return o;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataList.java b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataList.java
new file mode 100644
index 0000000..4de07d7
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/flatbuffer/MetadataList.java
@@ -0,0 +1,115 @@
+// CHECKSTYLE:OFF Generated code
+/*
+ * Copyright (C) 2017 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.text.emoji.flatbuffer;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+
+import com.google.flatbuffers.emojicompat.FlatBufferBuilder;
+import com.google.flatbuffers.emojicompat.Table;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Automatically generated by the FlatBuffers compiler, do not modify.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@SuppressWarnings("unused")
+public final class MetadataList extends Table {
+    public static MetadataList getRootAsMetadataList(ByteBuffer _bb) {
+        return getRootAsMetadataList(_bb, new MetadataList());
+    }
+
+    public static MetadataList getRootAsMetadataList(ByteBuffer _bb, MetadataList obj) {
+        _bb.order(ByteOrder.LITTLE_ENDIAN);
+        return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb));
+    }
+
+    public void __init(int _i, ByteBuffer _bb) {
+        bb_pos = _i;
+        bb = _bb;
+    }
+
+    public MetadataList __assign(int _i, ByteBuffer _bb) {
+        __init(_i, _bb);
+        return this;
+    }
+
+    public int version() {
+        int o = __offset(4);
+        return o != 0 ? bb.getInt(o + bb_pos) : 0;
+    }
+
+    public MetadataItem list(int j) {
+        return list(new MetadataItem(), j);
+    }
+
+    public MetadataItem list(MetadataItem obj, int j) {
+        int o = __offset(6);
+        return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null;
+    }
+
+    public int listLength() {
+        int o = __offset(6);
+        return o != 0 ? __vector_len(o) : 0;
+    }
+
+    public static int createMetadataList(FlatBufferBuilder builder,
+            int version,
+            int listOffset) {
+        builder.startObject(2);
+        MetadataList.addList(builder, listOffset);
+        MetadataList.addVersion(builder, version);
+        return MetadataList.endMetadataList(builder);
+    }
+
+    public static void startMetadataList(FlatBufferBuilder builder) {
+        builder.startObject(2);
+    }
+
+    public static void addVersion(FlatBufferBuilder builder, int version) {
+        builder.addInt(0, version, 0);
+    }
+
+    public static void addList(FlatBufferBuilder builder, int listOffset) {
+        builder.addOffset(1, listOffset, 0);
+    }
+
+    public static int createListVector(FlatBufferBuilder builder, int[] data) {
+        builder.startVector(4, data.length, 4);
+        for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]);
+        return builder.endVector();
+    }
+
+    public static void startListVector(FlatBufferBuilder builder, int numElems) {
+        builder.startVector(4, numElems, 4);
+    }
+
+    public static int endMetadataList(FlatBufferBuilder builder) {
+        int o = builder.endObject();
+        return o;
+    }
+
+    public static void finishMetadataListBuffer(FlatBufferBuilder builder, int offset) {
+        builder.finish(offset);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiButton.java b/emoji/core/src/android/support/text/emoji/widget/EmojiButton.java
new file mode 100644
index 0000000..bc55e66
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiButton.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+/**
+ * Button widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiButton extends Button {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiButton(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
new file mode 100644
index 0000000..3e9153b
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+
+/**
+ * EditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}.
+ */
+public class EmojiEditText extends EditText {
+    private EmojiEditTextHelper mEmojiEditTextHelper;
+    private boolean mInitialized;
+
+    public EmojiEditText(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiEditText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
+        }
+    }
+
+    @Override
+    public void setKeyListener(android.text.method.KeyListener input) {
+        super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+        return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
+    }
+
+    private EmojiEditTextHelper getEmojiEditTextHelper() {
+        if (mEmojiEditTextHelper == null) {
+            mEmojiEditTextHelper = new EmojiEditTextHelper(this);
+        }
+        return mEmojiEditTextHelper;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
new file mode 100644
index 0000000..c3d5e84
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.Preconditions;
+import android.text.method.KeyListener;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+import android.widget.TextView;
+
+/**
+ * Utility class to enhance an EditText with emoji capability.
+ */
+public final class EmojiEditTextHelper {
+    private final EditText mEditText;
+    private final EmojiTextWatcher mTextWatcher;
+
+    /**
+     * Default constructor.
+     *
+     * @param editText EditText instance
+     */
+    public EmojiEditTextHelper(@NonNull final EditText editText) {
+        Preconditions.checkNotNull(editText, "editText cannot be null");
+        mEditText = editText;
+        mTextWatcher = new EmojiTextWatcher(mEditText);
+        editText.addTextChangedListener(mTextWatcher);
+        editText.setEditableFactory(EmojiEditableFactory.getInstance());
+    }
+
+    /**
+     * Attaches EmojiCompat KeyListener to the widget. Should be called from {@link
+     * TextView#setKeyListener(KeyListener)}. Existing keyListener is wrapped into EmojiCompat
+     * KeyListener.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public void setKeyListener(android.text.method.KeyListener input) {
+     *     super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+     * }</code></pre>
+     *
+     * @param keyListener KeyListener passed into {@link TextView#setKeyListener(KeyListener)}
+     *
+     * @return a new KeyListener instance that wraps {@code keyListener}.
+     */
+
+    public KeyListener getKeyListener(@NonNull final KeyListener keyListener) {
+        Preconditions.checkNotNull(keyListener, "keyListener cannot be null");
+        return new EmojiKeyListener(keyListener);
+    }
+
+    /**
+     * Updates the InputConnection with emoji support. Should be called from {@link
+     * TextView#onCreateInputConnection(EditorInfo)}.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+     *     InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+     *     return getEmojiHelper().onCreateInputConnection(inputConnection, outAttrs);
+     * }</code></pre>
+     *
+     * @param inputConnection InputConnection instance created by TextView
+     * @param outAttrs        EditorInfo passed into
+     *                        {@link TextView#onCreateInputConnection(EditorInfo)}
+     *
+     * @return a new InputConnection instance that wraps {@code inputConnection}
+     */
+    public InputConnection onCreateInputConnection(@NonNull final InputConnection inputConnection,
+            @NonNull final EditorInfo outAttrs) {
+        Preconditions.checkNotNull(inputConnection, "inputConnection cannot be null");
+        return new EmojiInputConnection(mEditText, inputConnection, outAttrs);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java
new file mode 100644
index 0000000..1279b31
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.support.annotation.GuardedBy;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.Editable;
+
+/**
+ * EditableFactory used to improve editing operations on an EditText.
+ * <p>
+ * EditText uses DynamicLayout, which attaches to the Spannable instance that is being edited using
+ * ChangeWatcher. ChangeWatcher implements SpanWatcher and Textwatcher. Currently every delete/add
+ * operation is reported to DynamicLayout, for every span that has changed. For each change,
+ * DynamicLayout performs some expensive computations. i.e. if there is 100 EmojiSpans and the first
+ * span is deleted, DynamicLayout gets 99 calls about the change of position occurred in the
+ * remaining spans. This causes a huge delay in response time.
+ * <p>
+ * Since "android.text.DynamicLayout$ChangeWatcher" class is not a public class,
+ * EmojiEditableFactory checks if the watcher is in the classpath, and if so uses the modified
+ * Spannable which reduces the total number of calls to DynamicLayout for operations that affect
+ * EmojiSpans.
+ *
+ * @see SpannableBuilder
+ */
+final class EmojiEditableFactory extends Editable.Factory {
+    private static final Object sInstanceLock = new Object();
+    @GuardedBy("sInstanceLock")
+    private static volatile Editable.Factory sInstance;
+
+    @Nullable private static Class<?> sWatcherClass;
+
+    private EmojiEditableFactory() {
+        try {
+            String className = "android.text.DynamicLayout$ChangeWatcher";
+            sWatcherClass = getClass().getClassLoader().loadClass(className);
+        } catch (Throwable t) {
+            // ignore
+        }
+    }
+
+    public static Editable.Factory getInstance() {
+        if (sInstance == null) {
+            synchronized (sInstanceLock) {
+                if (sInstance == null) {
+                    sInstance = new EmojiEditableFactory();
+                }
+            }
+        }
+        return sInstance;
+    }
+
+    @Override
+    public Editable newEditable(@NonNull final CharSequence source) {
+        if (sWatcherClass != null) {
+            return SpannableBuilder.create(sWatcherClass, source);
+        }
+        return super.newEditable(source);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java b/emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java
new file mode 100644
index 0000000..3347130
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.text.Editable;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+import android.widget.TextView;
+
+/**
+ * InputConnectionWrapper for EditText delete operations. Keyboard does not have knowledge about
+ * emojis and therefore might send commands to delete a part of the emoji sequence which creates
+ * invalid codeunits/getCodepointAt in the text.
+ * <p/>
+ * This class tries to correctly delete an emoji checking if there is an emoji span.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiInputConnection extends InputConnectionWrapper {
+    private final TextView mTextView;
+
+    EmojiInputConnection(
+            @NonNull final TextView textView,
+            @NonNull final InputConnection inputConnection,
+            @NonNull final EditorInfo outAttrs) {
+        super(inputConnection, false);
+        mTextView = textView;
+        EmojiCompat.get().updateEditorInfoAttrs(outAttrs);
+    }
+
+    @Override
+    public boolean deleteSurroundingText(final int beforeLength, final int afterLength) {
+        final boolean result = EmojiCompat.handleDeleteSurroundingText(this, getEditable(),
+                beforeLength, afterLength, false /* in code ponints */);
+        return result || super.deleteSurroundingText(beforeLength, afterLength);
+    }
+
+    @Override
+    public boolean deleteSurroundingTextInCodePoints(final int beforeLength,
+            final int afterLength) {
+        final boolean result = EmojiCompat.handleDeleteSurroundingText(this, getEditable(),
+                beforeLength, afterLength, true  /* in code ponints */);
+        return result || super.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+    }
+
+    private Editable getEditable() {
+        return mTextView.getEditableText();
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java b/emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java
new file mode 100644
index 0000000..e716dfd
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.EmojiCompat.InitCallback;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.widget.TextView;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+/**
+ * InputFilter to add EmojiSpans to the CharSequence set in a TextView. Unlike EditText where a
+ * TextWatcher is used to enhance the CharSequence, InputFilter is used on TextView. The reason is
+ * that if you add a TextWatcher to a TextView, its internal layout mechanism change, and therefore
+ * depending on the CharSequence provided, adding a TextWatcher might have performance side
+ * effects.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiInputFilter implements android.text.InputFilter {
+    private final TextView mTextView;
+    private InitCallback mInitCallback;
+
+    EmojiInputFilter(@NonNull final TextView textView) {
+        mTextView = textView;
+    }
+
+    @Override
+    public CharSequence filter(final CharSequence source, final int sourceStart,
+            final int sourceEnd, final Spanned dest, final int destStart, final int destEnd) {
+        if (mTextView.isInEditMode()) {
+            return source;
+        }
+
+        if (EmojiCompat.get().isInitialized()) {
+            boolean process = true;
+            if (destEnd == 0 && destStart == 0 && dest.length() == 0) {
+                final CharSequence oldText = mTextView.getText();
+                if (source == oldText) {
+                    process = false;
+                }
+            }
+
+            if (process && source != null) {
+                final CharSequence text;
+                if (sourceStart == 0 && sourceEnd == source.length()) {
+                    text = source;
+                } else {
+                    text = source.subSequence(sourceStart, sourceEnd);
+                }
+                return EmojiCompat.get().process(text, 0, text.length());
+            }
+
+            return source;
+        } else {
+            EmojiCompat.get().registerInitCallback(getInitCallback());
+            return source;
+        }
+    }
+
+    private InitCallback getInitCallback() {
+        if (mInitCallback == null) {
+            mInitCallback = new InitCallbackImpl(mTextView);
+        }
+        return mInitCallback;
+    }
+
+    private static class InitCallbackImpl extends InitCallback {
+        private final Reference<TextView> mViewRef;
+
+        InitCallbackImpl(TextView textView) {
+            mViewRef = new WeakReference<>(textView);
+        }
+
+        @Override
+        public void onInitialized() {
+            super.onInitialized();
+            final TextView textView = mViewRef.get();
+            if (textView != null && textView.isAttachedToWindow()) {
+                final CharSequence result = EmojiCompat.get().process(textView.getText());
+
+                final int selectionStart = Selection.getSelectionStart(result);
+                final int selectionEnd = Selection.getSelectionEnd(result);
+
+                textView.setText(result);
+
+                if (result instanceof Spannable) {
+                    updateSelection((Spannable) result, selectionStart, selectionEnd);
+                }
+            }
+        }
+    }
+
+    static void updateSelection(Spannable spannable, final int start, final int end) {
+        if (start >= 0 && end >= 0) {
+            Selection.setSelection(spannable, start, end);
+        } else if (start >= 0) {
+            Selection.setSelection(spannable, start);
+        } else if (end >= 0) {
+            Selection.setSelection(spannable, end);
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java b/emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java
new file mode 100644
index 0000000..f1d18af
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.text.Editable;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * KeyListener class to handle delete operations correctly.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiKeyListener implements android.text.method.KeyListener {
+    private final android.text.method.KeyListener mKeyListener;
+
+    EmojiKeyListener(android.text.method.KeyListener keyListener) {
+        mKeyListener = keyListener;
+    }
+
+    @Override
+    public int getInputType() {
+        return mKeyListener.getInputType();
+    }
+
+    @Override
+    public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
+        final boolean result = EmojiCompat.handleOnKeyDown(content, keyCode, event);
+        return result || mKeyListener.onKeyDown(view, content, keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event) {
+        return mKeyListener.onKeyUp(view, text, keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyOther(View view, Editable text, KeyEvent event) {
+        return mKeyListener.onKeyOther(view, text, event);
+    }
+
+    @Override
+    public void clearMetaKeyState(View view, Editable content, int states) {
+        mKeyListener.clearMetaKeyState(view, content, states);
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java
new file mode 100644
index 0000000..86294d0
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.text.InputFilter;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+/**
+ * TextView widget enhanced with emoji capability by using {@link EmojiTextViewHelper}.
+ */
+public class EmojiTextView extends TextView {
+    private EmojiTextViewHelper mEmojiTextViewHelper;
+    private boolean mInitialized;
+
+    public EmojiTextView(Context context) {
+        super(context);
+        init();
+    }
+
+    public EmojiTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    private void init() {
+        if (!mInitialized) {
+            mInitialized = true;
+            getEmojiTextViewHelper().updateTransformationMethod();
+        }
+    }
+
+    @Override
+    public void setFilters(InputFilter[] filters) {
+        super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+    }
+
+    @Override
+    public void setAllCaps(boolean allCaps) {
+        super.setAllCaps(allCaps);
+        getEmojiTextViewHelper().setAllCaps(allCaps);
+    }
+
+    private EmojiTextViewHelper getEmojiTextViewHelper() {
+        if (mEmojiTextViewHelper == null) {
+            mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+        }
+        return mEmojiTextViewHelper;
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
new file mode 100644
index 0000000..e88cc87
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.Preconditions;
+import android.text.InputFilter;
+import android.text.method.PasswordTransformationMethod;
+import android.text.method.TransformationMethod;
+import android.widget.TextView;
+
+/**
+ * Utility class to enhance a TextView with emoji capability.
+ */
+public final class EmojiTextViewHelper {
+    private final TextView mTextView;
+    private final EmojiInputFilter mEmojiInputFilter;
+
+    /**
+     * Default constructor.
+     *
+     * @param textView TextView instance
+     */
+    public EmojiTextViewHelper(@NonNull TextView textView) {
+        Preconditions.checkNotNull(textView, "textView cannot be null");
+        mTextView = textView;
+        mEmojiInputFilter = new EmojiInputFilter(textView);
+    }
+
+    /**
+     * Updates widget's TransformationMethod so that the transformed text can be processed.
+     * Should be called in the widget constructor.
+     *
+     * @see #getTransformationMethod(TransformationMethod)
+     */
+    public void updateTransformationMethod() {
+        final TransformationMethod transformationMethod = mTextView.getTransformationMethod();
+        if (transformationMethod != null
+                && !(transformationMethod instanceof PasswordTransformationMethod)) {
+            mTextView.setTransformationMethod(getTransformationMethod(transformationMethod));
+        }
+    }
+
+    /**
+     * Appends EmojiCompat InputFilters to the widget InputFilters. Should be called by {@link
+     * TextView#setFilters(InputFilter[])} to update the InputFilters.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public void setFilters(InputFilter[] filters) {
+     *     super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+     * }</code></pre>
+     *
+     * @param filters InputFilter array passed to {@link TextView#setFilters(InputFilter[])}
+     *
+     * @return same copy if the array already contains EmojiCompat InputFilter. A new array copy if
+     * not.
+     */
+    public InputFilter[] getFilters(@NonNull final InputFilter[] filters) {
+        final int count = filters.length;
+        for (int i = 0; i < count; i++) {
+            if (filters[i] instanceof EmojiInputFilter) {
+                return filters;
+            }
+        }
+        final InputFilter[] newFilters = new InputFilter[filters.length + 1];
+        System.arraycopy(filters, 0, newFilters, 0, count);
+        newFilters[count] = mEmojiInputFilter;
+        return newFilters;
+    }
+
+    /**
+     * Returns transformation method that can update the transformed text to display emojis.
+     *
+     * @param transformationMethod instance to be wrapped
+     */
+    public TransformationMethod getTransformationMethod(
+            final TransformationMethod transformationMethod) {
+        return new EmojiTransformationMethod(transformationMethod);
+    }
+
+    /**
+     * Call when allCaps is set on TextView.
+     * <p/>
+     * <pre><code> {@literal @}Override
+     * public void setAllCaps(boolean allCaps) {
+     *     super.setAllCaps(allCaps);
+     *     getEmojiTextViewHelper().setAllCaps(allCaps);
+     * }</code></pre>
+     *
+     * @param allCaps allCaps parameter passed to {@link TextView#setAllCaps(boolean)}
+     */
+    public void setAllCaps(boolean allCaps) {
+        // When allCaps is set to false TextView sets the transformation method to be null. We
+        // are only interested when allCaps is set to true in order to wrap the original method.
+        if (allCaps) {
+            updateTransformationMethod();
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java
new file mode 100644
index 0000000..9adc015
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.EmojiCompat.InitCallback;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.widget.EditText;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+/**
+ * TextWatcher used for an EditText.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+final class EmojiTextWatcher implements android.text.TextWatcher {
+    private final EditText mEditText;
+    private InitCallback mInitCallback;
+
+    EmojiTextWatcher(EditText editText) {
+        mEditText = editText;
+    }
+
+    @Override
+    public void onTextChanged(CharSequence charSequence, final int start, final int before,
+            final int after) {
+        if (mEditText.isInEditMode()) {
+            return;
+        }
+        //before > after --> a deletion occured
+        if (before <= after && charSequence instanceof Spannable) {
+            if (EmojiCompat.get().isInitialized()) {
+                final Spannable s = (Spannable) charSequence;
+                EmojiCompat.get().process(s, start, start + after);
+            } else {
+                EmojiCompat.get().registerInitCallback(getInitCallback());
+            }
+        }
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        // do nothing
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+        // do nothing
+    }
+
+    private InitCallback getInitCallback() {
+        if (mInitCallback == null) {
+            mInitCallback = new InitCallbackImpl(mEditText);
+        }
+        return mInitCallback;
+    }
+
+    private static class InitCallbackImpl extends InitCallback {
+        private final Reference<EditText> mViewRef;
+
+        InitCallbackImpl(EditText editText) {
+            mViewRef = new WeakReference<>(editText);
+        }
+
+        @Override
+        public void onInitialized() {
+            super.onInitialized();
+            final EditText editText = mViewRef.get();
+            if (editText != null && editText.isAttachedToWindow()) {
+                final Editable text = editText.getEditableText();
+
+                final int selectionStart = Selection.getSelectionStart(text);
+                final int selectionEnd = Selection.getSelectionEnd(text);
+
+                EmojiCompat.get().process(text);
+
+                EmojiInputFilter.updateSelection(text, selectionStart, selectionEnd);
+            }
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java
new file mode 100644
index 0000000..224b600
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiCompat;
+import android.text.method.TransformationMethod;
+import android.view.View;
+
+/**
+ * TransformationMethod wrapper in order to update transformed text with emojis.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+class EmojiTransformationMethod implements TransformationMethod {
+    private final TransformationMethod mTransformationMethod;
+
+    EmojiTransformationMethod(TransformationMethod transformationMethod) {
+        mTransformationMethod = transformationMethod;
+    }
+
+    @Override
+    public CharSequence getTransformation(@Nullable CharSequence source, @NonNull final View view) {
+        if (view.isInEditMode()) {
+            return source;
+        }
+
+        if (mTransformationMethod != null) {
+            source = mTransformationMethod.getTransformation(source, view);
+        }
+
+        if (source != null) {
+            if (EmojiCompat.get().isInitialized()) {
+                return EmojiCompat.get().process(source);
+            }
+        }
+        return source;
+    }
+
+    @Override
+    public void onFocusChanged(final View view, final CharSequence sourceText,
+            final boolean focused, final int direction, final Rect previouslyFocusedRect) {
+        if (mTransformationMethod != null) {
+            mTransformationMethod.onFocusChanged(view, sourceText, focused, direction,
+                    previouslyFocusedRect);
+        }
+    }
+}
diff --git a/emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java b/emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java
new file mode 100644
index 0000000..bbce352
--- /dev/null
+++ b/emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.text.emoji.EmojiSpan;
+import android.support.v4.util.Preconditions;
+import android.text.Editable;
+import android.text.SpanWatcher;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextWatcher;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * When setSpan functions is called on EmojiSpannableBuilder, it checks if the mObject is instance
+ * of the DynamicLayout$ChangeWatcher. if so, it wraps it into another listener mObject
+ * (WatcherWrapper) that implements the same interfaces.
+ * <p>
+ * During a span change event WatcherWrapper’s functions are fired, it checks if the span is an
+ * EmojiSpan, and prevents the ChangeWatcher being fired for that span. WatcherWrapper informs
+ * ChangeWatcher only once at the end of the edit. Important point is, the block operation is
+ * applied only for EmojiSpans. Therefore any other span change operation works the same way as in
+ * the framework.
+ *
+ * @hide
+ * @see EmojiEditableFactory
+ */
+@RestrictTo(LIBRARY_GROUP)
+public final class SpannableBuilder extends SpannableStringBuilder {
+    /**
+     * DynamicLayout$ChangeWatcher class.
+     */
+    private final Class<?> mWatcherClass;
+
+    /**
+     * All WatcherWrappers.
+     */
+    private final List<WatcherWrapper> mWatchers = new ArrayList<>();
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    SpannableBuilder(@NonNull Class<?> watcherClass) {
+        Preconditions.checkNotNull(watcherClass, "watcherClass cannot be null");
+        mWatcherClass = watcherClass;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    SpannableBuilder(@NonNull Class<?> watcherClass, @NonNull CharSequence text) {
+        super(text);
+        Preconditions.checkNotNull(watcherClass, "watcherClass cannot be null");
+        mWatcherClass = watcherClass;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    SpannableBuilder(@NonNull Class<?> watcherClass, @NonNull CharSequence text, int start,
+            int end) {
+        super(text, start, end);
+        Preconditions.checkNotNull(watcherClass, "watcherClass cannot be null");
+        mWatcherClass = watcherClass;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    static SpannableBuilder create(@NonNull Class<?> clazz, @NonNull CharSequence text) {
+        return new SpannableBuilder(clazz, text);
+    }
+
+    /**
+     * Checks whether the mObject is instance of the DynamicLayout$ChangeWatcher.
+     *
+     * @param object mObject to be checked
+     *
+     * @return true if mObject is instance of the DynamicLayout$ChangeWatcher.
+     */
+    private boolean isWatcher(@Nullable Object object) {
+        return object != null && isWatcher(object.getClass());
+    }
+
+    /**
+     * Checks whether the class is DynamicLayout$ChangeWatcher.
+     *
+     * @param clazz class to be checked
+     *
+     * @return true if class is DynamicLayout$ChangeWatcher.
+     */
+    private boolean isWatcher(@NonNull Class<?> clazz) {
+        return mWatcherClass == clazz;
+    }
+
+    @Override
+    public CharSequence subSequence(int start, int end) {
+        return new SpannableBuilder(mWatcherClass, this, start, end);
+    }
+
+    /**
+     * If the span being added is instance of DynamicLayout$ChangeWatcher, wrap the watcher in
+     * another internal watcher that will prevent EmojiSpan events to be fired to DynamicLayout. Set
+     * this new mObject as the span.
+     */
+    @Override
+    public void setSpan(Object what, int start, int end, int flags) {
+        if (isWatcher(what)) {
+            final WatcherWrapper span = new WatcherWrapper(what);
+            mWatchers.add(span);
+            what = span;
+        }
+        super.setSpan(what, start, end, flags);
+    }
+
+    /**
+     * If previously a DynamicLayout$ChangeWatcher was wrapped in a WatcherWrapper, return the
+     * correct Object that the client has set.
+     */
+    @Override
+    public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
+        if (isWatcher(kind)) {
+            final WatcherWrapper[] spans = super.getSpans(queryStart, queryEnd,
+                    WatcherWrapper.class);
+            final T[] result = (T[]) Array.newInstance(kind, spans.length);
+            for (int i = 0; i < spans.length; i++) {
+                result[i] = (T) spans[i].mObject;
+            }
+            return result;
+        }
+        return super.getSpans(queryStart, queryEnd, kind);
+    }
+
+    /**
+     * If the client wants to remove the DynamicLayout$ChangeWatcher span, remove the WatcherWrapper
+     * instead.
+     */
+    @Override
+    public void removeSpan(Object what) {
+        final WatcherWrapper watcher;
+        if (isWatcher(what)) {
+            watcher = getWatcherFor(what);
+            if (watcher != null) {
+                what = watcher;
+            }
+        } else {
+            watcher = null;
+        }
+
+        super.removeSpan(what);
+
+        if (watcher != null) {
+            mWatchers.remove(watcher);
+        }
+    }
+
+    /**
+     * Return the correct start for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int getSpanStart(Object tag) {
+        if (isWatcher(tag)) {
+            final WatcherWrapper watcher = getWatcherFor(tag);
+            if (watcher != null) {
+                tag = watcher;
+            }
+        }
+        return super.getSpanStart(tag);
+    }
+
+    /**
+     * Return the correct end for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int getSpanEnd(Object tag) {
+        if (isWatcher(tag)) {
+            final WatcherWrapper watcher = getWatcherFor(tag);
+            if (watcher != null) {
+                tag = watcher;
+            }
+        }
+        return super.getSpanEnd(tag);
+    }
+
+    /**
+     * Return the correct flags for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int getSpanFlags(Object tag) {
+        if (isWatcher(tag)) {
+            final WatcherWrapper watcher = getWatcherFor(tag);
+            if (watcher != null) {
+                tag = watcher;
+            }
+        }
+        return super.getSpanFlags(tag);
+    }
+
+    /**
+     * Return the correct transition for the DynamicLayout$ChangeWatcher span.
+     */
+    @Override
+    public int nextSpanTransition(int start, int limit, Class type) {
+        if (isWatcher(type)) {
+            type = WatcherWrapper.class;
+        }
+        return super.nextSpanTransition(start, limit, type);
+    }
+
+    /**
+     * Find the WatcherWrapper for a given DynamicLayout$ChangeWatcher.
+     *
+     * @param object DynamicLayout$ChangeWatcher mObject
+     *
+     * @return WatcherWrapper that wraps the mObject.
+     */
+    private WatcherWrapper getWatcherFor(Object object) {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            WatcherWrapper watcher = mWatchers.get(i);
+            if (watcher.mObject == object) {
+                return watcher;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void beginBatchEdit() {
+        blockWatchers();
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void endBatchEdit() {
+        unblockwatchers();
+        fireWatchers();
+    }
+
+    /**
+     * Block all watcher wrapper events.
+     */
+    private void blockWatchers() {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            mWatchers.get(i).blockCalls();
+        }
+    }
+
+    /**
+     * Unblock all watcher wrapper events.
+     */
+    private void unblockwatchers() {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            mWatchers.get(i).unblockCalls();
+        }
+    }
+
+    /**
+     * Unblock all watcher wrapper events. Called by editing operations, namely
+     * {@link SpannableStringBuilder#replace(int, int, CharSequence)}.
+     */
+    private void fireWatchers() {
+        for (int i = 0; i < mWatchers.size(); i++) {
+            mWatchers.get(i).onTextChanged(this, 0, this.length(), this.length());
+        }
+    }
+
+    @Override
+    public SpannableStringBuilder replace(int start, int end, CharSequence tb) {
+        blockWatchers();
+        super.replace(start, end, tb);
+        unblockwatchers();
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart,
+            int tbend) {
+        blockWatchers();
+        super.replace(start, end, tb, tbstart, tbend);
+        unblockwatchers();
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder insert(int where, CharSequence tb) {
+        super.insert(where, tb);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) {
+        super.insert(where, tb, start, end);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder delete(int start, int end) {
+        super.delete(start, end);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(CharSequence text) {
+        super.append(text);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(char text) {
+        super.append(text);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(CharSequence text, int start, int end) {
+        super.append(text, start, end);
+        return this;
+    }
+
+    @Override
+    public SpannableStringBuilder append(CharSequence text, Object what, int flags) {
+        super.append(text, what, flags);
+        return this;
+    }
+
+    /**
+     * Wraps a DynamicLayout$ChangeWatcher in order to prevent firing of events to DynamicLayout.
+     */
+    private static class WatcherWrapper implements TextWatcher, SpanWatcher {
+        private final Object mObject;
+        private final AtomicInteger mBlockCalls = new AtomicInteger(0);
+
+        WatcherWrapper(Object object) {
+            this.mObject = object;
+        }
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            ((TextWatcher) mObject).beforeTextChanged(s, start, count, after);
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            ((TextWatcher) mObject).onTextChanged(s, start, before, count);
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            ((TextWatcher) mObject).afterTextChanged(s);
+        }
+
+        /**
+         * Prevent the onSpanAdded calls to DynamicLayout$ChangeWatcher if in a replace operation
+         * (mBlockCalls is set) and the span that is added is an EmojiSpan.
+         */
+        @Override
+        public void onSpanAdded(Spannable text, Object what, int start, int end) {
+            if (mBlockCalls.get() > 0 && isEmojiSpan(what)) {
+                return;
+            }
+            ((SpanWatcher) mObject).onSpanAdded(text, what, start, end);
+        }
+
+        /**
+         * Prevent the onSpanRemoved calls to DynamicLayout$ChangeWatcher if in a replace operation
+         * (mBlockCalls is set) and the span that is added is an EmojiSpan.
+         */
+        @Override
+        public void onSpanRemoved(Spannable text, Object what, int start, int end) {
+            if (mBlockCalls.get() > 0 && isEmojiSpan(what)) {
+                return;
+            }
+            ((SpanWatcher) mObject).onSpanRemoved(text, what, start, end);
+        }
+
+        /**
+         * Prevent the onSpanChanged calls to DynamicLayout$ChangeWatcher if in a replace operation
+         * (mBlockCalls is set) and the span that is added is an EmojiSpan.
+         */
+        @Override
+        public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart,
+                int nend) {
+            if (mBlockCalls.get() > 0 && isEmojiSpan(what)) {
+                return;
+            }
+            ((SpanWatcher) mObject).onSpanChanged(text, what, ostart, oend, nstart, nend);
+        }
+
+        final void blockCalls() {
+            mBlockCalls.incrementAndGet();
+        }
+
+        final void unblockCalls() {
+            mBlockCalls.decrementAndGet();
+        }
+
+        private boolean isEmojiSpan(final Object span) {
+            return span instanceof EmojiSpan;
+        }
+    }
+
+}
diff --git a/dynamic-animation/AndroidManifest-make.xml b/emoji/core/tests/AndroidManifest.xml
similarity index 83%
rename from dynamic-animation/AndroidManifest-make.xml
rename to emoji/core/tests/AndroidManifest.xml
index bfe97cc..4c706b2 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/emoji/core/tests/AndroidManifest.xml
@@ -14,6 +14,10 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+          package="android.support.text.emoji">
+
+    <application>
+        <activity android:name=".TestActivity"/>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/emoji/core/tests/assets/NotoColorEmojiCompat.ttf b/emoji/core/tests/assets/NotoColorEmojiCompat.ttf
new file mode 100644
index 0000000..0c59d8e
--- /dev/null
+++ b/emoji/core/tests/assets/NotoColorEmojiCompat.ttf
Binary files differ
diff --git a/emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java b/emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java
new file mode 100644
index 0000000..f84ecbc
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiAt;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+
+import static junit.framework.TestCase.assertTrue;
+
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.text.emoji.test.R;
+import android.support.text.emoji.util.TestString;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Reads raw/allemojis.txt which includes all the emojis known to human kind and tests that
+ * EmojiCompat creates EmojiSpans for each one of them.
+ */
+@SmallTest
+@RunWith(Parameterized.class)
+public class AllEmojisTest {
+
+    /**
+     * String representation for a single emoji
+     */
+    private String mString;
+
+    /**
+     * Codepoints of emoji for better assert error message.
+     */
+    private String mCodepoints;
+
+    @BeforeClass
+    public static void setup() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> data() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final InputStream inputStream = context.getResources().openRawResource(R.raw.all_emojis);
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+        final Collection<Object[]> data = new ArrayList<>();
+        final StringBuilder stringBuilder = new StringBuilder();
+        final StringBuilder codePointsBuilder = new StringBuilder();
+        final int hexPrefixLength = "0x".length();
+
+        try {
+            String s;
+            while ((s = reader.readLine()) != null) {
+                stringBuilder.setLength(0);
+                codePointsBuilder.setLength(0);
+
+                // emoji codepoints are space separated: i.e. 0x1f1e6 0x1f1e8
+                final String[] split = s.split(" ");
+
+                for (int index = 0; index < split.length; index++) {
+                    final String part = split[index];
+                    final String substring = part.substring(hexPrefixLength, part.length());
+                    codePointsBuilder.append(substring);
+                    codePointsBuilder.append(",");
+                    stringBuilder.append(Character.toChars(Integer.parseInt(substring, 16)));
+                }
+                data.add(new Object[]{stringBuilder.toString(), codePointsBuilder.toString()});
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return data;
+    }
+
+    public AllEmojisTest(String string, String codepoints) {
+        mString = string;
+        mCodepoints = codepoints;
+    }
+
+    @Test
+    public void testEmoji() {
+        assertTrue("EmojiCompat should have emoji: " + mCodepoints,
+                EmojiCompat.get().hasEmojiGlyph(mString));
+        assertEmojiCompatAddsEmoji(mString);
+    }
+
+    private void assertEmojiCompatAddsEmoji(final String str) {
+        TestString string = new TestString(str);
+        CharSequence sequence = EmojiCompat.get().process(string.toString());
+        assertThat(sequence, hasEmojiCount(1));
+        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is in the middle of string
+        string = new TestString(str).withPrefix().withSuffix();
+        sequence = EmojiCompat.get().process(string.toString());
+        assertThat(sequence, hasEmojiCount(1));
+        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is at the end of string
+        string = new TestString(str).withSuffix();
+        sequence = EmojiCompat.get().process(string.toString());
+        assertThat(sequence, hasEmojiCount(1));
+        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/ConfigTest.java b/emoji/core/tests/java/android/support/text/emoji/ConfigTest.java
new file mode 100644
index 0000000..d293dab
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/ConfigTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.text.emoji.util.Emoji.EMOJI_SINGLE_CODEPOINT;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.util.TestString;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ConfigTest {
+
+    Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testConstructor_throwsExceptionIfMetadataLoaderNull() {
+        new TestConfigBuilder.TestConfig(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMaxEmojiPerText_throwsExceptionIfNegative() {
+        new ValidTestConfig().setMaxEmojiPerText(-1);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testInitCallback_throwsExceptionIfNull() {
+        new ValidTestConfig().registerInitCallback(null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testUnregisterInitCallback_throwsExceptionIfNull() {
+        new ValidTestConfig().unregisterInitCallback(null);
+    }
+
+    @Test
+    public void testBuild_withDefaultValues() {
+        final EmojiCompat.Config config = new ValidTestConfig().setReplaceAll(true);
+
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+
+        final CharSequence processed = emojiCompat.process(new TestString(EMOJI_SINGLE_CODEPOINT)
+                .toString());
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
+    }
+
+    @Test
+    public void testBuild_withMaxEmojiSetToZero() {
+        final EmojiCompat.Config config = new ValidTestConfig().setReplaceAll(true)
+                .setMaxEmojiPerText(0);
+
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        final CharSequence processed = emojiCompat.process(original);
+
+        assertThat(processed, not(hasEmoji()));
+    }
+
+    @Test
+    public void testBuild_withMaxEmojiSetToOne() {
+        final EmojiCompat.Config config = new ValidTestConfig().setReplaceAll(true)
+                .setMaxEmojiPerText(1);
+
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        final CharSequence processed = emojiCompat.process(original);
+
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
+    }
+
+    @Test
+    public void testInitCallback_callsSuccessCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+
+        final EmojiCompat.Config config = new ValidTestConfig().registerInitCallback(initCallback1)
+                .registerInitCallback(initCallback2);
+        EmojiCompat.reset(config);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onInitialized();
+        verify(initCallback2, times(1)).onInitialized();
+    }
+
+    @Test
+    public void testInitCallback_callsFailCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = mock(EmojiCompat.MetadataLoader.class);
+        doThrow(new RuntimeException("")).when(loader).load(any(EmojiCompat.LoaderCallback
+                .class));
+
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .registerInitCallback(initCallback1)
+                .registerInitCallback(initCallback2);
+        EmojiCompat.reset(config);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onFailed(any(Throwable.class));
+        verify(initCallback2, times(1)).onFailed(any(Throwable.class));
+    }
+
+    private static class ValidTestConfig extends EmojiCompat.Config {
+        ValidTestConfig() {
+            super(new TestConfigBuilder.TestEmojiDataLoader());
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java
new file mode 100644
index 0000000..05c1367
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.text.emoji.TestConfigBuilder.TestConfig;
+import static android.support.text.emoji.TestConfigBuilder.WaitingDataLoader;
+import static android.support.text.emoji.TestConfigBuilder.config;
+import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_EMOJI_STYLE;
+import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_TEXT_STYLE;
+import static android.support.text.emoji.util.Emoji.CHAR_DIGIT;
+import static android.support.text.emoji.util.Emoji.CHAR_FITZPATRICK;
+import static android.support.text.emoji.util.Emoji.CHAR_VS_EMOJI;
+import static android.support.text.emoji.util.Emoji.CHAR_VS_TEXT;
+import static android.support.text.emoji.util.Emoji.DEFAULT_TEXT_STYLE;
+import static android.support.text.emoji.util.Emoji.EMOJI_ASTERISK_KEYCAP;
+import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES;
+import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES_KEYCAP;
+import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_KEYCAP;
+import static android.support.text.emoji.util.Emoji.EMOJI_FLAG;
+import static android.support.text.emoji.util.Emoji.EMOJI_GENDER;
+import static android.support.text.emoji.util.Emoji.EMOJI_GENDER_WITHOUT_VS;
+import static android.support.text.emoji.util.Emoji.EMOJI_REGIONAL_SYMBOL;
+import static android.support.text.emoji.util.Emoji.EMOJI_SINGLE_CODEPOINT;
+import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER;
+import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_TYPE_ONE;
+import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_WITH_VS;
+import static android.support.text.emoji.util.Emoji.EMOJI_UNKNOWN_FLAG;
+import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiAt;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+
+import static junit.framework.TestCase.assertFalse;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat.Config;
+import android.support.text.emoji.util.Emoji.EmojiMapping;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
+import android.view.inputmethod.EditorInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiCompatTest {
+
+    @Before
+    public void setup() {
+        EmojiCompat.reset(config());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testGet_throwsException() throws Exception {
+        EmojiCompat.reset((EmojiCompat) null);
+        EmojiCompat.get();
+    }
+
+    @Test
+    public void testProcess_doesNothing_withNullCharSequence() throws Exception {
+        assertNull(EmojiCompat.get().process(null));
+    }
+
+    @Test
+    public void testProcess_returnsEmptySpanned_withEmptyString() throws Exception {
+        final CharSequence charSequence = EmojiCompat.get().process("");
+        assertNotNull(charSequence);
+        assertEquals(0, charSequence.length());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withNegativeStartValue() throws Exception {
+        EmojiCompat.get().process("a", -1, 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withNegativeEndValue() throws Exception {
+        EmojiCompat.get().process("a", 1, -1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withStartSmallerThanEndValue() throws Exception {
+        EmojiCompat.get().process("aa", 1, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withStartGreaterThanLength() throws Exception {
+        EmojiCompat.get().process("a", 2, 2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withEndGreaterThanLength() throws Exception {
+        EmojiCompat.get().process("a", 0, 2);
+    }
+
+    @Test
+    public void testProcessWithStartEnd_withNoOpValues() throws Exception {
+        final Spannable spannable = new SpannableString(new TestString('a')
+                .withPrefix().withSuffix().toString());
+        // early return check
+        assertSame(spannable, EmojiCompat.get().process(spannable, 0, 0));
+        assertSame(spannable, EmojiCompat.get().process(spannable, 1, 1));
+        assertSame(spannable, EmojiCompat.get().process(spannable, spannable.length(),
+                spannable.length()));
+    }
+
+
+    @Test
+    public void testProcess_doesNotAddEmojiSpan() throws Exception {
+        final String string = "abc";
+        final CharSequence charSequence = EmojiCompat.get().process(string);
+        assertNotNull(charSequence);
+        assertEquals(string, charSequence.toString());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+
+    @Test
+    public void testProcess_addsSingleCodePointEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_SINGLE_CODEPOINT);
+    }
+
+    @Test
+    public void testProcess_addsFlagEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_FLAG);
+    }
+
+    @Test
+    public void testProcess_addsUnknownFlagEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_UNKNOWN_FLAG);
+    }
+
+    @Test
+    public void testProcess_addsRegionalIndicatorSymbol() throws Exception {
+        assertCodePointMatch(EMOJI_REGIONAL_SYMBOL);
+    }
+
+    @Test
+    public void testProcess_addsKeyCapEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_DIGIT_KEYCAP);
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmojiForNumbers() throws Exception {
+        assertCodePointDoesNotMatch(new int[] {CHAR_DIGIT});
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmojiForNumbers_1() throws Exception {
+        final TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).append('1', 'f');
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiCount(1));
+    }
+
+    @Test
+    public void testProcess_addsVariantSelectorEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_DIGIT_ES);
+    }
+
+    @Test
+    public void testProcess_doesNotAddVariantSelectorTextStyle() throws Exception {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT, CHAR_VS_TEXT});
+    }
+
+    @Test
+    public void testProcess_addsVariantSelectorAndKeyCapEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_DIGIT_ES_KEYCAP);
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmoji_forVariantBaseWithoutSelector() throws Exception {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT});
+    }
+
+    @Test
+    public void testProcess_addsAsteriskKeyCapEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_ASTERISK_KEYCAP);
+    }
+
+    @Test
+    public void testProcess_addsSkinModifierEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER);
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER_TYPE_ONE);
+    }
+
+    @Test
+    public void testProcess_addsSkinModifierEmoji_withVariantSelector() throws Exception {
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER_WITH_VS);
+    }
+
+    @Test
+    public void testProcess_addsSkinModifierEmoji_270c_withVariantSelector() throws Exception {
+        // 0x270c is a Standardized Variant Base, Emoji Modifier Base and also Emoji
+        // therefore it is different than i.e. 0x1f3c3. The code actually failed for this test
+        // at first.
+        assertCodePointMatch(0xF0734, new int[]{0x270C, CHAR_VS_EMOJI, CHAR_FITZPATRICK});
+    }
+
+    @Test
+    public void testProcess_defaultStyleDoesNotAddSpan() throws Exception {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_TEXT_STYLE});
+        assertCodePointMatch(DEFAULT_TEXT_STYLE);
+    }
+
+    @Test
+    public void testProcess_defaultEmojiStyle_withTextStyleVs() throws Exception {
+        assertCodePointMatch(EMOJI_SINGLE_CODEPOINT.id(),
+                new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI});
+        assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT});
+    }
+
+    @Test
+    public void testProcess_genderEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_GENDER);
+        assertCodePointMatch(EMOJI_GENDER_WITHOUT_VS);
+    }
+
+    @Test
+    public void testProcess_standardizedVariantEmojiExceptions() throws Exception {
+        final int[][] exceptions = new int[][]{
+                {0x2600, 0xF034D},
+                {0x2601, 0xF0167},
+                {0x260E, 0xF034E},
+                {0x261D, 0xF0227},
+                {0x263A, 0xF02A6},
+                {0x2660, 0xF0350},
+                {0x2663, 0xF033F},
+                {0x2665, 0xF033B},
+                {0x2666, 0xF033E},
+                {0x270C, 0xF0079},
+                {0x2744, 0xF0342},
+                {0x2764, 0xF0362}
+        };
+
+        for (int i = 0; i < exceptions.length; i++) {
+            final int[] codepoints = new int[]{exceptions[i][0]};
+            assertCodePointMatch(exceptions[i][1], codepoints);
+        }
+    }
+
+    @Test
+    public void testProcess_addsZwjEmoji() throws Exception {
+        assertCodePointMatch(EMOJI_WITH_ZWJ);
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmojiForNumbersAfterZwjEmo() throws Exception {
+        TestString string = new TestString(EMOJI_WITH_ZWJ).append(0x20, 0x2B, 0x31)
+                .withSuffix().withPrefix();
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(),
+                string.emojiEndIndex() - 3));
+        assertThat(charSequence, hasEmojiCount(1));
+
+        string = new TestString(EMOJI_WITH_ZWJ).withSuffix().withPrefix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiCount(1));
+    }
+
+    @Test
+    public void testProcess_withAppend() throws Exception {
+        final Editable editable = new SpannableStringBuilder(new TestString('a').withPrefix()
+                .withSuffix().toString());
+        final int start = 1;
+        final int end = start + EMOJI_SINGLE_CODEPOINT.charCount();
+        editable.insert(start, new TestString(EMOJI_SINGLE_CODEPOINT).toString());
+        EmojiCompat.get().process(editable, start, end);
+        assertThat(editable, hasEmojiCount(1));
+        assertThat(editable, hasEmojiAt(EMOJI_SINGLE_CODEPOINT, start, end));
+    }
+
+    @Test
+    public void testProcess_doesNotCreateSpannable_ifNoEmoji() throws Exception {
+        CharSequence processed = EmojiCompat.get().process("abc");
+        assertNotNull(processed);
+        assertThat(processed, instanceOf(String.class));
+
+        processed = EmojiCompat.get().process(new SpannedString("abc"));
+        assertNotNull(processed);
+        assertThat(processed, instanceOf(SpannedString.class));
+    }
+
+    @Test
+    public void testProcess_reprocess() throws Exception {
+        final String string = new TestString(EMOJI_SINGLE_CODEPOINT)
+                .append(EMOJI_SINGLE_CODEPOINT)
+                .append(EMOJI_SINGLE_CODEPOINT)
+                .withPrefix().withSuffix().toString();
+
+        Spannable processed = (Spannable) EmojiCompat.get().process(string);
+        assertThat(processed, hasEmojiCount(3));
+
+        final EmojiSpan[] spans = processed.getSpans(0, processed.length(), EmojiSpan.class);
+        final Set<EmojiSpan> spanSet = new HashSet<>();
+        for (int i = 0; i < spans.length; i++) {
+            spanSet.add(spans[i]);
+        }
+
+        processed = (Spannable) EmojiCompat.get().process(processed);
+        assertThat(processed, hasEmojiCount(3));
+        // new spans should be new instances
+        final EmojiSpan[] newSpans = processed.getSpans(0, processed.length(), EmojiSpan.class);
+        for (int i = 0; i < newSpans.length; i++) {
+            assertFalse(spanSet.contains(newSpans[i]));
+        }
+    }
+
+    @Test
+    public void testHasGlyph_returnsMetadata() throws Exception {
+        final String sequence = new TestString(EMOJI_FLAG).toString();
+        assertNotNull(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    public void testHasGlyph_returnsNullForNonExistentEmoji() throws Exception {
+        final String sequence = new TestString(EMOJI_FLAG).append(0x1111).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    public void testHashGlyph_withDefaultEmojiStyles() throws Exception {
+        String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
+
+        sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI}).toString();
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
+
+        sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT}).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    public void testHashGlyph_withMetadataVersion() throws Exception {
+        final String sequence = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, 0));
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE));
+    }
+
+    @Test
+    public void testIsInitialized_returnsTrueIfLoadSuccess() throws InterruptedException {
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(true /*success*/);
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        assertFalse(EmojiCompat.get().isInitialized());
+
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        assertTrue(EmojiCompat.get().isInitialized());
+    }
+
+    @Test
+    public void testIsInitialized_returnsFalseIfLoadFail() throws InterruptedException {
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(false/*fail*/);
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        assertFalse(EmojiCompat.get().isInitialized());
+
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        assertFalse(EmojiCompat.get().isInitialized());
+    }
+
+    @Test
+    public void testUpdateEditorInfoAttrs_doesNotSetKeyIfNotInitialized() {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.extras = new Bundle();
+
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader();
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
+
+        final Bundle extras = editorInfo.extras;
+        assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY));
+        assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+
+        metadataLoader.getLoaderLatch().countDown();
+    }
+
+    @Test
+    public void testUpdateEditorInfoAttrs_setsKeysIfInitialized() {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.extras = new Bundle();
+        Config config = new TestConfig().setReplaceAll(false);
+        EmojiCompat.reset(config);
+        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
+
+        final Bundle extras = editorInfo.extras;
+        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY));
+        assertTrue(extras.getInt(EmojiCompat.EDITOR_INFO_METAVERSION_KEY) > 0);
+        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+        assertFalse(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+
+        config = new TestConfig().setReplaceAll(true);
+        EmojiCompat.reset(config);
+        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
+
+        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+        assertTrue(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+    }
+
+    private void assertCodePointMatch(EmojiMapping emoji) {
+        assertCodePointMatch(emoji.id(), emoji.codepoints());
+    }
+
+    private void assertCodePointMatch(int id, int[] codepoints) {
+        TestString string = new TestString(codepoints);
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is in the middle of string
+        string = new TestString(codepoints).withPrefix().withSuffix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is at the end of string
+        string = new TestString(codepoints).withSuffix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
+    }
+
+    private void assertCodePointDoesNotMatch(int[] codepoints) {
+        TestString string = new TestString(codepoints);
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, not(hasEmoji()));
+
+        string = new TestString(codepoints).withSuffix().withPrefix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, not(hasEmoji()));
+
+        string = new TestString(codepoints).withPrefix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+
+    //FAILS: CHAR_DIGIT, CHAR_VS_EMOJI, CHAR_VS_TEXT
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java
new file mode 100644
index 0000000..eb0ba3a
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.text.emoji.util.Emoji.EMOJI_SINGLE_CODEPOINT;
+import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiAt;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+import static android.support.text.emoji.util.KeyboardUtil.del;
+import static android.support.text.emoji.util.KeyboardUtil.forwardDel;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertThat;
+
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.test.R;
+import android.support.text.emoji.util.KeyboardUtil;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.style.RelativeSizeSpan;
+import android.util.TypedValue;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiInstrumentationTest {
+
+    @Rule
+    public ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule<>(
+            TestActivity.class);
+    private Instrumentation mInstrumentation;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    @Test
+    public void testGetSize_withRelativeSizeSpan() throws Exception {
+        final TestActivity activity = mActivityRule.getActivity();
+        final TextView textView = (TextView) activity.findViewById(R.id.text);
+
+        // create a string with single codepoint emoji
+        final TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).withPrefix().withSuffix();
+        final CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertNotNull(charSequence);
+        assertThat(charSequence, hasEmojiCount(1));
+
+        final Spannable spanned = (Spannable) charSequence;
+        final EmojiSpan[] spans = spanned.getSpans(0, charSequence.length(), EmojiSpan.class);
+        final EmojiSpan span = spans[0];
+
+        // set text to the charSequence with the EmojiSpan
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setText(charSequence);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // record height of the default span
+        final int defaultHeight = span.getHeight();
+
+        // cover the charsequence with RelativeSizeSpan which will triple the size of the
+        // characters.
+        final RelativeSizeSpan sizeSpan = new RelativeSizeSpan(3.0f);
+        spanned.setSpan(sizeSpan, 0, charSequence.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        // set the new text
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setText(charSequence);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // record the height measured after RelativeSizeSpan
+        final int heightWithRelativeSpan = span.getHeight();
+
+        // accept 1sp error rate.
+        final float delta = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1,
+                mInstrumentation.getTargetContext().getResources().getDisplayMetrics());
+        assertEquals(defaultHeight * 3, heightWithRelativeSpan, delta);
+    }
+
+    @Test
+    public void testAppendWithSoftKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        Editable editable = editText.getEditableText();
+
+        // 0xf0950 is the remapped codepoint for WOMEN_WITH_BALL
+        assertThat(editable, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(),
+                string.emojiEndIndex()));
+    }
+
+    @Test
+    public void testBackDeleteWithSoftKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiEndIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.deleteSurrondingText(inputConnection, 1, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+
+    @Test
+    public void testForwardDeleteWithSoftKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiStartIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.deleteSurrondingText(inputConnection, 0, 1);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+
+    @Test
+    public void testBackDeleteWithHardwareKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiEndIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+
+        mInstrumentation.sendKeySync(del());
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+
+    @Test
+    public void testForwardDeleteWithHardwareKeyboard() throws Exception {
+        TestActivity activity = mActivityRule.getActivity();
+        final EditText editText = (EditText) activity.findViewById(R.id.editText);
+        final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
+                .withSuffix();
+        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
+                Selection.setSelection(editText.getEditableText(), string.emojiStartIndex());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final Editable editable = editText.getEditableText();
+        assertThat(editable, hasEmoji());
+
+        mInstrumentation.sendKeySync(forwardDel());
+        mInstrumentation.waitForIdleSync();
+        assertThat(editable, not(hasEmoji()));
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java
new file mode 100644
index 0000000..3abf89e
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Paint.FontMetricsInt;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextPaint;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiSpanTest {
+
+    @Before
+    public void setup() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Test
+    public void testGetSize() throws Exception {
+        final short dimensionX = 18;
+        final short dimensionY = 20;
+        final int fontHeight = 10;
+        final float expectedRatio = fontHeight * 1.0f / dimensionY;
+        final TextPaint paint = mock(TextPaint.class);
+
+        // mock TextPaint to return test font metrics
+        when(paint.getFontMetricsInt(any(FontMetricsInt.class))).thenAnswer(new Answer<Object>() {
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                final FontMetricsInt fontMetrics = (FontMetricsInt) invocation.getArguments()[0];
+                fontMetrics.ascent = 0;
+                fontMetrics.descent = -fontHeight;
+                return null;
+            }
+        });
+
+        final EmojiMetadata metadata = mock(EmojiMetadata.class);
+        when(metadata.getWidth()).thenReturn(dimensionX);
+        when(metadata.getHeight()).thenReturn(dimensionY);
+        final EmojiSpan span = new TypefaceEmojiSpan(metadata);
+
+        final int resultSize = span.getSize(paint, "", 0, 0, null);
+        assertEquals((int) (dimensionX * expectedRatio), resultSize);
+        assertEquals(expectedRatio, span.getRatio());
+        assertEquals((int) (dimensionX * expectedRatio), span.getWidth());
+        assertEquals((int) (dimensionY * expectedRatio), span.getHeight());
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java b/emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java
new file mode 100644
index 0000000..53078ae
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.text.emoji.util.Emoji.EMOJI_FLAG;
+import static android.support.text.emoji.util.Emoji.EMOJI_GENDER;
+import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+import static android.support.text.emoji.util.KeyboardUtil.altDel;
+import static android.support.text.emoji.util.KeyboardUtil.ctrlDel;
+import static android.support.text.emoji.util.KeyboardUtil.del;
+import static android.support.text.emoji.util.KeyboardUtil.fnDel;
+import static android.support.text.emoji.util.KeyboardUtil.forwardDel;
+import static android.support.text.emoji.util.KeyboardUtil.shiftDel;
+import static android.support.text.emoji.util.KeyboardUtil.zero;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.view.KeyEvent;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HardDeleteTest {
+
+    private TestString mTestString;
+    private Editable mEditable;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mTestString = new TestString(EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmojiCount(1));
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenKeyCodeIsNotDelOrForwardDel() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = zero();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withOtherModifiers() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = fnDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withAltModifier() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = altDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withCtrlModifier() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = ctrlDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withShiftModifier() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = shiftDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withSelectionLongerThanZeroLength() {
+        // when there is a selection which is longer than 0, it should not delete.
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        final KeyEvent event = del();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withoutEmojiSpans() {
+        final Editable editable = new SpannableStringBuilder("abc");
+        Selection.setSelection(editable, 1);
+        final KeyEvent event = del();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenNoSpansBefore() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = del();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = del();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotForwardDeleteEmoji_withNoSpansAfter() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = forwardDel();
+        assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_forwardDeletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = forwardDel();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji_ifSelectionIsInSpanBoundaries() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex() + 1);
+        final KeyEvent delEvent = del();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, delEvent.getKeyCode(), delEvent));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji_ifSelectionIsInSpanBoundaries_withForwardDel() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex() + 1);
+        final KeyEvent forwardDelEvent = forwardDel();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, forwardDelEvent.getKeyCode(),
+                forwardDelEvent));
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testOnKeyDown_deletesOnlyEmojiBeforeTheCursor() {
+        // contains three emojis
+        mTestString = new TestString(EMOJI_FLAG)
+                .append(EMOJI_WITH_ZWJ)
+                .append(EMOJI_GENDER)
+                .withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        EmojiCompat.get().process(mEditable);
+
+        // put the cursor after the second emoji
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex()
+                + EMOJI_FLAG.charCount()
+                + EMOJI_WITH_ZWJ.charCount());
+
+        // delete
+        final KeyEvent forwardDelEvent = del();
+        assertTrue(EmojiCompat.handleOnKeyDown(mEditable, forwardDelEvent.getKeyCode(),
+                forwardDelEvent));
+
+        assertThat(mEditable, hasEmojiCount(2));
+        assertThat(mEditable, hasEmoji(EMOJI_FLAG));
+        assertThat(mEditable, hasEmoji(EMOJI_GENDER));
+
+        assertEquals(new TestString(EMOJI_FLAG).append(EMOJI_GENDER)
+                .withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java b/emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java
new file mode 100644
index 0000000..ae07af5
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.TestConfigBuilder.TestConfig;
+import android.support.text.emoji.TestConfigBuilder.WaitingDataLoader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InitCallbackTest {
+
+    @Test
+    public void testRegisterInitCallback_callsSuccessCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+
+        final EmojiCompat.Config config = TestConfigBuilder.config();
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback1);
+        emojiCompat.registerInitCallback(initCallback2);
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onInitialized();
+        verify(initCallback2, times(1)).onInitialized();
+    }
+
+    @Test
+    public void testRegisterInitCallback_callsFailCallback() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = mock(EmojiCompat.MetadataLoader.class);
+        doThrow(new RuntimeException("")).when(loader).load(any(EmojiCompat.LoaderCallback
+                .class));
+
+        final EmojiCompat.Config config = new TestConfig(loader);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback1);
+        emojiCompat.registerInitCallback(initCallback2);
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onFailed(any(Throwable.class));
+        verify(initCallback2, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testRegisterInitCallback_callsFailCallback_whenOnFailCalledByLoader() {
+        final EmojiCompat.InitCallback initCallback = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = new EmojiCompat.MetadataLoader() {
+            @Override
+            public void load(EmojiCompat.LoaderCallback loaderCallback) {
+                loaderCallback.onFailed(new RuntimeException(""));
+            }
+        };
+
+        final EmojiCompat.Config config = new TestConfig(loader);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testRegisterInitCallback_callsFailCallback_whenMetadataRepoIsNull() {
+        final EmojiCompat.InitCallback initCallback = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.MetadataLoader loader = new EmojiCompat.MetadataLoader() {
+            @Override
+            public void load(EmojiCompat.LoaderCallback loaderCallback) {
+                loaderCallback.onLoaded(null);
+            }
+        };
+
+        final EmojiCompat.Config config = new TestConfig(loader);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testUnregisterInitCallback_doesNotInteractWithCallback()
+            throws InterruptedException {
+        // will be registered
+        final EmojiCompat.InitCallback callback = mock(EmojiCompat.InitCallback.class);
+        // will be registered, and then unregistered before metadata load is complete
+        final EmojiCompat.InitCallback callbackUnregister = mock(EmojiCompat.InitCallback.class);
+        // will be registered to config
+        final EmojiCompat.InitCallback callbackConfigUnregister = mock(
+                EmojiCompat.InitCallback.class);
+        // will be registered to config and then unregistered
+        final EmojiCompat.InitCallback callbackConfig = mock(EmojiCompat.InitCallback.class);
+
+        //make sure that loader does not load before unregister
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(false/*fail*/);
+        final EmojiCompat.Config config = new TestConfig(metadataLoader)
+                .registerInitCallback(callbackConfig)
+                .registerInitCallback(callbackConfigUnregister)
+                .unregisterInitCallback(callbackConfigUnregister);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        // register before metadata is loaded
+        emojiCompat.registerInitCallback(callbackUnregister);
+        emojiCompat.registerInitCallback(callback);
+
+        // unregister before metadata is loaded
+        emojiCompat.unregisterInitCallback(callbackUnregister);
+
+        // fire metadata loaded event
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(callbackUnregister, times(0)).onFailed(any(Throwable.class));
+        verify(callbackConfigUnregister, times(0)).onFailed(any(Throwable.class));
+        verify(callback, times(1)).onFailed(any(Throwable.class));
+        verify(callbackConfig, times(1)).onFailed(any(Throwable.class));
+    }
+
+    @Test
+    public void testInitCallback_addedToConfigAndInstance_callsSuccess() {
+        final EmojiCompat.InitCallback initCallback1 = mock(EmojiCompat.InitCallback.class);
+        final EmojiCompat.InitCallback initCallback2 = mock(EmojiCompat.InitCallback.class);
+
+        final EmojiCompat.Config config = TestConfigBuilder.config()
+                .registerInitCallback(initCallback1);
+        final EmojiCompat emojiCompat = EmojiCompat.reset(config);
+        emojiCompat.registerInitCallback(initCallback2);
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(initCallback1, times(1)).onInitialized();
+        verify(initCallback2, times(1)).onInitialized();
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java b/emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java
new file mode 100644
index 0000000..58764a2
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.MetadataRepo.Node;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MetadataRepoTest {
+
+    MetadataRepo mMetadataRepo;
+
+    @Before
+    public void clearResourceIndex() {
+        mMetadataRepo = new MetadataRepo();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testPut_withNullMetadata() throws Exception {
+        mMetadataRepo.put(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPut_withEmptyKeys() throws Exception {
+        mMetadataRepo.put(new TestEmojiMetadata(new int[0]));
+    }
+
+    @Test
+    public void testPut_withSingleCodePointMapping() throws Exception {
+        final int[] codePoint = new int[]{1};
+        final TestEmojiMetadata metadata = new TestEmojiMetadata(codePoint);
+        mMetadataRepo.put(metadata);
+        assertSame(metadata, getNode(codePoint));
+    }
+
+    @Test
+    public void testPut_withMultiCodePointsMapping() throws Exception {
+        final int[] codePoint = new int[]{1, 2, 3, 4};
+        final TestEmojiMetadata metadata = new TestEmojiMetadata(codePoint);
+        mMetadataRepo.put(metadata);
+        assertSame(metadata, getNode(codePoint));
+
+        assertEquals(null, getNode(new int[]{1}));
+        assertEquals(null, getNode(new int[]{1, 2}));
+        assertEquals(null, getNode(new int[]{1, 2, 3}));
+        assertEquals(null, getNode(new int[]{1, 2, 3, 5}));
+    }
+
+    @Test
+    public void testPut_sequentialCodePoints() throws Exception {
+        final int[] codePoint1 = new int[]{1, 2, 3, 4};
+        final EmojiMetadata metadata1 = new TestEmojiMetadata(codePoint1);
+
+        final int[] codePoint2 = new int[]{1, 2, 3};
+        final EmojiMetadata metadata2 = new TestEmojiMetadata(codePoint2);
+
+        final int[] codePoint3 = new int[]{1, 2};
+        final EmojiMetadata metadata3 = new TestEmojiMetadata(codePoint3);
+
+        mMetadataRepo.put(metadata1);
+        mMetadataRepo.put(metadata2);
+        mMetadataRepo.put(metadata3);
+
+        assertSame(metadata1, getNode(codePoint1));
+        assertSame(metadata2, getNode(codePoint2));
+        assertSame(metadata3, getNode(codePoint3));
+
+        assertEquals(null, getNode(new int[]{1}));
+        assertEquals(null, getNode(new int[]{1, 2, 3, 4, 5}));
+    }
+
+    final EmojiMetadata getNode(final int[] codepoints) {
+        return getNode(mMetadataRepo.getRootNode(), codepoints, 0);
+    }
+
+    final EmojiMetadata getNode(Node node, final int[] codepoints, int start) {
+        if (codepoints.length < start) return null;
+        if (codepoints.length == start) return node.getData();
+
+        final Node childNode = node.get(codepoints[start]);
+        if (childNode == null) return null;
+        return getNode(childNode, codepoints, start + 1);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java b/emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java
new file mode 100644
index 0000000..3dd29bc
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static android.support.text.emoji.util.Emoji.EMOJI_FLAG;
+import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.util.Emoji;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.view.inputmethod.InputConnection;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SoftDeleteTest {
+    private InputConnection mInputConnection;
+    private TestString mTestString;
+    private Editable mEditable;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mInputConnection = mock(InputConnection.class);
+        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmojiCount(1));
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+    }
+
+    @Test
+    public void testDelete_doesNotDelete_whenSelectionIsUndefined() {
+        // no selection is set on editable
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_doesNotDelete_whenThereIsSelectionLongerThanZero() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex(),
+                mTestString.emojiEndIndex() + 1);
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withNullEditable() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, null, 1, 0, false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withNullInputConnection() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(null, mEditable, 1, 0, false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withInvalidLength() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, -1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withInvalidAfterLength() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, -1,
+                false));
+
+        assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_backward() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        // backwards delete 1 character, it will delete the emoji
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_backward_inCodepoints() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        // backwards delete 1 character, it will delete the emoji
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                true));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_forward() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+
+        // forward delete 1 character, it will dele the emoji.
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, 1,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_forward_inCodepoints() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+
+        // forward delete 1 codepoint, it will delete the emoji.
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, 1,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_backward_doesNotDeleteWhenSelectionAtCharSequenceStart() {
+        // make sure selection at 0 does not do something weird for backward delete
+        Selection.setSelection(mEditable, 0);
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 1, 0,
+                false));
+
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_forward_doesNotDeleteWhenSelectionAtCharSequenceEnd() {
+        // make sure selection at end does not do something weird for forward delete
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 0, 1,
+                false));
+
+        assertThat(mEditable, hasEmoji());
+        assertEquals(mTestString.toString(), mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCharacters() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        // delete 4 characters forward, 4 character backwards
+        assertTrue(
+                EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 4, 4, false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("af", mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCodepoints() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        // delete 3 codepoints forward, 3 codepoints backwards
+        assertTrue(
+                EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 3, 3, true));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("af", mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCharacters_withDeleteLengthLongerThanString() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 100, 100,
+                false));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("", mEditable.toString());
+    }
+
+    @Test
+    public void testDelete_withMultipleCodepoints_withDeleteLengthLongerThanString() {
+        // prepare string as abc[emoji]def
+        mTestString = new TestString(EMOJI_FLAG);
+        mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
+        EmojiCompat.get().process(mEditable);
+
+        // set the selection in the middle of emoji
+        Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
+
+        assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable, 100, 100,
+                true));
+
+        assertThat(mEditable, not(hasEmoji()));
+        assertEquals("", mEditable.toString());
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestActivity.java b/emoji/core/tests/java/android/support/text/emoji/TestActivity.java
new file mode 100644
index 0000000..06dfcf9
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/TestActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.text.emoji.test.R;
+
+public class TestActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_default);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java b/emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java
new file mode 100644
index 0000000..bc3eec9
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import static org.junit.Assert.fail;
+
+import android.content.res.AssetManager;
+import android.support.annotation.GuardedBy;
+import android.support.test.InstrumentationRegistry;
+
+import java.util.concurrent.CountDownLatch;
+
+public class TestConfigBuilder {
+    public static EmojiCompat.Config config() {
+        return new TestConfig().setReplaceAll(true);
+    }
+
+    public static class TestConfig extends EmojiCompat.Config {
+        TestConfig() {
+            super(new TestEmojiDataLoader());
+        }
+
+        TestConfig(final EmojiCompat.MetadataLoader metadataLoader) {
+            super(metadataLoader);
+        }
+    }
+
+    public static class WaitingDataLoader implements EmojiCompat.MetadataLoader {
+        private final CountDownLatch mLoaderLatch;
+        private final CountDownLatch mTestLatch;
+        private final boolean mSuccess;
+
+        public WaitingDataLoader(boolean success) {
+            mLoaderLatch = new CountDownLatch(1);
+            mTestLatch = new CountDownLatch(1);
+            mSuccess = success;
+        }
+
+        public WaitingDataLoader() {
+            this(true);
+        }
+
+        public CountDownLatch getLoaderLatch() {
+            return mLoaderLatch;
+        }
+
+        public CountDownLatch getTestLatch() {
+            return mTestLatch;
+        }
+
+        @Override
+        public void load(final EmojiCompat.LoaderCallback loaderCallback) {
+            new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mLoaderLatch.await();
+                        if (mSuccess) {
+                            loaderCallback.onLoaded(new MetadataRepo());
+                        } else {
+                            loaderCallback.onFailed(null);
+                        }
+
+                        mTestLatch.countDown();
+                    } catch (Throwable e) {
+                        fail();
+                    }
+                }
+            }).start();
+        }
+    }
+
+    public static class TestEmojiDataLoader implements EmojiCompat.MetadataLoader {
+        static final Object sMetadataRepoLock = new Object();
+        // keep a static instance to in order not to slow down the tests
+        @GuardedBy("sMetadataRepoLock")
+        static volatile MetadataRepo sMetadataRepo;
+
+        TestEmojiDataLoader() {
+        }
+
+        @Override
+        public void load(EmojiCompat.LoaderCallback loaderCallback) {
+            if (sMetadataRepo == null) {
+                synchronized (sMetadataRepoLock) {
+                    if (sMetadataRepo == null) {
+                        try {
+                            final AssetManager assetManager =
+                                    InstrumentationRegistry.getContext().getAssets();
+                            sMetadataRepo = MetadataRepo.create(assetManager,
+                                    "NotoColorEmojiCompat.ttf");
+                        } catch (Throwable e) {
+                            loaderCallback.onFailed(e);
+                            throw new RuntimeException(e);
+                        }
+                    }
+                }
+            }
+
+            loaderCallback.onLoaded(sMetadataRepo);
+        }
+    }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java b/emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java
new file mode 100644
index 0000000..68337ba
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+public class TestEmojiMetadata extends EmojiMetadata {
+    private final int[] mCodePoints;
+    private int mId;
+
+    TestEmojiMetadata(int[] codePoints, int id) {
+        super(null, 0);
+        mCodePoints = codePoints;
+        mId = id;
+    }
+
+    TestEmojiMetadata(int[] codePoints) {
+        this(codePoints, 0);
+    }
+
+    @Override
+    public int getId() {
+        return mId;
+    }
+
+    @Override
+    public int getCodepointAt(int index) {
+        return mCodePoints[index];
+    }
+
+    @Override
+    public int getCodepointsLength() {
+        return mCodePoints.length;
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java b/emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java
new file mode 100644
index 0000000..affda10
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.text.emoji;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.TestConfigBuilder.TestConfig;
+import android.support.text.emoji.TestConfigBuilder.WaitingDataLoader;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UninitializedStateTest {
+
+    private WaitingDataLoader mWaitingDataLoader;
+
+    @Before
+    public void setup() {
+        mWaitingDataLoader = new WaitingDataLoader(true);
+        final EmojiCompat.Config config = new TestConfig(mWaitingDataLoader);
+        EmojiCompat.reset(config);
+    }
+
+    @After
+    public void after() {
+        mWaitingDataLoader.getLoaderLatch().countDown();
+        mWaitingDataLoader.getTestLatch().countDown();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testHasEmojiGlyph() throws Exception {
+        EmojiCompat.get().hasEmojiGlyph("anystring");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testHasEmojiGlyph_withMetadataVersion() throws Exception {
+        EmojiCompat.get().hasEmojiGlyph("anystring", 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testProcess() throws Exception {
+        EmojiCompat.get().process("anystring");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testProcess_withStartEnd() throws Exception {
+        EmojiCompat.get().process("anystring", 1, 2);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/Emoji.java b/emoji/core/tests/java/android/support/text/emoji/util/Emoji.java
new file mode 100644
index 0000000..d38e580
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/Emoji.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.util;
+
+import android.support.annotation.NonNull;
+
+public class Emoji {
+
+    public static final int CHAR_KEYCAP = 0x20E3;
+    public static final int CHAR_DIGIT = 0x0039;
+    public static final int CHAR_ZWJ = 0x200D;
+    public static final int CHAR_VS_EMOJI = 0xFE0f;
+    public static final int CHAR_VS_TEXT = 0xFE0E;
+    public static final int CHAR_FITZPATRICK = 0x1F3FE;
+    public static final int CHAR_FITZPATRICK_TYPE_1 = 0x1F3fB;
+    public static final int CHAR_DEFAULT_TEXT_STYLE = 0x26F9;
+    public static final int CHAR_DEFAULT_EMOJI_STYLE = 0x1f3A2;
+    public static final int CHAR_FEMALE_SIGN = 0x2640;
+    public static final int CHAR_MAN = 0x1F468;
+    public static final int CHAR_HEART = 0x2764;
+    public static final int CHAR_KISS = 0x1F48B;
+    public static final int CHAR_REGIONAL_SYMBOL = 0x1F1E8;
+    public static final int CHAR_ASTERISK = 0x002A;
+
+    public static final EmojiMapping EMOJI_SINGLE_CODEPOINT = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_EMOJI_STYLE}, 0xF01B4);
+
+    public static final EmojiMapping EMOJI_WITH_ZWJ = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_ZWJ, CHAR_HEART, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_KISS, CHAR_ZWJ,
+                    CHAR_MAN}, 0xF051F);
+
+    public static final EmojiMapping EMOJI_GENDER = new EmojiMapping(new int[]{
+            CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping EMOJI_FLAG = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL, CHAR_REGIONAL_SYMBOL}, 0xF03A0);
+
+    public static final EmojiMapping EMOJI_GENDER_WITHOUT_VS = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping DEFAULT_TEXT_STYLE = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI}, 0xF04C6);
+
+    public static final EmojiMapping EMOJI_REGIONAL_SYMBOL = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL}, 0xF0025);
+
+    public static final EmojiMapping EMOJI_UNKNOWN_FLAG = new EmojiMapping(
+            new int[]{0x1F1FA, 0x1F1F3}, 0xF0599);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI}, 0xF0340);
+
+    public static final EmojiMapping EMOJI_DIGIT_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_ASTERISK_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_ASTERISK, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF051D);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK}, 0xF0603);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_TYPE_ONE = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_WITH_VS = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_VS_EMOJI, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static class EmojiMapping {
+        private final int[] mCodepoints;
+        private final int mId;
+
+        private EmojiMapping(@NonNull final int[] codepoints, final int id) {
+            mCodepoints = codepoints;
+            mId = id;
+        }
+
+        public final int[] codepoints() {
+            return mCodepoints;
+        }
+
+        public final int id() {
+            return mId;
+        }
+
+        public final int charCount() {
+            int count = 0;
+            for (int i = 0; i < mCodepoints.length; i++) {
+                count += Character.charCount(mCodepoints[i]);
+            }
+            return count;
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java b/emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java
new file mode 100644
index 0000000..20f656d
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.util;
+
+import static org.mockito.Matchers.argThat;
+
+import android.support.text.emoji.EmojiSpan;
+import android.text.Spanned;
+import android.text.TextUtils;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Utility class that includes matchers specific to emojis and EmojiSpans.
+ */
+public class EmojiMatcher {
+
+    public static Matcher<CharSequence> hasEmojiAt(final int id, final int start,
+            final int end) {
+        return new EmojiResourceMatcher(id, start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmojiAt(final Emoji.EmojiMapping emojiMapping,
+            final int start, final int end) {
+        return new EmojiResourceMatcher(emojiMapping.id(), start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmojiAt(final int start, final int end) {
+        return new EmojiResourceMatcher(-1, start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmoji(final int id) {
+        return new EmojiResourceMatcher(id, -1, -1);
+    }
+
+    public static Matcher<CharSequence> hasEmoji(final Emoji.EmojiMapping emojiMapping) {
+        return new EmojiResourceMatcher(emojiMapping.id(), -1, -1);
+    }
+
+    public static Matcher<CharSequence> hasEmoji() {
+        return new EmojiSpanMatcher();
+    }
+
+    public static Matcher<CharSequence> hasEmojiCount(final int count) {
+        return new EmojiCountMatcher(count);
+    }
+
+    public static <T extends CharSequence> T sameCharSequence(final T expected) {
+        return argThat(new BaseMatcher<T>() {
+            @Override
+            public boolean matches(Object o) {
+                if (o instanceof CharSequence && expected.getClass() == o.getClass()) {
+                    return TextUtils.equals(expected, (CharSequence) o);
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("doesn't match " + expected);
+            }
+        });
+    }
+
+    private static class EmojiSpanMatcher extends TypeSafeMatcher<CharSequence> {
+
+        private EmojiSpan[] mSpans;
+
+        EmojiSpanMatcher() {
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have EmojiSpans");
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            mismatchDescription.appendText(" has no EmojiSpans");
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) return false;
+            if (!(charSequence instanceof Spanned)) return false;
+            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
+            return mSpans.length != 0;
+        }
+    }
+
+    private static class EmojiCountMatcher extends TypeSafeMatcher<CharSequence> {
+
+        private final int mCount;
+        private EmojiSpan[] mSpans;
+
+        EmojiCountMatcher(final int count) {
+            mCount = count;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have ").appendValue(mCount).appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            mismatchDescription.appendText(" has ");
+            if (mSpans == null) {
+                mismatchDescription.appendValue("no");
+            } else {
+                mismatchDescription.appendValue(mSpans.length);
+            }
+
+            mismatchDescription.appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) return false;
+            if (!(charSequence instanceof Spanned)) return false;
+            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
+            return mSpans.length == mCount;
+        }
+    }
+
+    private static class EmojiResourceMatcher extends TypeSafeMatcher<CharSequence> {
+        private static final int ERR_NONE = 0;
+        private static final int ERR_SPANNABLE_NULL = 1;
+        private static final int ERR_NO_SPANS = 2;
+        private static final int ERR_WRONG_INDEX = 3;
+        private final int mResId;
+        private final int mStart;
+        private final int mEnd;
+        private int mError = ERR_NONE;
+        private int mActualStart = -1;
+        private int mActualEnd = -1;
+
+        EmojiResourceMatcher(int resId, int start, int end) {
+            mResId = resId;
+            mStart = start;
+            mEnd = end;
+        }
+
+        @Override
+        public void describeTo(final Description description) {
+            if (mResId == -1) {
+                description.appendText("should have EmojiSpan at ")
+                        .appendValue("[" + mStart + "," + mEnd + "]");
+            } else if (mStart == -1 && mEnd == -1) {
+                description.appendText("should have EmojiSpan with resource id ")
+                        .appendValue(Integer.toHexString(mResId));
+            } else {
+                description.appendText("should have EmojiSpan with resource id ")
+                        .appendValue(Integer.toHexString(mResId))
+                        .appendText(" at ")
+                        .appendValue("[" + mStart + "," + mEnd + "]");
+            }
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            int offset = 0;
+            mismatchDescription.appendText("[");
+            while (offset < charSequence.length()) {
+                int codepoint = Character.codePointAt(charSequence, offset);
+                mismatchDescription.appendText(Integer.toHexString(codepoint));
+                offset += Character.charCount(codepoint);
+                if (offset < charSequence.length()) {
+                    mismatchDescription.appendText(",");
+                }
+            }
+            mismatchDescription.appendText("]");
+
+            switch (mError) {
+                case ERR_NO_SPANS:
+                    mismatchDescription.appendText(" had no spans");
+                    break;
+                case ERR_SPANNABLE_NULL:
+                    mismatchDescription.appendText(" was null");
+                    break;
+                case ERR_WRONG_INDEX:
+                    mismatchDescription.appendText(" had Emoji at ")
+                            .appendValue("[" + mActualStart + "," + mActualEnd + "]");
+                    break;
+                default:
+                    mismatchDescription.appendText(" does not have an EmojiSpan with given "
+                            + "resource id ");
+            }
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) {
+                mError = ERR_SPANNABLE_NULL;
+                return false;
+            }
+
+            if (!(charSequence instanceof Spanned)) {
+                mError = ERR_NO_SPANS;
+                return false;
+            }
+
+            Spanned spanned = (Spanned) charSequence;
+            final EmojiSpan[] spans = spanned.getSpans(0, charSequence.length(), EmojiSpan.class);
+
+            if (spans.length == 0) {
+                mError = ERR_NO_SPANS;
+                return false;
+            }
+
+            if (mStart == -1 && mEnd == -1) {
+                for (int index = 0; index < spans.length; index++) {
+                    if (mResId == spans[index].getId()) {
+                        return true;
+                    }
+                }
+                return false;
+            } else {
+                for (int index = 0; index < spans.length; index++) {
+                    if (mResId == -1 || mResId == spans[index].getId()) {
+                        mActualStart = spanned.getSpanStart(spans[index]);
+                        mActualEnd = spanned.getSpanEnd(spans[index]);
+                        if (mActualStart == mStart && mActualEnd == mEnd) {
+                            return true;
+                        }
+                    }
+                }
+
+                if (mActualStart != -1 && mActualEnd != -1) {
+                    mError = ERR_WRONG_INDEX;
+                }
+
+                return false;
+            }
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java b/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
new file mode 100644
index 0000000..4764455
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.util;
+
+import android.view.KeyEvent;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * Utility class for KeyEvents
+ */
+public class KeyboardUtil {
+    private static final int ALT = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON;
+    private static final int CTRL = KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON;
+    private static final int SHIFT = KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON;
+    private static final int FN = KeyEvent.META_FUNCTION_ON;
+
+    public static KeyEvent zero() {
+        return keyEvent(KeyEvent.KEYCODE_0);
+    }
+
+    public static KeyEvent del() {
+        return keyEvent(KeyEvent.KEYCODE_DEL);
+    }
+
+    public static KeyEvent altDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, ALT);
+    }
+
+    public static KeyEvent ctrlDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, CTRL);
+    }
+
+    public static KeyEvent shiftDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, SHIFT);
+    }
+
+    public static KeyEvent fnDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, FN);
+    }
+
+    public static KeyEvent forwardDel() {
+        return keyEvent(KeyEvent.KEYCODE_FORWARD_DEL);
+    }
+
+    public static KeyEvent keyEvent(int keycode, int metaState) {
+        final long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0, metaState);
+    }
+
+    public static KeyEvent keyEvent(int keycode) {
+        final long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0);
+    }
+
+    public static void setComposingTextInBatch(InputConnection input, CharSequence text) {
+        input.beginBatchEdit();
+        input.setComposingText(text, 1);
+        input.endBatchEdit();
+    }
+
+    public static void deleteSurrondingText(InputConnection input, int before, int after) {
+        input.beginBatchEdit();
+        input.deleteSurroundingText(before, after);
+        input.endBatchEdit();
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/TestString.java b/emoji/core/tests/java/android/support/text/emoji/util/TestString.java
new file mode 100644
index 0000000..8f2331e
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/util/TestString.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class used to create strings with emojis during tests.
+ */
+public class TestString {
+
+    private static final List<Integer> EMPTY_LIST = new ArrayList<>();
+
+    private static final String EXTRA = "ab";
+    private final List<Integer> mCodePoints;
+    private String mString;
+    private final String mValue;
+    private boolean mHasSuffix;
+    private boolean mHasPrefix;
+
+    public TestString(int... codePoints) {
+        if (codePoints.length == 0) {
+            mCodePoints = EMPTY_LIST;
+        } else {
+            mCodePoints = new ArrayList<>();
+            append(codePoints);
+        }
+        mValue = null;
+    }
+
+    public TestString(Emoji.EmojiMapping emojiMapping) {
+        this(emojiMapping.codepoints());
+    }
+
+    public TestString(String string) {
+        mCodePoints = EMPTY_LIST;
+        mValue = string;
+    }
+
+    public TestString append(int... codePoints) {
+        for (int i = 0; i < codePoints.length; i++) {
+            mCodePoints.add(codePoints[i]);
+        }
+        return this;
+    }
+
+    public TestString append(Emoji.EmojiMapping emojiMapping) {
+        return append(emojiMapping.codepoints());
+    }
+
+    public TestString withSuffix() {
+        mHasSuffix = true;
+        return this;
+    }
+
+    public TestString withPrefix() {
+        mHasPrefix = true;
+        return this;
+    }
+
+    @SuppressWarnings("ForLoopReplaceableByForEach")
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        if (mHasPrefix) {
+            builder.append(EXTRA);
+        }
+
+        for (int index = 0; index < mCodePoints.size(); index++) {
+            builder.append(Character.toChars(mCodePoints.get(index)));
+        }
+
+        if (mValue != null) {
+            builder.append(mValue);
+        }
+
+        if (mHasSuffix) {
+            builder.append(EXTRA);
+        }
+        mString = builder.toString();
+        return mString;
+    }
+
+    public int emojiStartIndex() {
+        if (mHasPrefix) return EXTRA.length();
+        return 0;
+    }
+
+    public int emojiEndIndex() {
+        if (mHasSuffix) return mString.lastIndexOf(EXTRA);
+        return mString.length();
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java
new file mode 100644
index 0000000..f75e956
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiMetadata;
+import android.support.text.emoji.EmojiSpan;
+import android.support.text.emoji.TypefaceEmojiSpan;
+import android.text.Editable;
+import android.text.SpannableString;
+import android.text.Spanned;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiEditableFactoryTest {
+
+    @Test
+    public void testGetInstance() {
+        final Editable.Factory instance = EmojiEditableFactory.getInstance();
+        assertNotNull(instance);
+
+        final Editable.Factory instance2 = EmojiEditableFactory.getInstance();
+        assertSame(instance, instance2);
+    }
+
+    @Test
+    public void testNewEditable_returnsEditable() {
+        final Editable editable = EmojiEditableFactory.getInstance().newEditable("abc");
+        assertNotNull(editable);
+        assertThat(editable, instanceOf(Editable.class));
+    }
+
+    @Test
+    public void testNewEditable_preservesCharSequenceData() {
+        final String string = "abc";
+        final SpannableString str = new SpannableString(string);
+        final EmojiMetadata metadata = mock(EmojiMetadata.class);
+        final EmojiSpan span = new TypefaceEmojiSpan(metadata);
+        str.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        final Editable editable = EmojiEditableFactory.getInstance().newEditable(str);
+        assertNotNull(editable);
+        assertEquals(string, editable.toString());
+        final EmojiSpan[] spans = editable.getSpans(0, 1, EmojiSpan.class);
+        assertThat(spans, arrayWithSize(1));
+        assertSame(spans[0], span);
+    }
+
+    @Test
+    public void testNewEditable_returnsEmojiSpannableIfWatcherClassExists() {
+        Class clazz = null;
+        try {
+            String className = "android.text.DynamicLayout$ChangeWatcher";
+            clazz = getClass().getClassLoader().loadClass(className);
+        } catch (Throwable t) {
+            // ignore
+        }
+
+        if (clazz == null) {
+            final Editable editable = EmojiEditableFactory.getInstance().newEditable("");
+            assertThat(editable, instanceOf(Editable.class));
+        } else {
+            final Editable editable = EmojiEditableFactory.getInstance().newEditable("");
+            assertThat(editable, instanceOf(SpannableBuilder.class));
+        }
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java
new file mode 100644
index 0000000..4202c38
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.TestConfigBuilder;
+import android.support.text.emoji.util.Emoji;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.view.inputmethod.EditorInfo;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiInputConnectionTest {
+
+    private android.view.inputmethod.InputConnection mInputConnection;
+    private TestString mTestString;
+    private Editable mEditable;
+    private EmojiInputConnection mEmojiEmojiInputConnection;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        mInputConnection = mock(android.view.inputmethod.InputConnection.class);
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final TextView textView = spy(new TextView(context));
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmoji());
+
+        doReturn(mEditable).when(textView).getEditableText();
+        when(mInputConnection.deleteSurroundingText(anyInt(), anyInt())).thenReturn(false);
+        setupDeleteSurroundingText();
+
+        mEmojiEmojiInputConnection = new EmojiInputConnection(textView, mInputConnection,
+                new EditorInfo());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    private void setupDeleteSurroundingText() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            when(mInputConnection.deleteSurroundingTextInCodePoints(anyInt(), anyInt())).thenReturn(
+                    false);
+        }
+    }
+
+    @Test
+    public void testDeleteSurroundingText_doesNotDelete() {
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingText(1, 0);
+    }
+
+    @Test
+    public void testDeleteSurroundingText_deletesEmojiBackward() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt());
+    }
+
+    @Test
+    public void testDeleteSurroundingText_doesNotDeleteEmojiIfSelectionAtStartIndex() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingText(1, 0);
+    }
+
+    @Test
+    public void testDeleteSurroundingText_deletesEmojiForward() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(0, 1));
+        verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_doesNotDelete() {
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0);
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_deletesEmojiBackward() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
+        verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_deletesEmojiForward() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(0, 1));
+        verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt());
+    }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+    @Test
+    public void testDeleteSurroundingTextInCodePoints_doesNotDeleteEmojiIfSelectionAtStartIndex() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java
new file mode 100644
index 0000000..2d30657
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.text.emoji.util.EmojiMatcher.sameCharSequence;
+
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertSame;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat;
+import android.text.Spannable;
+import android.text.SpannableString;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiInputFilterTest {
+
+    private android.widget.TextView mTextView;
+    private EmojiInputFilter mInputFilter;
+    private EmojiCompat mEmojiCompat;
+
+    @Before
+    public void setup() {
+        mTextView = mock(android.widget.TextView.class);
+        mEmojiCompat = mock(EmojiCompat.class);
+        EmojiCompat.reset(mEmojiCompat);
+        when(mEmojiCompat.isInitialized()).thenReturn(true);
+        mInputFilter = new EmojiInputFilter(mTextView);
+    }
+
+    @Test
+    public void testFilter_withNullSource() {
+        assertNull(mInputFilter.filter(null, 0, 1, null, 0, 1));
+        verify(mEmojiCompat, never()).process(any(CharSequence.class));
+        verify(mEmojiCompat, never()).process(any(CharSequence.class), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testFilter_withString() {
+        final String testString = "abc";
+        when(mEmojiCompat.process(any(Spannable.class), anyInt(), anyInt()))
+                .thenReturn(new SpannableString(testString));
+        final CharSequence result = mInputFilter.filter(testString, 0, 1, null, 0, 1);
+
+        assertNotNull(result);
+        assertTrue(result instanceof Spannable);
+        verify(mEmojiCompat, times(1)).process(sameCharSequence("a"), eq(0), eq(1));
+    }
+
+    @Test
+    public void testFilter_withSpannable() {
+        final Spannable testString = new SpannableString("abc");
+        when(mEmojiCompat.process(any(Spannable.class), anyInt(), anyInt())).thenReturn(testString);
+
+        final CharSequence result = mInputFilter.filter(testString, 0, 1, null, 0, 1);
+
+        assertNotNull(result);
+        assertSame(result, testString);
+        verify(mEmojiCompat, times(1)).process(sameCharSequence(testString.subSequence(0, 1)),
+                eq(0), eq(1));
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java
new file mode 100644
index 0000000..11bd9c1
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.KeyboardUtil.altDel;
+import static android.support.text.emoji.util.KeyboardUtil.ctrlDel;
+import static android.support.text.emoji.util.KeyboardUtil.del;
+import static android.support.text.emoji.util.KeyboardUtil.fnDel;
+import static android.support.text.emoji.util.KeyboardUtil.forwardDel;
+import static android.support.text.emoji.util.KeyboardUtil.shiftDel;
+import static android.support.text.emoji.util.KeyboardUtil.zero;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.TestConfigBuilder;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.method.KeyListener;
+import android.view.KeyEvent;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiKeyListenerTest {
+
+    private KeyListener mKeyListener;
+    private TestString mTestString;
+    private Editable mEditable;
+    private EmojiKeyListener mEmojiKeyListener;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mKeyListener = mock(KeyListener.class);
+        mTestString = new TestString(EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        mEmojiKeyListener = new EmojiKeyListener(mKeyListener);
+        EmojiCompat.get().process(mEditable);
+        assertThat(mEditable, hasEmoji());
+
+        when(mKeyListener.onKeyDown(any(View.class), any(Editable.class), anyInt(),
+                any(KeyEvent.class))).thenReturn(false);
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenKeyCodeIsNotDelOrForwardDel() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = zero();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withOtherModifiers() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = fnDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withAltModifier() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = altDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withCtrlModifier() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = ctrlDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withShiftModifier() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = shiftDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withSelection() {
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        final KeyEvent event = del();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_withoutEmojiSpans() {
+        Editable editable = new SpannableStringBuilder("abc");
+        Selection.setSelection(editable, 1);
+        final KeyEvent event = del();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, editable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(editable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotDelete_whenNoSpansBefore() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = del();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_deletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = del();
+        assertTrue(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verifyNoMoreInteractions(mKeyListener);
+    }
+
+    @Test
+    public void testOnKeyDown_doesNotForwardDeleteEmoji_withNoSpansAfter() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        final KeyEvent event = forwardDel();
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+
+    @Test
+    public void testOnKeyDown_forwardDeletesEmoji() {
+        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
+        final KeyEvent event = forwardDel();
+        assertTrue(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verifyNoMoreInteractions(mKeyListener);
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java
new file mode 100644
index 0000000..2359b3b
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2017 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.text.emoji.widget;
+
+import static junit.framework.Assert.assertSame;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.withSettings;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiSpan;
+import android.text.Editable;
+import android.text.SpanWatcher;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.TextWatcher;
+import android.text.style.QuoteSpan;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableBuilderTest {
+
+    private TextWatcher mWatcher;
+    private Class mClass;
+
+    @Before
+    public void setup() {
+        mWatcher = mock(TextWatcher.class, withSettings().extraInterfaces(SpanWatcher.class));
+        mClass = mWatcher.getClass();
+    }
+
+    @Test
+    public void testConstructor() {
+        new SpannableBuilder(mClass);
+
+        new SpannableBuilder(mClass, "abc");
+
+        new SpannableBuilder(mClass, "abc", 0, 3);
+
+        // test spannable copying? do I need it?
+    }
+
+    @Test
+    public void testSubSequence() {
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abc");
+        final QuoteSpan span1 = mock(QuoteSpan.class);
+        final QuoteSpan span2 = mock(QuoteSpan.class);
+        spannable.setSpan(span1, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        spannable.setSpan(span2, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        final CharSequence subsequence = spannable.subSequence(0, 1);
+        assertNotNull(subsequence);
+        assertThat(subsequence, instanceOf(SpannableBuilder.class));
+
+        final QuoteSpan[] spans = spannable.getSpans(0, 1, QuoteSpan.class);
+        assertThat(spans, arrayWithSize(1));
+        assertSame(spans[0], span1);
+    }
+
+    @Test
+    public void testSetAndGetSpan() {
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abcde");
+        spannable.setSpan(mWatcher, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+        // getSpans should return the span
+        Object[] spans = spannable.getSpans(0, spannable.length(), mClass);
+        assertNotNull(spans);
+        assertThat(spans, arrayWithSize(1));
+        assertSame(mWatcher, spans[0]);
+
+        // span attributes should be correct
+        assertEquals(1, spannable.getSpanStart(mWatcher));
+        assertEquals(2, spannable.getSpanEnd(mWatcher));
+        assertEquals(Spanned.SPAN_INCLUSIVE_INCLUSIVE, spannable.getSpanFlags(mWatcher));
+
+        // should remove the span
+        spannable.removeSpan(mWatcher);
+        spans = spannable.getSpans(0, spannable.length(), QuoteSpan.class);
+        assertNotNull(spans);
+        assertThat(spans, arrayWithSize(0));
+    }
+
+    @Test
+    public void testNextSpanTransition() {
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abcde");
+        spannable.setSpan(mWatcher, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        final int start = spannable.nextSpanTransition(0, spannable.length(), mClass);
+        Assert.assertEquals(1, start);
+    }
+
+    @Test
+    public void testBlocksSpanCallbacks_forEmojiSpans() {
+        final EmojiSpan span = mock(EmojiSpan.class);
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
+        spannable.setSpan(mWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        reset(mWatcher);
+
+        spannable.delete(0, 3);
+
+        // verify that characters are deleted
+        assertEquals("456", spannable.toString());
+        // verify EmojiSpan is deleted
+        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);
+        assertThat(spans, arrayWithSize(0));
+
+        // verify the call to span callbacks are blocked
+        verify((SpanWatcher) mWatcher, never()).onSpanRemoved(any(Spannable.class),
+                same(span), anyInt(), anyInt());
+        verify((SpanWatcher) mWatcher, never()).onSpanAdded(any(Spannable.class),
+                same(span), anyInt(), anyInt());
+        verify((SpanWatcher) mWatcher, never()).onSpanChanged(any(Spannable.class),
+                same(span), anyInt(), anyInt(), anyInt(), anyInt());
+
+        // verify the call to TextWatcher callbacks are called
+        verify(mWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(),
+                anyInt(), anyInt());
+        verify(mWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
+    }
+
+    @Test
+    public void testDoesNotBlockSpanCallbacks_forNonEmojiSpans() {
+        final QuoteSpan span = mock(QuoteSpan.class);
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
+        spannable.setSpan(mWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        reset(mWatcher);
+
+        spannable.delete(0, 3);
+
+        // verify that characters are deleted
+        assertEquals("456", spannable.toString());
+        // verify QuoteSpan is deleted
+        QuoteSpan[] spans = spannable.getSpans(0, spannable.length(), QuoteSpan.class);
+        assertThat(spans, arrayWithSize(0));
+
+        // verify the call to span callbacks are not blocked
+        verify((SpanWatcher) mWatcher, times(1)).onSpanRemoved(any(Spannable.class),
+                anyObject(), anyInt(), anyInt());
+
+        // verify the call to TextWatcher callbacks are called
+        verify(mWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(mWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
+    }
+
+    @Test
+    public void testDoesNotBlockSpanCallbacksForOtherWatchers() {
+        final TextWatcher textWatcher = mock(TextWatcher.class);
+        final SpanWatcher spanWatcher = mock(SpanWatcher.class);
+
+        final EmojiSpan span = mock(EmojiSpan.class);
+        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
+        spannable.setSpan(textWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(spanWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        reset(textWatcher);
+
+        spannable.delete(0, 3);
+
+        // verify that characters are deleted
+        assertEquals("456", spannable.toString());
+        // verify EmojiSpan is deleted
+        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);
+        assertThat(spans, arrayWithSize(0));
+
+        // verify the call to span callbacks are blocked
+        verify(spanWatcher, times(1)).onSpanRemoved(any(Spannable.class), same(span),
+                anyInt(), anyInt());
+
+        // verify the call to TextWatcher callbacks are called
+        verify(textWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(),
+                anyInt(), anyInt());
+        verify(textWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
+                anyInt());
+        verify(textWatcher, times(1)).afterTextChanged(any(Editable.class));
+    }
+}
diff --git a/emoji/core/tests/res/layout/activity_default.xml b/emoji/core/tests/res/layout/activity_default.xml
new file mode 100644
index 0000000..b9a09ca
--- /dev/null
+++ b/emoji/core/tests/res/layout/activity_default.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/root"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <android.support.text.emoji.widget.EmojiEditText
+        android:id="@+id/editText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+</LinearLayout>
diff --git a/emoji/core/tests/res/raw/all_emojis.txt b/emoji/core/tests/res/raw/all_emojis.txt
new file mode 100644
index 0000000..0d9ea3c
--- /dev/null
+++ b/emoji/core/tests/res/raw/all_emojis.txt
@@ -0,0 +1,2404 @@
+0x1f004
+0x1f004 0xfe0f
+0x1f0cf
+0x1f170 0xfe0f
+0x1f171 0xfe0f
+0x1f17e 0xfe0f
+0x1f17f 0xfe0f
+0x1f18e
+0x1f191
+0x1f192
+0x1f193
+0x1f194
+0x1f195
+0x1f196
+0x1f197
+0x1f198
+0x1f199
+0x1f19a
+0x1f1e6
+0x1f1e6 0x1f1e8
+0x1f1e6 0x1f1e9
+0x1f1e6 0x1f1ea
+0x1f1e6 0x1f1eb
+0x1f1e6 0x1f1ec
+0x1f1e6 0x1f1ee
+0x1f1e6 0x1f1f1
+0x1f1e6 0x1f1f2
+0x1f1e6 0x1f1f4
+0x1f1e6 0x1f1f6
+0x1f1e6 0x1f1f7
+0x1f1e6 0x1f1f8
+0x1f1e6 0x1f1f9
+0x1f1e6 0x1f1fa
+0x1f1e6 0x1f1fc
+0x1f1e6 0x1f1fd
+0x1f1e6 0x1f1ff
+0x1f1e7
+0x1f1e7 0x1f1e6
+0x1f1e7 0x1f1e7
+0x1f1e7 0x1f1e9
+0x1f1e7 0x1f1ea
+0x1f1e7 0x1f1eb
+0x1f1e7 0x1f1ec
+0x1f1e7 0x1f1ed
+0x1f1e7 0x1f1ee
+0x1f1e7 0x1f1ef
+0x1f1e7 0x1f1f1
+0x1f1e7 0x1f1f2
+0x1f1e7 0x1f1f3
+0x1f1e7 0x1f1f4
+0x1f1e7 0x1f1f6
+0x1f1e7 0x1f1f7
+0x1f1e7 0x1f1f8
+0x1f1e7 0x1f1f9
+0x1f1e7 0x1f1fb
+0x1f1e7 0x1f1fc
+0x1f1e7 0x1f1fe
+0x1f1e7 0x1f1ff
+0x1f1e8
+0x1f1e8 0x1f1e6
+0x1f1e8 0x1f1e8
+0x1f1e8 0x1f1e9
+0x1f1e8 0x1f1eb
+0x1f1e8 0x1f1ec
+0x1f1e8 0x1f1ed
+0x1f1e8 0x1f1ee
+0x1f1e8 0x1f1f0
+0x1f1e8 0x1f1f1
+0x1f1e8 0x1f1f2
+0x1f1e8 0x1f1f3
+0x1f1e8 0x1f1f4
+0x1f1e8 0x1f1f5
+0x1f1e8 0x1f1f7
+0x1f1e8 0x1f1fa
+0x1f1e8 0x1f1fb
+0x1f1e8 0x1f1fc
+0x1f1e8 0x1f1fd
+0x1f1e8 0x1f1fe
+0x1f1e8 0x1f1ff
+0x1f1e9
+0x1f1e9 0x1f1ea
+0x1f1e9 0x1f1ec
+0x1f1e9 0x1f1ef
+0x1f1e9 0x1f1f0
+0x1f1e9 0x1f1f2
+0x1f1e9 0x1f1f4
+0x1f1e9 0x1f1ff
+0x1f1ea
+0x1f1ea 0x1f1e6
+0x1f1ea 0x1f1e8
+0x1f1ea 0x1f1ea
+0x1f1ea 0x1f1ec
+0x1f1ea 0x1f1ed
+0x1f1ea 0x1f1f7
+0x1f1ea 0x1f1f8
+0x1f1ea 0x1f1f9
+0x1f1ea 0x1f1fa
+0x1f1eb
+0x1f1eb 0x1f1ee
+0x1f1eb 0x1f1ef
+0x1f1eb 0x1f1f0
+0x1f1eb 0x1f1f2
+0x1f1eb 0x1f1f4
+0x1f1eb 0x1f1f7
+0x1f1ec
+0x1f1ec 0x1f1e6
+0x1f1ec 0x1f1e7
+0x1f1ec 0x1f1e9
+0x1f1ec 0x1f1ea
+0x1f1ec 0x1f1eb
+0x1f1ec 0x1f1ec
+0x1f1ec 0x1f1ed
+0x1f1ec 0x1f1ee
+0x1f1ec 0x1f1f1
+0x1f1ec 0x1f1f2
+0x1f1ec 0x1f1f3
+0x1f1ec 0x1f1f5
+0x1f1ec 0x1f1f6
+0x1f1ec 0x1f1f7
+0x1f1ec 0x1f1f8
+0x1f1ec 0x1f1f9
+0x1f1ec 0x1f1fa
+0x1f1ec 0x1f1fc
+0x1f1ec 0x1f1fe
+0x1f1ed
+0x1f1ed 0x1f1f0
+0x1f1ed 0x1f1f2
+0x1f1ed 0x1f1f3
+0x1f1ed 0x1f1f7
+0x1f1ed 0x1f1f9
+0x1f1ed 0x1f1fa
+0x1f1ee
+0x1f1ee 0x1f1e8
+0x1f1ee 0x1f1e9
+0x1f1ee 0x1f1ea
+0x1f1ee 0x1f1f1
+0x1f1ee 0x1f1f2
+0x1f1ee 0x1f1f3
+0x1f1ee 0x1f1f4
+0x1f1ee 0x1f1f6
+0x1f1ee 0x1f1f7
+0x1f1ee 0x1f1f8
+0x1f1ee 0x1f1f9
+0x1f1ef
+0x1f1ef 0x1f1ea
+0x1f1ef 0x1f1f2
+0x1f1ef 0x1f1f4
+0x1f1ef 0x1f1f5
+0x1f1f0
+0x1f1f0 0x1f1ea
+0x1f1f0 0x1f1ec
+0x1f1f0 0x1f1ed
+0x1f1f0 0x1f1ee
+0x1f1f0 0x1f1f2
+0x1f1f0 0x1f1f3
+0x1f1f0 0x1f1f5
+0x1f1f0 0x1f1f7
+0x1f1f0 0x1f1fc
+0x1f1f0 0x1f1fe
+0x1f1f0 0x1f1ff
+0x1f1f1
+0x1f1f1 0x1f1e6
+0x1f1f1 0x1f1e7
+0x1f1f1 0x1f1e8
+0x1f1f1 0x1f1ee
+0x1f1f1 0x1f1f0
+0x1f1f1 0x1f1f7
+0x1f1f1 0x1f1f8
+0x1f1f1 0x1f1f9
+0x1f1f1 0x1f1fa
+0x1f1f1 0x1f1fb
+0x1f1f1 0x1f1fe
+0x1f1f2
+0x1f1f2 0x1f1e6
+0x1f1f2 0x1f1e8
+0x1f1f2 0x1f1e9
+0x1f1f2 0x1f1ea
+0x1f1f2 0x1f1eb
+0x1f1f2 0x1f1ec
+0x1f1f2 0x1f1ed
+0x1f1f2 0x1f1f0
+0x1f1f2 0x1f1f1
+0x1f1f2 0x1f1f2
+0x1f1f2 0x1f1f3
+0x1f1f2 0x1f1f4
+0x1f1f2 0x1f1f5
+0x1f1f2 0x1f1f6
+0x1f1f2 0x1f1f7
+0x1f1f2 0x1f1f8
+0x1f1f2 0x1f1f9
+0x1f1f2 0x1f1fa
+0x1f1f2 0x1f1fb
+0x1f1f2 0x1f1fc
+0x1f1f2 0x1f1fd
+0x1f1f2 0x1f1fe
+0x1f1f2 0x1f1ff
+0x1f1f3
+0x1f1f3 0x1f1e6
+0x1f1f3 0x1f1e8
+0x1f1f3 0x1f1ea
+0x1f1f3 0x1f1eb
+0x1f1f3 0x1f1ec
+0x1f1f3 0x1f1ee
+0x1f1f3 0x1f1f1
+0x1f1f3 0x1f1f4
+0x1f1f3 0x1f1f5
+0x1f1f3 0x1f1f7
+0x1f1f3 0x1f1fa
+0x1f1f3 0x1f1ff
+0x1f1f4
+0x1f1f4 0x1f1f2
+0x1f1f5
+0x1f1f5 0x1f1e6
+0x1f1f5 0x1f1ea
+0x1f1f5 0x1f1eb
+0x1f1f5 0x1f1ec
+0x1f1f5 0x1f1ed
+0x1f1f5 0x1f1f0
+0x1f1f5 0x1f1f1
+0x1f1f5 0x1f1f2
+0x1f1f5 0x1f1f3
+0x1f1f5 0x1f1f7
+0x1f1f5 0x1f1f8
+0x1f1f5 0x1f1f9
+0x1f1f5 0x1f1fc
+0x1f1f5 0x1f1fe
+0x1f1f6
+0x1f1f6 0x1f1e6
+0x1f1f7
+0x1f1f7 0x1f1ea
+0x1f1f7 0x1f1f4
+0x1f1f7 0x1f1f8
+0x1f1f7 0x1f1fa
+0x1f1f7 0x1f1fc
+0x1f1f8
+0x1f1f8 0x1f1e6
+0x1f1f8 0x1f1e7
+0x1f1f8 0x1f1e8
+0x1f1f8 0x1f1e9
+0x1f1f8 0x1f1ea
+0x1f1f8 0x1f1ec
+0x1f1f8 0x1f1ed
+0x1f1f8 0x1f1ee
+0x1f1f8 0x1f1ef
+0x1f1f8 0x1f1f0
+0x1f1f8 0x1f1f1
+0x1f1f8 0x1f1f2
+0x1f1f8 0x1f1f3
+0x1f1f8 0x1f1f4
+0x1f1f8 0x1f1f7
+0x1f1f8 0x1f1f8
+0x1f1f8 0x1f1f9
+0x1f1f8 0x1f1fb
+0x1f1f8 0x1f1fd
+0x1f1f8 0x1f1fe
+0x1f1f8 0x1f1ff
+0x1f1f9
+0x1f1f9 0x1f1e6
+0x1f1f9 0x1f1e8
+0x1f1f9 0x1f1e9
+0x1f1f9 0x1f1eb
+0x1f1f9 0x1f1ec
+0x1f1f9 0x1f1ed
+0x1f1f9 0x1f1ef
+0x1f1f9 0x1f1f0
+0x1f1f9 0x1f1f1
+0x1f1f9 0x1f1f2
+0x1f1f9 0x1f1f3
+0x1f1f9 0x1f1f4
+0x1f1f9 0x1f1f7
+0x1f1f9 0x1f1f9
+0x1f1f9 0x1f1fb
+0x1f1f9 0x1f1fc
+0x1f1f9 0x1f1ff
+0x1f1fa
+0x1f1fa 0x1f1e6
+0x1f1fa 0x1f1ec
+0x1f1fa 0x1f1f2
+0x1f1fa 0x1f1f3
+0x1f1fa 0x1f1f8
+0x1f1fa 0x1f1fe
+0x1f1fa 0x1f1ff
+0x1f1fb
+0x1f1fb 0x1f1e6
+0x1f1fb 0x1f1e8
+0x1f1fb 0x1f1ea
+0x1f1fb 0x1f1ec
+0x1f1fb 0x1f1ee
+0x1f1fb 0x1f1f3
+0x1f1fb 0x1f1fa
+0x1f1fc
+0x1f1fc 0x1f1eb
+0x1f1fc 0x1f1f8
+0x1f1fd
+0x1f1fd 0x1f1f0
+0x1f1fe
+0x1f1fe 0x1f1ea
+0x1f1fe 0x1f1f9
+0x1f1ff
+0x1f1ff 0x1f1e6
+0x1f1ff 0x1f1f2
+0x1f1ff 0x1f1fc
+0x1f201
+0x1f202 0xfe0f
+0x1f21a
+0x1f21a 0xfe0f
+0x1f22f
+0x1f22f 0xfe0f
+0x1f232
+0x1f233
+0x1f234
+0x1f235
+0x1f236
+0x1f237 0xfe0f
+0x1f238
+0x1f239
+0x1f23a
+0x1f250
+0x1f251
+0x1f300
+0x1f301
+0x1f302
+0x1f303
+0x1f304
+0x1f305
+0x1f306
+0x1f307
+0x1f308
+0x1f309
+0x1f30a
+0x1f30b
+0x1f30c
+0x1f30d
+0x1f30e
+0x1f30f
+0x1f310
+0x1f311
+0x1f312
+0x1f313
+0x1f314
+0x1f315
+0x1f316
+0x1f317
+0x1f318
+0x1f319
+0x1f31a
+0x1f31b
+0x1f31c
+0x1f31d
+0x1f31e
+0x1f31f
+0x1f320
+0x1f321 0xfe0f
+0x1f324 0xfe0f
+0x1f325 0xfe0f
+0x1f326 0xfe0f
+0x1f327 0xfe0f
+0x1f328 0xfe0f
+0x1f329 0xfe0f
+0x1f32a 0xfe0f
+0x1f32b 0xfe0f
+0x1f32c 0xfe0f
+0x1f32d
+0x1f32e
+0x1f32f
+0x1f330
+0x1f331
+0x1f332
+0x1f333
+0x1f334
+0x1f335
+0x1f336 0xfe0f
+0x1f337
+0x1f338
+0x1f339
+0x1f33a
+0x1f33b
+0x1f33c
+0x1f33d
+0x1f33e
+0x1f33f
+0x1f340
+0x1f341
+0x1f342
+0x1f343
+0x1f344
+0x1f345
+0x1f346
+0x1f347
+0x1f348
+0x1f349
+0x1f34a
+0x1f34b
+0x1f34c
+0x1f34d
+0x1f34e
+0x1f34f
+0x1f350
+0x1f351
+0x1f352
+0x1f353
+0x1f354
+0x1f355
+0x1f356
+0x1f357
+0x1f358
+0x1f359
+0x1f35a
+0x1f35b
+0x1f35c
+0x1f35d
+0x1f35e
+0x1f35f
+0x1f360
+0x1f361
+0x1f362
+0x1f363
+0x1f364
+0x1f365
+0x1f366
+0x1f367
+0x1f368
+0x1f369
+0x1f36a
+0x1f36b
+0x1f36c
+0x1f36d
+0x1f36e
+0x1f36f
+0x1f370
+0x1f371
+0x1f372
+0x1f373
+0x1f374
+0x1f375
+0x1f376
+0x1f377
+0x1f378
+0x1f379
+0x1f37a
+0x1f37b
+0x1f37c
+0x1f37d 0xfe0f
+0x1f37e
+0x1f37f
+0x1f380
+0x1f381
+0x1f382
+0x1f383
+0x1f384
+0x1f385
+0x1f385 0x1f3fb
+0x1f385 0x1f3fc
+0x1f385 0x1f3fd
+0x1f385 0x1f3fe
+0x1f385 0x1f3ff
+0x1f386
+0x1f387
+0x1f388
+0x1f389
+0x1f38a
+0x1f38b
+0x1f38c
+0x1f38d
+0x1f38e
+0x1f38f
+0x1f390
+0x1f391
+0x1f392
+0x1f393
+0x1f396 0xfe0f
+0x1f397 0xfe0f
+0x1f399 0xfe0f
+0x1f39a 0xfe0f
+0x1f39b 0xfe0f
+0x1f39e 0xfe0f
+0x1f39f 0xfe0f
+0x1f3a0
+0x1f3a1
+0x1f3a2
+0x1f3a3
+0x1f3a4
+0x1f3a5
+0x1f3a6
+0x1f3a7
+0x1f3a8
+0x1f3a9
+0x1f3aa
+0x1f3ab
+0x1f3ac
+0x1f3ad
+0x1f3ae
+0x1f3af
+0x1f3b0
+0x1f3b1
+0x1f3b2
+0x1f3b3
+0x1f3b4
+0x1f3b5
+0x1f3b6
+0x1f3b7
+0x1f3b8
+0x1f3b9
+0x1f3ba
+0x1f3bb
+0x1f3bc
+0x1f3bd
+0x1f3be
+0x1f3bf
+0x1f3c0
+0x1f3c1
+0x1f3c2
+0x1f3c3
+0x1f3c3 0x1f3fb
+0x1f3c3 0x1f3fb 0x200d 0x2640
+0x1f3c3 0x1f3fb 0x200d 0x2642
+0x1f3c3 0x1f3fc
+0x1f3c3 0x1f3fc 0x200d 0x2640
+0x1f3c3 0x1f3fc 0x200d 0x2642
+0x1f3c3 0x1f3fd
+0x1f3c3 0x1f3fd 0x200d 0x2640
+0x1f3c3 0x1f3fd 0x200d 0x2642
+0x1f3c3 0x1f3fe
+0x1f3c3 0x1f3fe 0x200d 0x2640
+0x1f3c3 0x1f3fe 0x200d 0x2642
+0x1f3c3 0x1f3ff
+0x1f3c3 0x1f3ff 0x200d 0x2640
+0x1f3c3 0x1f3ff 0x200d 0x2642
+0x1f3c3 0x200d 0x2640
+0x1f3c3 0x200d 0x2642
+0x1f3c4
+0x1f3c4 0x1f3fb
+0x1f3c4 0x1f3fb 0x200d 0x2640
+0x1f3c4 0x1f3fb 0x200d 0x2642
+0x1f3c4 0x1f3fc
+0x1f3c4 0x1f3fc 0x200d 0x2640
+0x1f3c4 0x1f3fc 0x200d 0x2642
+0x1f3c4 0x1f3fd
+0x1f3c4 0x1f3fd 0x200d 0x2640
+0x1f3c4 0x1f3fd 0x200d 0x2642
+0x1f3c4 0x1f3fe
+0x1f3c4 0x1f3fe 0x200d 0x2640
+0x1f3c4 0x1f3fe 0x200d 0x2642
+0x1f3c4 0x1f3ff
+0x1f3c4 0x1f3ff 0x200d 0x2640
+0x1f3c4 0x1f3ff 0x200d 0x2642
+0x1f3c4 0x200d 0x2640
+0x1f3c4 0x200d 0x2642
+0x1f3c5
+0x1f3c6
+0x1f3c7
+0x1f3c8
+0x1f3c9
+0x1f3ca
+0x1f3ca 0x1f3fb
+0x1f3ca 0x1f3fb 0x200d 0x2640
+0x1f3ca 0x1f3fb 0x200d 0x2642
+0x1f3ca 0x1f3fc
+0x1f3ca 0x1f3fc 0x200d 0x2640
+0x1f3ca 0x1f3fc 0x200d 0x2642
+0x1f3ca 0x1f3fd
+0x1f3ca 0x1f3fd 0x200d 0x2640
+0x1f3ca 0x1f3fd 0x200d 0x2642
+0x1f3ca 0x1f3fe
+0x1f3ca 0x1f3fe 0x200d 0x2640
+0x1f3ca 0x1f3fe 0x200d 0x2642
+0x1f3ca 0x1f3ff
+0x1f3ca 0x1f3ff 0x200d 0x2640
+0x1f3ca 0x1f3ff 0x200d 0x2642
+0x1f3ca 0x200d 0x2640
+0x1f3ca 0x200d 0x2642
+0x1f3cb 0x1f3fb
+0x1f3cb 0x1f3fb 0x200d 0x2640
+0x1f3cb 0x1f3fb 0x200d 0x2642
+0x1f3cb 0x1f3fc
+0x1f3cb 0x1f3fc 0x200d 0x2640
+0x1f3cb 0x1f3fc 0x200d 0x2642
+0x1f3cb 0x1f3fd
+0x1f3cb 0x1f3fd 0x200d 0x2640
+0x1f3cb 0x1f3fd 0x200d 0x2642
+0x1f3cb 0x1f3fe
+0x1f3cb 0x1f3fe 0x200d 0x2640
+0x1f3cb 0x1f3fe 0x200d 0x2642
+0x1f3cb 0x1f3ff
+0x1f3cb 0x1f3ff 0x200d 0x2640
+0x1f3cb 0x1f3ff 0x200d 0x2642
+0x1f3cb 0x200d 0x2640
+0x1f3cb 0x200d 0x2642
+0x1f3cb 0xfe0f
+0x1f3cc 0x200d 0x2640
+0x1f3cc 0x200d 0x2642
+0x1f3cc 0xfe0f
+0x1f3cd 0xfe0f
+0x1f3ce 0xfe0f
+0x1f3cf
+0x1f3d0
+0x1f3d1
+0x1f3d2
+0x1f3d3
+0x1f3d4 0xfe0f
+0x1f3d5 0xfe0f
+0x1f3d6 0xfe0f
+0x1f3d7 0xfe0f
+0x1f3d8 0xfe0f
+0x1f3d9 0xfe0f
+0x1f3da 0xfe0f
+0x1f3db 0xfe0f
+0x1f3dc 0xfe0f
+0x1f3dd 0xfe0f
+0x1f3de 0xfe0f
+0x1f3df 0xfe0f
+0x1f3e0
+0x1f3e1
+0x1f3e2
+0x1f3e3
+0x1f3e4
+0x1f3e5
+0x1f3e6
+0x1f3e7
+0x1f3e8
+0x1f3e9
+0x1f3ea
+0x1f3eb
+0x1f3ec
+0x1f3ed
+0x1f3ee
+0x1f3ef
+0x1f3f0
+0x1f3f3 0x200d 0x1f308
+0x1f3f3 0xfe0f
+0x1f3f4
+0x1f3f5 0xfe0f
+0x1f3f7 0xfe0f
+0x1f3f8
+0x1f3f9
+0x1f3fa
+0x1f3fb
+0x1f3fc
+0x1f3fd
+0x1f3fe
+0x1f3ff
+0x1f400
+0x1f401
+0x1f402
+0x1f403
+0x1f404
+0x1f405
+0x1f406
+0x1f407
+0x1f408
+0x1f409
+0x1f40a
+0x1f40b
+0x1f40c
+0x1f40d
+0x1f40e
+0x1f40f
+0x1f410
+0x1f411
+0x1f412
+0x1f413
+0x1f414
+0x1f415
+0x1f416
+0x1f417
+0x1f418
+0x1f419
+0x1f41a
+0x1f41b
+0x1f41c
+0x1f41d
+0x1f41e
+0x1f41f
+0x1f420
+0x1f421
+0x1f422
+0x1f423
+0x1f424
+0x1f425
+0x1f426
+0x1f427
+0x1f428
+0x1f429
+0x1f42a
+0x1f42b
+0x1f42c
+0x1f42d
+0x1f42e
+0x1f42f
+0x1f430
+0x1f431
+0x1f432
+0x1f433
+0x1f434
+0x1f435
+0x1f436
+0x1f437
+0x1f438
+0x1f439
+0x1f43a
+0x1f43b
+0x1f43c
+0x1f43d
+0x1f43e
+0x1f43f 0xfe0f
+0x1f440
+0x1f441 0x200d 0x1f5e8
+0x1f441 0xfe0f
+0x1f442
+0x1f442 0x1f3fb
+0x1f442 0x1f3fc
+0x1f442 0x1f3fd
+0x1f442 0x1f3fe
+0x1f442 0x1f3ff
+0x1f443
+0x1f443 0x1f3fb
+0x1f443 0x1f3fc
+0x1f443 0x1f3fd
+0x1f443 0x1f3fe
+0x1f443 0x1f3ff
+0x1f444
+0x1f445
+0x1f446
+0x1f446 0x1f3fb
+0x1f446 0x1f3fc
+0x1f446 0x1f3fd
+0x1f446 0x1f3fe
+0x1f446 0x1f3ff
+0x1f447
+0x1f447 0x1f3fb
+0x1f447 0x1f3fc
+0x1f447 0x1f3fd
+0x1f447 0x1f3fe
+0x1f447 0x1f3ff
+0x1f448
+0x1f448 0x1f3fb
+0x1f448 0x1f3fc
+0x1f448 0x1f3fd
+0x1f448 0x1f3fe
+0x1f448 0x1f3ff
+0x1f449
+0x1f449 0x1f3fb
+0x1f449 0x1f3fc
+0x1f449 0x1f3fd
+0x1f449 0x1f3fe
+0x1f449 0x1f3ff
+0x1f44a
+0x1f44a 0x1f3fb
+0x1f44a 0x1f3fc
+0x1f44a 0x1f3fd
+0x1f44a 0x1f3fe
+0x1f44a 0x1f3ff
+0x1f44b
+0x1f44b 0x1f3fb
+0x1f44b 0x1f3fc
+0x1f44b 0x1f3fd
+0x1f44b 0x1f3fe
+0x1f44b 0x1f3ff
+0x1f44c
+0x1f44c 0x1f3fb
+0x1f44c 0x1f3fc
+0x1f44c 0x1f3fd
+0x1f44c 0x1f3fe
+0x1f44c 0x1f3ff
+0x1f44d
+0x1f44d 0x1f3fb
+0x1f44d 0x1f3fc
+0x1f44d 0x1f3fd
+0x1f44d 0x1f3fe
+0x1f44d 0x1f3ff
+0x1f44e
+0x1f44e 0x1f3fb
+0x1f44e 0x1f3fc
+0x1f44e 0x1f3fd
+0x1f44e 0x1f3fe
+0x1f44e 0x1f3ff
+0x1f44f
+0x1f44f 0x1f3fb
+0x1f44f 0x1f3fc
+0x1f44f 0x1f3fd
+0x1f44f 0x1f3fe
+0x1f44f 0x1f3ff
+0x1f450
+0x1f450 0x1f3fb
+0x1f450 0x1f3fc
+0x1f450 0x1f3fd
+0x1f450 0x1f3fe
+0x1f450 0x1f3ff
+0x1f451
+0x1f452
+0x1f453
+0x1f454
+0x1f455
+0x1f456
+0x1f457
+0x1f458
+0x1f459
+0x1f45a
+0x1f45b
+0x1f45c
+0x1f45d
+0x1f45e
+0x1f45f
+0x1f460
+0x1f461
+0x1f462
+0x1f463
+0x1f464
+0x1f465
+0x1f466
+0x1f466 0x1f3fb
+0x1f466 0x1f3fc
+0x1f466 0x1f3fd
+0x1f466 0x1f3fe
+0x1f466 0x1f3ff
+0x1f467
+0x1f467 0x1f3fb
+0x1f467 0x1f3fc
+0x1f467 0x1f3fd
+0x1f467 0x1f3fe
+0x1f467 0x1f3ff
+0x1f468
+0x1f468 0x1f3fb
+0x1f468 0x1f3fb 0x200d 0x1f33e
+0x1f468 0x1f3fb 0x200d 0x1f373
+0x1f468 0x1f3fb 0x200d 0x1f393
+0x1f468 0x1f3fb 0x200d 0x1f3a4
+0x1f468 0x1f3fb 0x200d 0x1f3eb
+0x1f468 0x1f3fb 0x200d 0x1f3ed
+0x1f468 0x1f3fb 0x200d 0x1f4bb
+0x1f468 0x1f3fb 0x200d 0x1f4bc
+0x1f468 0x1f3fb 0x200d 0x1f527
+0x1f468 0x1f3fb 0x200d 0x1f52c
+0x1f468 0x1f3fb 0x200d 0x2695
+0x1f468 0x1f3fc
+0x1f468 0x1f3fc 0x200d 0x1f33e
+0x1f468 0x1f3fc 0x200d 0x1f373
+0x1f468 0x1f3fc 0x200d 0x1f393
+0x1f468 0x1f3fc 0x200d 0x1f3a4
+0x1f468 0x1f3fc 0x200d 0x1f3eb
+0x1f468 0x1f3fc 0x200d 0x1f3ed
+0x1f468 0x1f3fc 0x200d 0x1f4bb
+0x1f468 0x1f3fc 0x200d 0x1f4bc
+0x1f468 0x1f3fc 0x200d 0x1f527
+0x1f468 0x1f3fc 0x200d 0x1f52c
+0x1f468 0x1f3fc 0x200d 0x2695
+0x1f468 0x1f3fd
+0x1f468 0x1f3fd 0x200d 0x1f33e
+0x1f468 0x1f3fd 0x200d 0x1f373
+0x1f468 0x1f3fd 0x200d 0x1f393
+0x1f468 0x1f3fd 0x200d 0x1f3a4
+0x1f468 0x1f3fd 0x200d 0x1f3eb
+0x1f468 0x1f3fd 0x200d 0x1f3ed
+0x1f468 0x1f3fd 0x200d 0x1f4bb
+0x1f468 0x1f3fd 0x200d 0x1f4bc
+0x1f468 0x1f3fd 0x200d 0x1f527
+0x1f468 0x1f3fd 0x200d 0x1f52c
+0x1f468 0x1f3fd 0x200d 0x2695
+0x1f468 0x1f3fe
+0x1f468 0x1f3fe 0x200d 0x1f33e
+0x1f468 0x1f3fe 0x200d 0x1f373
+0x1f468 0x1f3fe 0x200d 0x1f393
+0x1f468 0x1f3fe 0x200d 0x1f3a4
+0x1f468 0x1f3fe 0x200d 0x1f3eb
+0x1f468 0x1f3fe 0x200d 0x1f3ed
+0x1f468 0x1f3fe 0x200d 0x1f4bb
+0x1f468 0x1f3fe 0x200d 0x1f4bc
+0x1f468 0x1f3fe 0x200d 0x1f527
+0x1f468 0x1f3fe 0x200d 0x1f52c
+0x1f468 0x1f3fe 0x200d 0x2695
+0x1f468 0x1f3ff
+0x1f468 0x1f3ff 0x200d 0x1f33e
+0x1f468 0x1f3ff 0x200d 0x1f373
+0x1f468 0x1f3ff 0x200d 0x1f393
+0x1f468 0x1f3ff 0x200d 0x1f3a4
+0x1f468 0x1f3ff 0x200d 0x1f3eb
+0x1f468 0x1f3ff 0x200d 0x1f3ed
+0x1f468 0x1f3ff 0x200d 0x1f4bb
+0x1f468 0x1f3ff 0x200d 0x1f4bc
+0x1f468 0x1f3ff 0x200d 0x1f527
+0x1f468 0x1f3ff 0x200d 0x1f52c
+0x1f468 0x1f3ff 0x200d 0x2695
+0x1f468 0x200d 0x1f33e
+0x1f468 0x200d 0x1f373
+0x1f468 0x200d 0x1f393
+0x1f468 0x200d 0x1f3a4
+0x1f468 0x200d 0x1f3a8
+0x1f468 0x200d 0x1f3eb
+0x1f468 0x200d 0x1f3ed
+0x1f468 0x200d 0x1f466
+0x1f468 0x200d 0x1f466 0x200d 0x1f466
+0x1f468 0x200d 0x1f467
+0x1f468 0x200d 0x1f467 0x200d 0x1f466
+0x1f468 0x200d 0x1f467 0x200d 0x1f467
+0x1f468 0x200d 0x1f468 0x200d 0x1f466
+0x1f468 0x200d 0x1f468 0x200d 0x1f466 0x200d 0x1f466
+0x1f468 0x200d 0x1f468 0x200d 0x1f467
+0x1f468 0x200d 0x1f468 0x200d 0x1f467 0x200d 0x1f466
+0x1f468 0x200d 0x1f468 0x200d 0x1f467 0x200d 0x1f467
+0x1f468 0x200d 0x1f469 0x200d 0x1f466
+0x1f468 0x200d 0x1f469 0x200d 0x1f466 0x200d 0x1f466
+0x1f468 0x200d 0x1f469 0x200d 0x1f467
+0x1f468 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f466
+0x1f468 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f467
+0x1f468 0x200d 0x1f4bb
+0x1f468 0x200d 0x1f4bc
+0x1f468 0x200d 0x1f527
+0x1f468 0x200d 0x1f52c
+0x1f468 0x200d 0x1f680
+0x1f468 0x200d 0x1f692
+0x1f468 0x200d 0x2695
+0x1f468 0x200d 0x2696
+0x1f468 0x200d 0x2708
+0x1f468 0x200d 0x2764 0x200d 0x1f468
+0x1f468 0x200d 0x2764 0x200d 0x1f48b 0x200d 0x1f468
+0x1f469
+0x1f469 0x1f3fb
+0x1f469 0x1f3fb 0x200d 0x1f33e
+0x1f469 0x1f3fb 0x200d 0x1f373
+0x1f469 0x1f3fb 0x200d 0x1f393
+0x1f469 0x1f3fb 0x200d 0x1f3a4
+0x1f469 0x1f3fb 0x200d 0x1f3eb
+0x1f469 0x1f3fb 0x200d 0x1f3ed
+0x1f469 0x1f3fb 0x200d 0x1f4bb
+0x1f469 0x1f3fb 0x200d 0x1f4bc
+0x1f469 0x1f3fb 0x200d 0x1f527
+0x1f469 0x1f3fb 0x200d 0x1f52c
+0x1f469 0x1f3fb 0x200d 0x2695
+0x1f469 0x1f3fc
+0x1f469 0x1f3fc 0x200d 0x1f33e
+0x1f469 0x1f3fc 0x200d 0x1f373
+0x1f469 0x1f3fc 0x200d 0x1f393
+0x1f469 0x1f3fc 0x200d 0x1f3a4
+0x1f469 0x1f3fc 0x200d 0x1f3eb
+0x1f469 0x1f3fc 0x200d 0x1f3ed
+0x1f469 0x1f3fc 0x200d 0x1f4bb
+0x1f469 0x1f3fc 0x200d 0x1f4bc
+0x1f469 0x1f3fc 0x200d 0x1f527
+0x1f469 0x1f3fc 0x200d 0x1f52c
+0x1f469 0x1f3fc 0x200d 0x2695
+0x1f469 0x1f3fd
+0x1f469 0x1f3fd 0x200d 0x1f33e
+0x1f469 0x1f3fd 0x200d 0x1f373
+0x1f469 0x1f3fd 0x200d 0x1f393
+0x1f469 0x1f3fd 0x200d 0x1f3a4
+0x1f469 0x1f3fd 0x200d 0x1f3eb
+0x1f469 0x1f3fd 0x200d 0x1f3ed
+0x1f469 0x1f3fd 0x200d 0x1f4bb
+0x1f469 0x1f3fd 0x200d 0x1f4bc
+0x1f469 0x1f3fd 0x200d 0x1f527
+0x1f469 0x1f3fd 0x200d 0x1f52c
+0x1f469 0x1f3fd 0x200d 0x2695
+0x1f469 0x1f3fe
+0x1f469 0x1f3fe 0x200d 0x1f33e
+0x1f469 0x1f3fe 0x200d 0x1f373
+0x1f469 0x1f3fe 0x200d 0x1f393
+0x1f469 0x1f3fe 0x200d 0x1f3a4
+0x1f469 0x1f3fe 0x200d 0x1f3eb
+0x1f469 0x1f3fe 0x200d 0x1f3ed
+0x1f469 0x1f3fe 0x200d 0x1f4bb
+0x1f469 0x1f3fe 0x200d 0x1f4bc
+0x1f469 0x1f3fe 0x200d 0x1f527
+0x1f469 0x1f3fe 0x200d 0x1f52c
+0x1f469 0x1f3fe 0x200d 0x2695
+0x1f469 0x1f3ff
+0x1f469 0x1f3ff 0x200d 0x1f33e
+0x1f469 0x1f3ff 0x200d 0x1f373
+0x1f469 0x1f3ff 0x200d 0x1f393
+0x1f469 0x1f3ff 0x200d 0x1f3a4
+0x1f469 0x1f3ff 0x200d 0x1f3eb
+0x1f469 0x1f3ff 0x200d 0x1f3ed
+0x1f469 0x1f3ff 0x200d 0x1f4bb
+0x1f469 0x1f3ff 0x200d 0x1f4bc
+0x1f469 0x1f3ff 0x200d 0x1f527
+0x1f469 0x1f3ff 0x200d 0x1f52c
+0x1f469 0x1f3ff 0x200d 0x2695
+0x1f469 0x200d 0x1f33e
+0x1f469 0x200d 0x1f373
+0x1f469 0x200d 0x1f393
+0x1f469 0x200d 0x1f3a4
+0x1f469 0x200d 0x1f3a8
+0x1f469 0x200d 0x1f3eb
+0x1f469 0x200d 0x1f3ed
+0x1f469 0x200d 0x1f466
+0x1f469 0x200d 0x1f466 0x200d 0x1f466
+0x1f469 0x200d 0x1f467
+0x1f469 0x200d 0x1f467 0x200d 0x1f466
+0x1f469 0x200d 0x1f467 0x200d 0x1f467
+0x1f469 0x200d 0x1f469 0x200d 0x1f466
+0x1f469 0x200d 0x1f469 0x200d 0x1f466 0x200d 0x1f466
+0x1f469 0x200d 0x1f469 0x200d 0x1f467
+0x1f469 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f466
+0x1f469 0x200d 0x1f469 0x200d 0x1f467 0x200d 0x1f467
+0x1f469 0x200d 0x1f4bb
+0x1f469 0x200d 0x1f4bc
+0x1f469 0x200d 0x1f527
+0x1f469 0x200d 0x1f52c
+0x1f469 0x200d 0x1f680
+0x1f469 0x200d 0x1f692
+0x1f469 0x200d 0x2695
+0x1f469 0x200d 0x2696
+0x1f469 0x200d 0x2708
+0x1f469 0x200d 0x2764 0x200d 0x1f468
+0x1f469 0x200d 0x2764 0x200d 0x1f469
+0x1f469 0x200d 0x2764 0x200d 0x1f48b 0x200d 0x1f468
+0x1f469 0x200d 0x2764 0x200d 0x1f48b 0x200d 0x1f469
+0x1f46a
+0x1f46b
+0x1f46c
+0x1f46d
+0x1f46e
+0x1f46e 0x1f3fb
+0x1f46e 0x1f3fb 0x200d 0x2640
+0x1f46e 0x1f3fb 0x200d 0x2642
+0x1f46e 0x1f3fc
+0x1f46e 0x1f3fc 0x200d 0x2640
+0x1f46e 0x1f3fc 0x200d 0x2642
+0x1f46e 0x1f3fd
+0x1f46e 0x1f3fd 0x200d 0x2640
+0x1f46e 0x1f3fd 0x200d 0x2642
+0x1f46e 0x1f3fe
+0x1f46e 0x1f3fe 0x200d 0x2640
+0x1f46e 0x1f3fe 0x200d 0x2642
+0x1f46e 0x1f3ff
+0x1f46e 0x1f3ff 0x200d 0x2640
+0x1f46e 0x1f3ff 0x200d 0x2642
+0x1f46e 0x200d 0x2640
+0x1f46e 0x200d 0x2642
+0x1f46f
+0x1f46f 0x200d 0x2640
+0x1f46f 0x200d 0x2642
+0x1f470
+0x1f470 0x1f3fb
+0x1f470 0x1f3fc
+0x1f470 0x1f3fd
+0x1f470 0x1f3fe
+0x1f470 0x1f3ff
+0x1f471
+0x1f471 0x1f3fb
+0x1f471 0x1f3fb 0x200d 0x2640
+0x1f471 0x1f3fb 0x200d 0x2642
+0x1f471 0x1f3fc
+0x1f471 0x1f3fc 0x200d 0x2640
+0x1f471 0x1f3fc 0x200d 0x2642
+0x1f471 0x1f3fd
+0x1f471 0x1f3fd 0x200d 0x2640
+0x1f471 0x1f3fd 0x200d 0x2642
+0x1f471 0x1f3fe
+0x1f471 0x1f3fe 0x200d 0x2640
+0x1f471 0x1f3fe 0x200d 0x2642
+0x1f471 0x1f3ff
+0x1f471 0x1f3ff 0x200d 0x2640
+0x1f471 0x1f3ff 0x200d 0x2642
+0x1f471 0x200d 0x2640
+0x1f471 0x200d 0x2642
+0x1f472
+0x1f472 0x1f3fb
+0x1f472 0x1f3fc
+0x1f472 0x1f3fd
+0x1f472 0x1f3fe
+0x1f472 0x1f3ff
+0x1f473
+0x1f473 0x1f3fb
+0x1f473 0x1f3fb 0x200d 0x2640
+0x1f473 0x1f3fb 0x200d 0x2642
+0x1f473 0x1f3fc
+0x1f473 0x1f3fc 0x200d 0x2640
+0x1f473 0x1f3fc 0x200d 0x2642
+0x1f473 0x1f3fd
+0x1f473 0x1f3fd 0x200d 0x2640
+0x1f473 0x1f3fd 0x200d 0x2642
+0x1f473 0x1f3fe
+0x1f473 0x1f3fe 0x200d 0x2640
+0x1f473 0x1f3fe 0x200d 0x2642
+0x1f473 0x1f3ff
+0x1f473 0x1f3ff 0x200d 0x2640
+0x1f473 0x1f3ff 0x200d 0x2642
+0x1f473 0x200d 0x2640
+0x1f473 0x200d 0x2642
+0x1f474
+0x1f474 0x1f3fb
+0x1f474 0x1f3fc
+0x1f474 0x1f3fd
+0x1f474 0x1f3fe
+0x1f474 0x1f3ff
+0x1f475
+0x1f475 0x1f3fb
+0x1f475 0x1f3fc
+0x1f475 0x1f3fd
+0x1f475 0x1f3fe
+0x1f475 0x1f3ff
+0x1f476
+0x1f476 0x1f3fb
+0x1f476 0x1f3fc
+0x1f476 0x1f3fd
+0x1f476 0x1f3fe
+0x1f476 0x1f3ff
+0x1f477
+0x1f477 0x1f3fb
+0x1f477 0x1f3fb 0x200d 0x2640
+0x1f477 0x1f3fb 0x200d 0x2642
+0x1f477 0x1f3fc
+0x1f477 0x1f3fc 0x200d 0x2640
+0x1f477 0x1f3fc 0x200d 0x2642
+0x1f477 0x1f3fd
+0x1f477 0x1f3fd 0x200d 0x2640
+0x1f477 0x1f3fd 0x200d 0x2642
+0x1f477 0x1f3fe
+0x1f477 0x1f3fe 0x200d 0x2640
+0x1f477 0x1f3fe 0x200d 0x2642
+0x1f477 0x1f3ff
+0x1f477 0x1f3ff 0x200d 0x2640
+0x1f477 0x1f3ff 0x200d 0x2642
+0x1f477 0x200d 0x2640
+0x1f477 0x200d 0x2642
+0x1f478
+0x1f478 0x1f3fb
+0x1f478 0x1f3fc
+0x1f478 0x1f3fd
+0x1f478 0x1f3fe
+0x1f478 0x1f3ff
+0x1f479
+0x1f47a
+0x1f47b
+0x1f47c
+0x1f47c 0x1f3fb
+0x1f47c 0x1f3fc
+0x1f47c 0x1f3fd
+0x1f47c 0x1f3fe
+0x1f47c 0x1f3ff
+0x1f47d
+0x1f47e
+0x1f47f
+0x1f480
+0x1f481
+0x1f481 0x1f3fb
+0x1f481 0x1f3fb 0x200d 0x2640
+0x1f481 0x1f3fb 0x200d 0x2642
+0x1f481 0x1f3fc
+0x1f481 0x1f3fc 0x200d 0x2640
+0x1f481 0x1f3fc 0x200d 0x2642
+0x1f481 0x1f3fd
+0x1f481 0x1f3fd 0x200d 0x2640
+0x1f481 0x1f3fd 0x200d 0x2642
+0x1f481 0x1f3fe
+0x1f481 0x1f3fe 0x200d 0x2640
+0x1f481 0x1f3fe 0x200d 0x2642
+0x1f481 0x1f3ff
+0x1f481 0x1f3ff 0x200d 0x2640
+0x1f481 0x1f3ff 0x200d 0x2642
+0x1f481 0x200d 0x2640
+0x1f481 0x200d 0x2642
+0x1f482
+0x1f482 0x1f3fb
+0x1f482 0x1f3fb 0x200d 0x2640
+0x1f482 0x1f3fb 0x200d 0x2642
+0x1f482 0x1f3fc
+0x1f482 0x1f3fc 0x200d 0x2640
+0x1f482 0x1f3fc 0x200d 0x2642
+0x1f482 0x1f3fd
+0x1f482 0x1f3fd 0x200d 0x2640
+0x1f482 0x1f3fd 0x200d 0x2642
+0x1f482 0x1f3fe
+0x1f482 0x1f3fe 0x200d 0x2640
+0x1f482 0x1f3fe 0x200d 0x2642
+0x1f482 0x1f3ff
+0x1f482 0x1f3ff 0x200d 0x2640
+0x1f482 0x1f3ff 0x200d 0x2642
+0x1f482 0x200d 0x2640
+0x1f482 0x200d 0x2642
+0x1f483
+0x1f483 0x1f3fb
+0x1f483 0x1f3fc
+0x1f483 0x1f3fd
+0x1f483 0x1f3fe
+0x1f483 0x1f3ff
+0x1f484
+0x1f485
+0x1f485 0x1f3fb
+0x1f485 0x1f3fc
+0x1f485 0x1f3fd
+0x1f485 0x1f3fe
+0x1f485 0x1f3ff
+0x1f486
+0x1f486 0x1f3fb
+0x1f486 0x1f3fb 0x200d 0x2640
+0x1f486 0x1f3fb 0x200d 0x2642
+0x1f486 0x1f3fc
+0x1f486 0x1f3fc 0x200d 0x2640
+0x1f486 0x1f3fc 0x200d 0x2642
+0x1f486 0x1f3fd
+0x1f486 0x1f3fd 0x200d 0x2640
+0x1f486 0x1f3fd 0x200d 0x2642
+0x1f486 0x1f3fe
+0x1f486 0x1f3fe 0x200d 0x2640
+0x1f486 0x1f3fe 0x200d 0x2642
+0x1f486 0x1f3ff
+0x1f486 0x1f3ff 0x200d 0x2640
+0x1f486 0x1f3ff 0x200d 0x2642
+0x1f486 0x200d 0x2640
+0x1f486 0x200d 0x2642
+0x1f487
+0x1f487 0x1f3fb
+0x1f487 0x1f3fb 0x200d 0x2640
+0x1f487 0x1f3fb 0x200d 0x2642
+0x1f487 0x1f3fc
+0x1f487 0x1f3fc 0x200d 0x2640
+0x1f487 0x1f3fc 0x200d 0x2642
+0x1f487 0x1f3fd
+0x1f487 0x1f3fd 0x200d 0x2640
+0x1f487 0x1f3fd 0x200d 0x2642
+0x1f487 0x1f3fe
+0x1f487 0x1f3fe 0x200d 0x2640
+0x1f487 0x1f3fe 0x200d 0x2642
+0x1f487 0x1f3ff
+0x1f487 0x1f3ff 0x200d 0x2640
+0x1f487 0x1f3ff 0x200d 0x2642
+0x1f487 0x200d 0x2640
+0x1f487 0x200d 0x2642
+0x1f488
+0x1f489
+0x1f48a
+0x1f48b
+0x1f48c
+0x1f48d
+0x1f48e
+0x1f48f
+0x1f490
+0x1f491
+0x1f492
+0x1f493
+0x1f494
+0x1f495
+0x1f496
+0x1f497
+0x1f498
+0x1f499
+0x1f49a
+0x1f49b
+0x1f49c
+0x1f49d
+0x1f49e
+0x1f49f
+0x1f4a0
+0x1f4a1
+0x1f4a2
+0x1f4a3
+0x1f4a4
+0x1f4a5
+0x1f4a6
+0x1f4a7
+0x1f4a8
+0x1f4a9
+0x1f4aa
+0x1f4aa 0x1f3fb
+0x1f4aa 0x1f3fc
+0x1f4aa 0x1f3fd
+0x1f4aa 0x1f3fe
+0x1f4aa 0x1f3ff
+0x1f4ab
+0x1f4ac
+0x1f4ad
+0x1f4ae
+0x1f4af
+0x1f4b0
+0x1f4b1
+0x1f4b2
+0x1f4b3
+0x1f4b4
+0x1f4b5
+0x1f4b6
+0x1f4b7
+0x1f4b8
+0x1f4b9
+0x1f4ba
+0x1f4bb
+0x1f4bc
+0x1f4bd
+0x1f4be
+0x1f4bf
+0x1f4c0
+0x1f4c1
+0x1f4c2
+0x1f4c3
+0x1f4c4
+0x1f4c5
+0x1f4c6
+0x1f4c7
+0x1f4c8
+0x1f4c9
+0x1f4ca
+0x1f4cb
+0x1f4cc
+0x1f4cd
+0x1f4ce
+0x1f4cf
+0x1f4d0
+0x1f4d1
+0x1f4d2
+0x1f4d3
+0x1f4d4
+0x1f4d5
+0x1f4d6
+0x1f4d7
+0x1f4d8
+0x1f4d9
+0x1f4da
+0x1f4db
+0x1f4dc
+0x1f4dd
+0x1f4de
+0x1f4df
+0x1f4e0
+0x1f4e1
+0x1f4e2
+0x1f4e3
+0x1f4e4
+0x1f4e5
+0x1f4e6
+0x1f4e7
+0x1f4e8
+0x1f4e9
+0x1f4ea
+0x1f4eb
+0x1f4ec
+0x1f4ed
+0x1f4ee
+0x1f4ef
+0x1f4f0
+0x1f4f1
+0x1f4f2
+0x1f4f3
+0x1f4f4
+0x1f4f5
+0x1f4f6
+0x1f4f7
+0x1f4f8
+0x1f4f9
+0x1f4fa
+0x1f4fb
+0x1f4fc
+0x1f4fd 0xfe0f
+0x1f4ff
+0x1f500
+0x1f501
+0x1f502
+0x1f503
+0x1f504
+0x1f505
+0x1f506
+0x1f507
+0x1f508
+0x1f509
+0x1f50a
+0x1f50b
+0x1f50c
+0x1f50d
+0x1f50e
+0x1f50f
+0x1f510
+0x1f511
+0x1f512
+0x1f513
+0x1f514
+0x1f515
+0x1f516
+0x1f517
+0x1f518
+0x1f519
+0x1f51a
+0x1f51b
+0x1f51c
+0x1f51d
+0x1f51e
+0x1f51f
+0x1f520
+0x1f521
+0x1f522
+0x1f523
+0x1f524
+0x1f525
+0x1f526
+0x1f527
+0x1f528
+0x1f529
+0x1f52a
+0x1f52b
+0x1f52c
+0x1f52d
+0x1f52e
+0x1f52f
+0x1f530
+0x1f531
+0x1f532
+0x1f533
+0x1f534
+0x1f535
+0x1f536
+0x1f537
+0x1f538
+0x1f539
+0x1f53a
+0x1f53b
+0x1f53c
+0x1f53d
+0x1f549 0xfe0f
+0x1f54a 0xfe0f
+0x1f54b
+0x1f54c
+0x1f54d
+0x1f54e
+0x1f550
+0x1f551
+0x1f552
+0x1f553
+0x1f554
+0x1f555
+0x1f556
+0x1f557
+0x1f558
+0x1f559
+0x1f55a
+0x1f55b
+0x1f55c
+0x1f55d
+0x1f55e
+0x1f55f
+0x1f560
+0x1f561
+0x1f562
+0x1f563
+0x1f564
+0x1f565
+0x1f566
+0x1f567
+0x1f56f 0xfe0f
+0x1f570 0xfe0f
+0x1f573 0xfe0f
+0x1f574 0xfe0f
+0x1f575 0x1f3fb
+0x1f575 0x1f3fb 0x200d 0x2640
+0x1f575 0x1f3fb 0x200d 0x2642
+0x1f575 0x1f3fc
+0x1f575 0x1f3fc 0x200d 0x2640
+0x1f575 0x1f3fc 0x200d 0x2642
+0x1f575 0x1f3fd
+0x1f575 0x1f3fd 0x200d 0x2640
+0x1f575 0x1f3fd 0x200d 0x2642
+0x1f575 0x1f3fe
+0x1f575 0x1f3fe 0x200d 0x2640
+0x1f575 0x1f3fe 0x200d 0x2642
+0x1f575 0x1f3ff
+0x1f575 0x1f3ff 0x200d 0x2640
+0x1f575 0x1f3ff 0x200d 0x2642
+0x1f575 0x200d 0x2640
+0x1f575 0x200d 0x2642
+0x1f575 0xfe0f
+0x1f576 0xfe0f
+0x1f577 0xfe0f
+0x1f578 0xfe0f
+0x1f579 0xfe0f
+0x1f57a
+0x1f57a 0x1f3fb
+0x1f57a 0x1f3fc
+0x1f57a 0x1f3fd
+0x1f57a 0x1f3fe
+0x1f57a 0x1f3ff
+0x1f587 0xfe0f
+0x1f58a 0xfe0f
+0x1f58b 0xfe0f
+0x1f58c 0xfe0f
+0x1f58d 0xfe0f
+0x1f590 0x1f3fb
+0x1f590 0x1f3fc
+0x1f590 0x1f3fd
+0x1f590 0x1f3fe
+0x1f590 0x1f3ff
+0x1f590 0xfe0f
+0x1f595
+0x1f595 0x1f3fb
+0x1f595 0x1f3fc
+0x1f595 0x1f3fd
+0x1f595 0x1f3fe
+0x1f595 0x1f3ff
+0x1f596
+0x1f596 0x1f3fb
+0x1f596 0x1f3fc
+0x1f596 0x1f3fd
+0x1f596 0x1f3fe
+0x1f596 0x1f3ff
+0x1f5a4
+0x1f5a5 0xfe0f
+0x1f5a8 0xfe0f
+0x1f5b1 0xfe0f
+0x1f5b2 0xfe0f
+0x1f5bc 0xfe0f
+0x1f5c2 0xfe0f
+0x1f5c3 0xfe0f
+0x1f5c4 0xfe0f
+0x1f5d1 0xfe0f
+0x1f5d2 0xfe0f
+0x1f5d3 0xfe0f
+0x1f5dc 0xfe0f
+0x1f5dd 0xfe0f
+0x1f5de 0xfe0f
+0x1f5e1 0xfe0f
+0x1f5e3 0xfe0f
+0x1f5e8 0xfe0f
+0x1f5ef 0xfe0f
+0x1f5f3 0xfe0f
+0x1f5fa 0xfe0f
+0x1f5fb
+0x1f5fc
+0x1f5fd
+0x1f5fe
+0x1f5ff
+0x1f600
+0x1f601
+0x1f602
+0x1f603
+0x1f604
+0x1f605
+0x1f606
+0x1f607
+0x1f608
+0x1f609
+0x1f60a
+0x1f60b
+0x1f60c
+0x1f60d
+0x1f60e
+0x1f60f
+0x1f610
+0x1f611
+0x1f612
+0x1f613
+0x1f614
+0x1f615
+0x1f616
+0x1f617
+0x1f618
+0x1f619
+0x1f61a
+0x1f61b
+0x1f61c
+0x1f61d
+0x1f61e
+0x1f61f
+0x1f620
+0x1f621
+0x1f622
+0x1f623
+0x1f624
+0x1f625
+0x1f626
+0x1f627
+0x1f628
+0x1f629
+0x1f62a
+0x1f62b
+0x1f62c
+0x1f62d
+0x1f62e
+0x1f62f
+0x1f630
+0x1f631
+0x1f632
+0x1f633
+0x1f634
+0x1f635
+0x1f636
+0x1f637
+0x1f638
+0x1f639
+0x1f63a
+0x1f63b
+0x1f63c
+0x1f63d
+0x1f63e
+0x1f63f
+0x1f640
+0x1f641
+0x1f642
+0x1f643
+0x1f644
+0x1f645
+0x1f645 0x1f3fb
+0x1f645 0x1f3fb 0x200d 0x2640
+0x1f645 0x1f3fb 0x200d 0x2642
+0x1f645 0x1f3fc
+0x1f645 0x1f3fc 0x200d 0x2640
+0x1f645 0x1f3fc 0x200d 0x2642
+0x1f645 0x1f3fd
+0x1f645 0x1f3fd 0x200d 0x2640
+0x1f645 0x1f3fd 0x200d 0x2642
+0x1f645 0x1f3fe
+0x1f645 0x1f3fe 0x200d 0x2640
+0x1f645 0x1f3fe 0x200d 0x2642
+0x1f645 0x1f3ff
+0x1f645 0x1f3ff 0x200d 0x2640
+0x1f645 0x1f3ff 0x200d 0x2642
+0x1f645 0x200d 0x2640
+0x1f645 0x200d 0x2642
+0x1f646
+0x1f646 0x1f3fb
+0x1f646 0x1f3fb 0x200d 0x2640
+0x1f646 0x1f3fb 0x200d 0x2642
+0x1f646 0x1f3fc
+0x1f646 0x1f3fc 0x200d 0x2640
+0x1f646 0x1f3fc 0x200d 0x2642
+0x1f646 0x1f3fd
+0x1f646 0x1f3fd 0x200d 0x2640
+0x1f646 0x1f3fd 0x200d 0x2642
+0x1f646 0x1f3fe
+0x1f646 0x1f3fe 0x200d 0x2640
+0x1f646 0x1f3fe 0x200d 0x2642
+0x1f646 0x1f3ff
+0x1f646 0x1f3ff 0x200d 0x2640
+0x1f646 0x1f3ff 0x200d 0x2642
+0x1f646 0x200d 0x2640
+0x1f646 0x200d 0x2642
+0x1f647
+0x1f647 0x1f3fb
+0x1f647 0x1f3fb 0x200d 0x2640
+0x1f647 0x1f3fb 0x200d 0x2642
+0x1f647 0x1f3fc
+0x1f647 0x1f3fc 0x200d 0x2640
+0x1f647 0x1f3fc 0x200d 0x2642
+0x1f647 0x1f3fd
+0x1f647 0x1f3fd 0x200d 0x2640
+0x1f647 0x1f3fd 0x200d 0x2642
+0x1f647 0x1f3fe
+0x1f647 0x1f3fe 0x200d 0x2640
+0x1f647 0x1f3fe 0x200d 0x2642
+0x1f647 0x1f3ff
+0x1f647 0x1f3ff 0x200d 0x2640
+0x1f647 0x1f3ff 0x200d 0x2642
+0x1f647 0x200d 0x2640
+0x1f647 0x200d 0x2642
+0x1f648
+0x1f649
+0x1f64a
+0x1f64b
+0x1f64b 0x1f3fb
+0x1f64b 0x1f3fb 0x200d 0x2640
+0x1f64b 0x1f3fb 0x200d 0x2642
+0x1f64b 0x1f3fc
+0x1f64b 0x1f3fc 0x200d 0x2640
+0x1f64b 0x1f3fc 0x200d 0x2642
+0x1f64b 0x1f3fd
+0x1f64b 0x1f3fd 0x200d 0x2640
+0x1f64b 0x1f3fd 0x200d 0x2642
+0x1f64b 0x1f3fe
+0x1f64b 0x1f3fe 0x200d 0x2640
+0x1f64b 0x1f3fe 0x200d 0x2642
+0x1f64b 0x1f3ff
+0x1f64b 0x1f3ff 0x200d 0x2640
+0x1f64b 0x1f3ff 0x200d 0x2642
+0x1f64b 0x200d 0x2640
+0x1f64b 0x200d 0x2642
+0x1f64c
+0x1f64c 0x1f3fb
+0x1f64c 0x1f3fc
+0x1f64c 0x1f3fd
+0x1f64c 0x1f3fe
+0x1f64c 0x1f3ff
+0x1f64d
+0x1f64d 0x1f3fb
+0x1f64d 0x1f3fb 0x200d 0x2640
+0x1f64d 0x1f3fb 0x200d 0x2642
+0x1f64d 0x1f3fc
+0x1f64d 0x1f3fc 0x200d 0x2640
+0x1f64d 0x1f3fc 0x200d 0x2642
+0x1f64d 0x1f3fd
+0x1f64d 0x1f3fd 0x200d 0x2640
+0x1f64d 0x1f3fd 0x200d 0x2642
+0x1f64d 0x1f3fe
+0x1f64d 0x1f3fe 0x200d 0x2640
+0x1f64d 0x1f3fe 0x200d 0x2642
+0x1f64d 0x1f3ff
+0x1f64d 0x1f3ff 0x200d 0x2640
+0x1f64d 0x1f3ff 0x200d 0x2642
+0x1f64d 0x200d 0x2640
+0x1f64d 0x200d 0x2642
+0x1f64e
+0x1f64e 0x1f3fb
+0x1f64e 0x1f3fb 0x200d 0x2640
+0x1f64e 0x1f3fb 0x200d 0x2642
+0x1f64e 0x1f3fc
+0x1f64e 0x1f3fc 0x200d 0x2640
+0x1f64e 0x1f3fc 0x200d 0x2642
+0x1f64e 0x1f3fd
+0x1f64e 0x1f3fd 0x200d 0x2640
+0x1f64e 0x1f3fd 0x200d 0x2642
+0x1f64e 0x1f3fe
+0x1f64e 0x1f3fe 0x200d 0x2640
+0x1f64e 0x1f3fe 0x200d 0x2642
+0x1f64e 0x1f3ff
+0x1f64e 0x1f3ff 0x200d 0x2640
+0x1f64e 0x1f3ff 0x200d 0x2642
+0x1f64e 0x200d 0x2640
+0x1f64e 0x200d 0x2642
+0x1f64f
+0x1f64f 0x1f3fb
+0x1f64f 0x1f3fc
+0x1f64f 0x1f3fd
+0x1f64f 0x1f3fe
+0x1f64f 0x1f3ff
+0x1f680
+0x1f681
+0x1f682
+0x1f683
+0x1f684
+0x1f685
+0x1f686
+0x1f687
+0x1f688
+0x1f689
+0x1f68a
+0x1f68b
+0x1f68c
+0x1f68d
+0x1f68e
+0x1f68f
+0x1f690
+0x1f691
+0x1f692
+0x1f693
+0x1f694
+0x1f695
+0x1f696
+0x1f697
+0x1f698
+0x1f699
+0x1f69a
+0x1f69b
+0x1f69c
+0x1f69d
+0x1f69e
+0x1f69f
+0x1f6a0
+0x1f6a1
+0x1f6a2
+0x1f6a3
+0x1f6a3 0x1f3fb
+0x1f6a3 0x1f3fb 0x200d 0x2640
+0x1f6a3 0x1f3fb 0x200d 0x2642
+0x1f6a3 0x1f3fc
+0x1f6a3 0x1f3fc 0x200d 0x2640
+0x1f6a3 0x1f3fc 0x200d 0x2642
+0x1f6a3 0x1f3fd
+0x1f6a3 0x1f3fd 0x200d 0x2640
+0x1f6a3 0x1f3fd 0x200d 0x2642
+0x1f6a3 0x1f3fe
+0x1f6a3 0x1f3fe 0x200d 0x2640
+0x1f6a3 0x1f3fe 0x200d 0x2642
+0x1f6a3 0x1f3ff
+0x1f6a3 0x1f3ff 0x200d 0x2640
+0x1f6a3 0x1f3ff 0x200d 0x2642
+0x1f6a3 0x200d 0x2640
+0x1f6a3 0x200d 0x2642
+0x1f6a4
+0x1f6a5
+0x1f6a6
+0x1f6a7
+0x1f6a8
+0x1f6a9
+0x1f6aa
+0x1f6ab
+0x1f6ac
+0x1f6ad
+0x1f6ae
+0x1f6af
+0x1f6b0
+0x1f6b1
+0x1f6b2
+0x1f6b3
+0x1f6b4
+0x1f6b4 0x1f3fb
+0x1f6b4 0x1f3fb 0x200d 0x2640
+0x1f6b4 0x1f3fb 0x200d 0x2642
+0x1f6b4 0x1f3fc
+0x1f6b4 0x1f3fc 0x200d 0x2640
+0x1f6b4 0x1f3fc 0x200d 0x2642
+0x1f6b4 0x1f3fd
+0x1f6b4 0x1f3fd 0x200d 0x2640
+0x1f6b4 0x1f3fd 0x200d 0x2642
+0x1f6b4 0x1f3fe
+0x1f6b4 0x1f3fe 0x200d 0x2640
+0x1f6b4 0x1f3fe 0x200d 0x2642
+0x1f6b4 0x1f3ff
+0x1f6b4 0x1f3ff 0x200d 0x2640
+0x1f6b4 0x1f3ff 0x200d 0x2642
+0x1f6b4 0x200d 0x2640
+0x1f6b4 0x200d 0x2642
+0x1f6b5
+0x1f6b5 0x1f3fb
+0x1f6b5 0x1f3fb 0x200d 0x2640
+0x1f6b5 0x1f3fb 0x200d 0x2642
+0x1f6b5 0x1f3fc
+0x1f6b5 0x1f3fc 0x200d 0x2640
+0x1f6b5 0x1f3fc 0x200d 0x2642
+0x1f6b5 0x1f3fd
+0x1f6b5 0x1f3fd 0x200d 0x2640
+0x1f6b5 0x1f3fd 0x200d 0x2642
+0x1f6b5 0x1f3fe
+0x1f6b5 0x1f3fe 0x200d 0x2640
+0x1f6b5 0x1f3fe 0x200d 0x2642
+0x1f6b5 0x1f3ff
+0x1f6b5 0x1f3ff 0x200d 0x2640
+0x1f6b5 0x1f3ff 0x200d 0x2642
+0x1f6b5 0x200d 0x2640
+0x1f6b5 0x200d 0x2642
+0x1f6b6
+0x1f6b6 0x1f3fb
+0x1f6b6 0x1f3fb 0x200d 0x2640
+0x1f6b6 0x1f3fb 0x200d 0x2642
+0x1f6b6 0x1f3fc
+0x1f6b6 0x1f3fc 0x200d 0x2640
+0x1f6b6 0x1f3fc 0x200d 0x2642
+0x1f6b6 0x1f3fd
+0x1f6b6 0x1f3fd 0x200d 0x2640
+0x1f6b6 0x1f3fd 0x200d 0x2642
+0x1f6b6 0x1f3fe
+0x1f6b6 0x1f3fe 0x200d 0x2640
+0x1f6b6 0x1f3fe 0x200d 0x2642
+0x1f6b6 0x1f3ff
+0x1f6b6 0x1f3ff 0x200d 0x2640
+0x1f6b6 0x1f3ff 0x200d 0x2642
+0x1f6b6 0x200d 0x2640
+0x1f6b6 0x200d 0x2642
+0x1f6b7
+0x1f6b8
+0x1f6b9
+0x1f6ba
+0x1f6bb
+0x1f6bc
+0x1f6bd
+0x1f6be
+0x1f6bf
+0x1f6c0
+0x1f6c0 0x1f3fb
+0x1f6c0 0x1f3fc
+0x1f6c0 0x1f3fd
+0x1f6c0 0x1f3fe
+0x1f6c0 0x1f3ff
+0x1f6c1
+0x1f6c2
+0x1f6c3
+0x1f6c4
+0x1f6c5
+0x1f6cb 0xfe0f
+0x1f6cc
+0x1f6cd 0xfe0f
+0x1f6ce 0xfe0f
+0x1f6cf 0xfe0f
+0x1f6d0
+0x1f6d1
+0x1f6d2
+0x1f6e0 0xfe0f
+0x1f6e1 0xfe0f
+0x1f6e2 0xfe0f
+0x1f6e3 0xfe0f
+0x1f6e4 0xfe0f
+0x1f6e5 0xfe0f
+0x1f6e9 0xfe0f
+0x1f6eb
+0x1f6ec
+0x1f6f0 0xfe0f
+0x1f6f3 0xfe0f
+0x1f6f4
+0x1f6f5
+0x1f6f6
+0x1f910
+0x1f911
+0x1f912
+0x1f913
+0x1f914
+0x1f915
+0x1f916
+0x1f917
+0x1f918
+0x1f918 0x1f3fb
+0x1f918 0x1f3fc
+0x1f918 0x1f3fd
+0x1f918 0x1f3fe
+0x1f918 0x1f3ff
+0x1f919
+0x1f919 0x1f3fb
+0x1f919 0x1f3fc
+0x1f919 0x1f3fd
+0x1f919 0x1f3fe
+0x1f919 0x1f3ff
+0x1f91a
+0x1f91a 0x1f3fb
+0x1f91a 0x1f3fc
+0x1f91a 0x1f3fd
+0x1f91a 0x1f3fe
+0x1f91a 0x1f3ff
+0x1f91b
+0x1f91b 0x1f3fb
+0x1f91b 0x1f3fc
+0x1f91b 0x1f3fd
+0x1f91b 0x1f3fe
+0x1f91b 0x1f3ff
+0x1f91c
+0x1f91c 0x1f3fb
+0x1f91c 0x1f3fc
+0x1f91c 0x1f3fd
+0x1f91c 0x1f3fe
+0x1f91c 0x1f3ff
+0x1f91d
+0x1f91d 0x1f3fb
+0x1f91d 0x1f3fc
+0x1f91d 0x1f3fd
+0x1f91d 0x1f3fe
+0x1f91d 0x1f3ff
+0x1f91e
+0x1f91e 0x1f3fb
+0x1f91e 0x1f3fc
+0x1f91e 0x1f3fd
+0x1f91e 0x1f3fe
+0x1f91e 0x1f3ff
+0x1f920
+0x1f921
+0x1f922
+0x1f923
+0x1f924
+0x1f925
+0x1f926
+0x1f926 0x1f3fb
+0x1f926 0x1f3fb 0x200d 0x2640
+0x1f926 0x1f3fb 0x200d 0x2642
+0x1f926 0x1f3fc
+0x1f926 0x1f3fc 0x200d 0x2640
+0x1f926 0x1f3fc 0x200d 0x2642
+0x1f926 0x1f3fd
+0x1f926 0x1f3fd 0x200d 0x2640
+0x1f926 0x1f3fd 0x200d 0x2642
+0x1f926 0x1f3fe
+0x1f926 0x1f3fe 0x200d 0x2640
+0x1f926 0x1f3fe 0x200d 0x2642
+0x1f926 0x1f3ff
+0x1f926 0x1f3ff 0x200d 0x2640
+0x1f926 0x1f3ff 0x200d 0x2642
+0x1f926 0x200d 0x2640
+0x1f926 0x200d 0x2642
+0x1f927
+0x1f930
+0x1f930 0x1f3fb
+0x1f930 0x1f3fc
+0x1f930 0x1f3fd
+0x1f930 0x1f3fe
+0x1f930 0x1f3ff
+0x1f933
+0x1f933 0x1f3fb
+0x1f933 0x1f3fc
+0x1f933 0x1f3fd
+0x1f933 0x1f3fe
+0x1f933 0x1f3ff
+0x1f934
+0x1f934 0x1f3fb
+0x1f934 0x1f3fc
+0x1f934 0x1f3fd
+0x1f934 0x1f3fe
+0x1f934 0x1f3ff
+0x1f935
+0x1f935 0x1f3fb
+0x1f935 0x1f3fc
+0x1f935 0x1f3fd
+0x1f935 0x1f3fe
+0x1f935 0x1f3ff
+0x1f936
+0x1f936 0x1f3fb
+0x1f936 0x1f3fc
+0x1f936 0x1f3fd
+0x1f936 0x1f3fe
+0x1f936 0x1f3ff
+0x1f937
+0x1f937 0x1f3fb
+0x1f937 0x1f3fb 0x200d 0x2640
+0x1f937 0x1f3fb 0x200d 0x2642
+0x1f937 0x1f3fc
+0x1f937 0x1f3fc 0x200d 0x2640
+0x1f937 0x1f3fc 0x200d 0x2642
+0x1f937 0x1f3fd
+0x1f937 0x1f3fd 0x200d 0x2640
+0x1f937 0x1f3fd 0x200d 0x2642
+0x1f937 0x1f3fe
+0x1f937 0x1f3fe 0x200d 0x2640
+0x1f937 0x1f3fe 0x200d 0x2642
+0x1f937 0x1f3ff
+0x1f937 0x1f3ff 0x200d 0x2640
+0x1f937 0x1f3ff 0x200d 0x2642
+0x1f937 0x200d 0x2640
+0x1f937 0x200d 0x2642
+0x1f938
+0x1f938 0x1f3fb
+0x1f938 0x1f3fb 0x200d 0x2640
+0x1f938 0x1f3fb 0x200d 0x2642
+0x1f938 0x1f3fc
+0x1f938 0x1f3fc 0x200d 0x2640
+0x1f938 0x1f3fc 0x200d 0x2642
+0x1f938 0x1f3fd
+0x1f938 0x1f3fd 0x200d 0x2640
+0x1f938 0x1f3fd 0x200d 0x2642
+0x1f938 0x1f3fe
+0x1f938 0x1f3fe 0x200d 0x2640
+0x1f938 0x1f3fe 0x200d 0x2642
+0x1f938 0x1f3ff
+0x1f938 0x1f3ff 0x200d 0x2640
+0x1f938 0x1f3ff 0x200d 0x2642
+0x1f938 0x200d 0x2640
+0x1f938 0x200d 0x2642
+0x1f939
+0x1f939 0x1f3fb
+0x1f939 0x1f3fb 0x200d 0x2640
+0x1f939 0x1f3fb 0x200d 0x2642
+0x1f939 0x1f3fc
+0x1f939 0x1f3fc 0x200d 0x2640
+0x1f939 0x1f3fc 0x200d 0x2642
+0x1f939 0x1f3fd
+0x1f939 0x1f3fd 0x200d 0x2640
+0x1f939 0x1f3fd 0x200d 0x2642
+0x1f939 0x1f3fe
+0x1f939 0x1f3fe 0x200d 0x2640
+0x1f939 0x1f3fe 0x200d 0x2642
+0x1f939 0x1f3ff
+0x1f939 0x1f3ff 0x200d 0x2640
+0x1f939 0x1f3ff 0x200d 0x2642
+0x1f939 0x200d 0x2640
+0x1f939 0x200d 0x2642
+0x1f93a
+0x1f93c
+0x1f93c 0x1f3fb
+0x1f93c 0x1f3fb 0x200d 0x2640
+0x1f93c 0x1f3fb 0x200d 0x2642
+0x1f93c 0x1f3fc
+0x1f93c 0x1f3fc 0x200d 0x2640
+0x1f93c 0x1f3fc 0x200d 0x2642
+0x1f93c 0x1f3fd
+0x1f93c 0x1f3fd 0x200d 0x2640
+0x1f93c 0x1f3fd 0x200d 0x2642
+0x1f93c 0x1f3fe
+0x1f93c 0x1f3fe 0x200d 0x2640
+0x1f93c 0x1f3fe 0x200d 0x2642
+0x1f93c 0x1f3ff
+0x1f93c 0x1f3ff 0x200d 0x2640
+0x1f93c 0x1f3ff 0x200d 0x2642
+0x1f93c 0x200d 0x2640
+0x1f93c 0x200d 0x2642
+0x1f93d
+0x1f93d 0x1f3fb
+0x1f93d 0x1f3fb 0x200d 0x2640
+0x1f93d 0x1f3fb 0x200d 0x2642
+0x1f93d 0x1f3fc
+0x1f93d 0x1f3fc 0x200d 0x2640
+0x1f93d 0x1f3fc 0x200d 0x2642
+0x1f93d 0x1f3fd
+0x1f93d 0x1f3fd 0x200d 0x2640
+0x1f93d 0x1f3fd 0x200d 0x2642
+0x1f93d 0x1f3fe
+0x1f93d 0x1f3fe 0x200d 0x2640
+0x1f93d 0x1f3fe 0x200d 0x2642
+0x1f93d 0x1f3ff
+0x1f93d 0x1f3ff 0x200d 0x2640
+0x1f93d 0x1f3ff 0x200d 0x2642
+0x1f93d 0x200d 0x2640
+0x1f93d 0x200d 0x2642
+0x1f93e
+0x1f93e 0x1f3fb
+0x1f93e 0x1f3fb 0x200d 0x2640
+0x1f93e 0x1f3fb 0x200d 0x2642
+0x1f93e 0x1f3fc
+0x1f93e 0x1f3fc 0x200d 0x2640
+0x1f93e 0x1f3fc 0x200d 0x2642
+0x1f93e 0x1f3fd
+0x1f93e 0x1f3fd 0x200d 0x2640
+0x1f93e 0x1f3fd 0x200d 0x2642
+0x1f93e 0x1f3fe
+0x1f93e 0x1f3fe 0x200d 0x2640
+0x1f93e 0x1f3fe 0x200d 0x2642
+0x1f93e 0x1f3ff
+0x1f93e 0x1f3ff 0x200d 0x2640
+0x1f93e 0x1f3ff 0x200d 0x2642
+0x1f93e 0x200d 0x2640
+0x1f93e 0x200d 0x2642
+0x1f940
+0x1f941
+0x1f942
+0x1f943
+0x1f944
+0x1f945
+0x1f947
+0x1f948
+0x1f949
+0x1f94a
+0x1f94b
+0x1f950
+0x1f951
+0x1f952
+0x1f953
+0x1f954
+0x1f955
+0x1f956
+0x1f957
+0x1f958
+0x1f959
+0x1f95a
+0x1f95b
+0x1f95c
+0x1f95d
+0x1f95e
+0x1f980
+0x1f981
+0x1f982
+0x1f983
+0x1f984
+0x1f985
+0x1f986
+0x1f987
+0x1f988
+0x1f989
+0x1f98a
+0x1f98b
+0x1f98c
+0x1f98d
+0x1f98e
+0x1f98f
+0x1f990
+0x1f991
+0x1f9c0
+0x203c 0xfe0f
+0x2049 0xfe0f
+0x2122 0xfe0f
+0x2139 0xfe0f
+0x2194 0xfe0f
+0x2195 0xfe0f
+0x2196 0xfe0f
+0x2197 0xfe0f
+0x2198 0xfe0f
+0x2199 0xfe0f
+0x21a9 0xfe0f
+0x21aa 0xfe0f
+0x23 0x20e3
+0x23 0xfe0f
+0x231a
+0x231a 0xfe0f
+0x231b
+0x231b 0xfe0f
+0x2328 0xfe0f
+0x23cf 0xfe0f
+0x23e9
+0x23ea
+0x23eb
+0x23ec
+0x23ed 0xfe0f
+0x23ee 0xfe0f
+0x23ef 0xfe0f
+0x23f0
+0x23f1 0xfe0f
+0x23f2 0xfe0f
+0x23f3
+0x23f8 0xfe0f
+0x23f9 0xfe0f
+0x23fa 0xfe0f
+0x24c2 0xfe0f
+0x25aa 0xfe0f
+0x25ab 0xfe0f
+0x25b6 0xfe0f
+0x25c0 0xfe0f
+0x25fb 0xfe0f
+0x25fc 0xfe0f
+0x25fd
+0x25fd 0xfe0f
+0x25fe
+0x25fe 0xfe0f
+0x2600 0xfe0f
+0x2601 0xfe0f
+0x2602 0xfe0f
+0x2603 0xfe0f
+0x2604 0xfe0f
+0x260e 0xfe0f
+0x2611 0xfe0f
+0x2614
+0x2614 0xfe0f
+0x2615
+0x2615 0xfe0f
+0x2618 0xfe0f
+0x261d 0x1f3fb
+0x261d 0x1f3fc
+0x261d 0x1f3fd
+0x261d 0x1f3fe
+0x261d 0x1f3ff
+0x261d 0xfe0f
+0x2620 0xfe0f
+0x2622 0xfe0f
+0x2623 0xfe0f
+0x2626 0xfe0f
+0x262a 0xfe0f
+0x262e 0xfe0f
+0x262f 0xfe0f
+0x2638 0xfe0f
+0x2639 0xfe0f
+0x263a 0xfe0f
+0x2640 0xfe0f
+0x2642 0xfe0f
+0x2648
+0x2648 0xfe0f
+0x2649
+0x2649 0xfe0f
+0x264a
+0x264a 0xfe0f
+0x264b
+0x264b 0xfe0f
+0x264c
+0x264c 0xfe0f
+0x264d
+0x264d 0xfe0f
+0x264e
+0x264e 0xfe0f
+0x264f
+0x264f 0xfe0f
+0x2650
+0x2650 0xfe0f
+0x2651
+0x2651 0xfe0f
+0x2652
+0x2652 0xfe0f
+0x2653
+0x2653 0xfe0f
+0x2660 0xfe0f
+0x2663 0xfe0f
+0x2665 0xfe0f
+0x2666 0xfe0f
+0x2668 0xfe0f
+0x267b 0xfe0f
+0x267f
+0x267f 0xfe0f
+0x2692 0xfe0f
+0x2693
+0x2693 0xfe0f
+0x2694 0xfe0f
+0x2695 0xfe0f
+0x2696 0xfe0f
+0x2697 0xfe0f
+0x2699 0xfe0f
+0x269b 0xfe0f
+0x269c 0xfe0f
+0x26a0 0xfe0f
+0x26a1
+0x26a1 0xfe0f
+0x26aa
+0x26aa 0xfe0f
+0x26ab
+0x26ab 0xfe0f
+0x26b0 0xfe0f
+0x26b1 0xfe0f
+0x26bd
+0x26bd 0xfe0f
+0x26be
+0x26be 0xfe0f
+0x26c4
+0x26c4 0xfe0f
+0x26c5
+0x26c5 0xfe0f
+0x26c8 0xfe0f
+0x26ce
+0x26cf 0xfe0f
+0x26d1 0xfe0f
+0x26d3 0xfe0f
+0x26d4
+0x26d4 0xfe0f
+0x26e9 0xfe0f
+0x26ea
+0x26ea 0xfe0f
+0x26f0 0xfe0f
+0x26f1 0xfe0f
+0x26f2
+0x26f2 0xfe0f
+0x26f3
+0x26f3 0xfe0f
+0x26f4 0xfe0f
+0x26f5
+0x26f5 0xfe0f
+0x26f7 0xfe0f
+0x26f8 0xfe0f
+0x26f9 0x1f3fb
+0x26f9 0x1f3fb 0x200d 0x2640
+0x26f9 0x1f3fb 0x200d 0x2642
+0x26f9 0x1f3fc
+0x26f9 0x1f3fc 0x200d 0x2640
+0x26f9 0x1f3fc 0x200d 0x2642
+0x26f9 0x1f3fd
+0x26f9 0x1f3fd 0x200d 0x2640
+0x26f9 0x1f3fd 0x200d 0x2642
+0x26f9 0x1f3fe
+0x26f9 0x1f3fe 0x200d 0x2640
+0x26f9 0x1f3fe 0x200d 0x2642
+0x26f9 0x1f3ff
+0x26f9 0x1f3ff 0x200d 0x2640
+0x26f9 0x1f3ff 0x200d 0x2642
+0x26f9 0x200d 0x2640
+0x26f9 0x200d 0x2642
+0x26f9 0xfe0f
+0x26fa
+0x26fa 0xfe0f
+0x26fd
+0x26fd 0xfe0f
+0x2702 0xfe0f
+0x2705
+0x2708 0xfe0f
+0x2709 0xfe0f
+0x270a
+0x270a 0x1f3fb
+0x270a 0x1f3fc
+0x270a 0x1f3fd
+0x270a 0x1f3fe
+0x270a 0x1f3ff
+0x270b
+0x270b 0x1f3fb
+0x270b 0x1f3fc
+0x270b 0x1f3fd
+0x270b 0x1f3fe
+0x270b 0x1f3ff
+0x270c 0x1f3fb
+0x270c 0x1f3fc
+0x270c 0x1f3fd
+0x270c 0x1f3fe
+0x270c 0x1f3ff
+0x270c 0xfe0f
+0x270d 0x1f3fb
+0x270d 0x1f3fc
+0x270d 0x1f3fd
+0x270d 0x1f3fe
+0x270d 0x1f3ff
+0x270d 0xfe0f
+0x270f 0xfe0f
+0x2712 0xfe0f
+0x2714 0xfe0f
+0x2716 0xfe0f
+0x271d 0xfe0f
+0x2721 0xfe0f
+0x2728
+0x2733 0xfe0f
+0x2734 0xfe0f
+0x2744 0xfe0f
+0x2747 0xfe0f
+0x274c
+0x274e
+0x2753
+0x2754
+0x2755
+0x2757
+0x2757 0xfe0f
+0x2763 0xfe0f
+0x2764 0xfe0f
+0x2795
+0x2796
+0x2797
+0x27a1 0xfe0f
+0x27b0
+0x27bf
+0x2934 0xfe0f
+0x2935 0xfe0f
+0x2a 0x20e3
+0x2a 0xfe0f
+0x2b05 0xfe0f
+0x2b06 0xfe0f
+0x2b07 0xfe0f
+0x2b1b
+0x2b1b 0xfe0f
+0x2b1c
+0x2b1c 0xfe0f
+0x2b50
+0x2b50 0xfe0f
+0x2b55
+0x2b55 0xfe0f
+0x30 0x20e3
+0x30 0xfe0f
+0x3030 0xfe0f
+0x303d 0xfe0f
+0x31 0x20e3
+0x31 0xfe0f
+0x32 0x20e3
+0x32 0xfe0f
+0x3297 0xfe0f
+0x3299 0xfe0f
+0x33 0x20e3
+0x33 0xfe0f
+0x34 0x20e3
+0x34 0xfe0f
+0x35 0x20e3
+0x35 0xfe0f
+0x36 0x20e3
+0x36 0xfe0f
+0x37 0x20e3
+0x37 0xfe0f
+0x38 0x20e3
+0x38 0xfe0f
+0x39 0x20e3
+0x39 0xfe0f
+0xa9 0xfe0f
+0xae 0xfe0f
\ No newline at end of file
diff --git a/emoji/core/third_party/flatbuffers/FLATBUFFERS_LICENSE.txt b/emoji/core/third_party/flatbuffers/FLATBUFFERS_LICENSE.txt
new file mode 100644
index 0000000..6c4f91c
--- /dev/null
+++ b/emoji/core/third_party/flatbuffers/FLATBUFFERS_LICENSE.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2014 Google Inc.
+
+   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.
\ No newline at end of file
diff --git a/emoji/core/third_party/flatbuffers/flatbuffers-java-1.6.0.jar b/emoji/core/third_party/flatbuffers/flatbuffers-java-1.6.0.jar
new file mode 100644
index 0000000..65cd337
--- /dev/null
+++ b/emoji/core/third_party/flatbuffers/flatbuffers-java-1.6.0.jar
Binary files differ
diff --git a/exifinterface/src/android/support/media/ExifInterface.java b/exifinterface/src/android/support/media/ExifInterface.java
index c4d602d..ec59c63 100644
--- a/exifinterface/src/android/support/media/ExifInterface.java
+++ b/exifinterface/src/android/support/media/ExifInterface.java
@@ -50,7 +50,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 import java.util.TimeZone;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -1185,14 +1184,19 @@
             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG);
 
     // Mappings from tag number to tag name and each item represents one IFD tag group.
-    private static final HashMap[] sExifTagMapsForReading = new HashMap[EXIF_TAGS.length];
+    @SuppressWarnings("unchecked")
+    private static final HashMap<Integer, ExifTag>[] sExifTagMapsForReading =
+            new HashMap[EXIF_TAGS.length];
     // Mappings from tag name to tag number and each item represents one IFD tag group.
-    private static final HashMap[] sExifTagMapsForWriting = new HashMap[EXIF_TAGS.length];
+    @SuppressWarnings("unchecked")
+    private static final HashMap<String, ExifTag>[] sExifTagMapsForWriting =
+            new HashMap[EXIF_TAGS.length];
     private static final HashSet<String> sTagSetForCompatibility = new HashSet<>(Arrays.asList(
             TAG_F_NUMBER, TAG_DIGITAL_ZOOM_RATIO, TAG_EXPOSURE_TIME, TAG_SUBJECT_DISTANCE,
             TAG_GPS_TIMESTAMP));
     // Mappings from tag number to IFD type for pointer tags.
-    private static final HashMap sExifPointerTagMap = new HashMap();
+    @SuppressWarnings("unchecked")
+    private static final HashMap<Integer, Integer> sExifPointerTagMap = new HashMap();
 
     // See JPEG File Interchange Format Version 1.02.
     // The following values are defined for handling JPEG streams. In this implementation, we are
@@ -1245,8 +1249,8 @@
 
         // Build up the hash tables to look up Exif tags for reading Exif tags.
         for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
-            sExifTagMapsForReading[ifdType] = new HashMap();
-            sExifTagMapsForWriting[ifdType] = new HashMap();
+            sExifTagMapsForReading[ifdType] = new HashMap<>();
+            sExifTagMapsForWriting[ifdType] = new HashMap<>();
             for (ExifTag tag : EXIF_TAGS[ifdType]) {
                 sExifTagMapsForReading[ifdType].put(tag.number, tag);
                 sExifTagMapsForWriting[ifdType].put(tag.name, tag);
@@ -1265,7 +1269,8 @@
     private final String mFilename;
     private final AssetManager.AssetInputStream mAssetInputStream;
     private int mMimeType;
-    private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
+    @SuppressWarnings("unchecked")
+    private final HashMap<String, ExifAttribute>[] mAttributes = new HashMap[EXIF_TAGS.length];
     private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
     private boolean mHasThumbnail;
     // The following values used for indicating a thumbnail position.
@@ -1333,9 +1338,9 @@
         // Retrieves all tag groups. The value from primary image tag group has a higher priority
         // than the value from the thumbnail tag group if there are more than one candidates.
         for (int i = 0; i < EXIF_TAGS.length; ++i) {
-            Object value = mAttributes[i].get(tag);
+            ExifAttribute value = mAttributes[i].get(tag);
             if (value != null) {
-                return (ExifAttribute) value;
+                return value;
             }
         }
         return null;
@@ -1453,13 +1458,12 @@
             if (i == IFD_TYPE_THUMBNAIL && !mHasThumbnail) {
                 continue;
             }
-            final Object obj = sExifTagMapsForWriting[i].get(tag);
-            if (obj != null) {
+            final ExifTag exifTag = sExifTagMapsForWriting[i].get(tag);
+            if (exifTag != null) {
                 if (value == null) {
                     mAttributes[i].remove(tag);
                     continue;
                 }
-                final ExifTag exifTag = (ExifTag) obj;
                 Pair<Integer, Integer> guess = guessDataFormat(value);
                 int dataFormat;
                 if (exifTag.primaryFormat == guess.first || exifTag.primaryFormat == guess.second) {
@@ -1600,7 +1604,7 @@
         try {
             // Initialize mAttributes.
             for (int i = 0; i < EXIF_TAGS.length; ++i) {
-                mAttributes[i] = new HashMap();
+                mAttributes[i] = new HashMap<>();
             }
 
             // Check file type
@@ -1667,8 +1671,8 @@
     private void printAttributes() {
         for (int i = 0; i < mAttributes.length; ++i) {
             Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size());
-            for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
-                final ExifAttribute tagValue = (ExifAttribute) entry.getValue();
+            for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) {
+                final ExifAttribute tagValue = entry.getValue();
                 Log.d(TAG, "tagName: " + entry.getKey() + ", tagType: " + tagValue.toString()
                         + ", tagValue: '" + tagValue.getStringValue(mExifByteOrder) + "'");
             }
@@ -2076,7 +2080,7 @@
      * http://fileformats.archiveteam.org/wiki/Fujifilm_RAF
      */
     private boolean isRafFormat(byte[] signatureCheckBytes) throws IOException {
-        byte[] rafSignatureBytes = RAF_SIGNATURE.getBytes();
+        byte[] rafSignatureBytes = RAF_SIGNATURE.getBytes(Charset.defaultCharset());
         for (int i = 0; i < rafSignatureBytes.length; i++) {
             if (signatureCheckBytes[i] != rafSignatureBytes[i]) {
                 return false;
@@ -2734,11 +2738,11 @@
                     Log.d(TAG, "seek to data offset: " + offset);
                 }
                 if (mMimeType == IMAGE_TYPE_ORF) {
-                    if (tag.name == TAG_MAKER_NOTE) {
+                    if (TAG_MAKER_NOTE.equals(tag.name)) {
                         // Save offset value for reading thumbnail
                         mOrfMakerNoteOffset = offset;
                     } else if (ifdType == IFD_TYPE_ORF_MAKER_NOTE
-                            && tag.name == TAG_ORF_THUMBNAIL_IMAGE) {
+                            && TAG_ORF_THUMBNAIL_IMAGE.equals(tag.name)) {
                         // Retrieve & update values for thumbnail offset and length values for ORF
                         mOrfThumbnailOffset = offset;
                         mOrfThumbnailLength = numberOfComponents;
@@ -2757,7 +2761,7 @@
                                 jpegInterchangeFormatLengthAttribute);
                     }
                 } else if (mMimeType == IMAGE_TYPE_RW2) {
-                    if (tag.name == TAG_RW2_JPG_FROM_RAW) {
+                    if (TAG_RW2_JPG_FROM_RAW.equals(tag.name)) {
                         mRw2JpgFromRawOffset = offset;
                     }
                 }
@@ -2772,7 +2776,7 @@
             }
 
             // Recursively parse IFD when a IFD pointer tag appears.
-            Object nextIfdType = sExifPointerTagMap.get(tagNumber);
+            Integer nextIfdType = sExifPointerTagMap.get(tagNumber);
             if (DEBUG) {
                 Log.d(TAG, "nextIfdType: " + nextIfdType + " byteCount: " + byteCount);
             }
@@ -2808,7 +2812,7 @@
                 }
                 if (offset > 0L && offset < dataInputStream.mLength) {
                     dataInputStream.seek(offset);
-                    readImageFileDirectory(dataInputStream, (int) nextIfdType);
+                    readImageFileDirectory(dataInputStream, nextIfdType);
                 } else {
                     Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset);
                 }
@@ -2825,16 +2829,16 @@
             // DNG files have a DNG Version tag specifying the version of specifications that the
             // image file is following.
             // See http://fileformats.archiveteam.org/wiki/DNG
-            if (tag.name == TAG_DNG_VERSION) {
+            if (TAG_DNG_VERSION.equals(tag.name)) {
                 mMimeType = IMAGE_TYPE_DNG;
             }
 
             // PEF files have a Make or Model tag that begins with "PENTAX" or a compression tag
             // that is 65535.
             // See http://fileformats.archiveteam.org/wiki/Pentax_PEF
-            if (((tag.name == TAG_MAKE || tag.name == TAG_MODEL)
+            if (((TAG_MAKE.equals(tag.name) || TAG_MODEL.equals(tag.name))
                     && attribute.getStringValue(mExifByteOrder).contains(PEF_SIGNATURE))
-                    || (tag.name == TAG_COMPRESSION
+                    || (TAG_COMPRESSION.equals(tag.name)
                     && attribute.getIntValue(mExifByteOrder) == 65535)) {
                 mMimeType = IMAGE_TYPE_PEF;
             }
@@ -3098,7 +3102,7 @@
         if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
             if (isThumbnail(mAttributes[IFD_TYPE_PREVIEW])) {
                 mAttributes[IFD_TYPE_THUMBNAIL] = mAttributes[IFD_TYPE_PREVIEW];
-                mAttributes[IFD_TYPE_PREVIEW] = new HashMap();
+                mAttributes[IFD_TYPE_PREVIEW] = new HashMap<>();
             }
         }
 
@@ -3235,8 +3239,8 @@
         // value which has a bigger size than 4 bytes.
         for (int i = 0; i < EXIF_TAGS.length; ++i) {
             int sum = 0;
-            for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
-                final ExifAttribute exifAttribute = (ExifAttribute) entry.getValue();
+            for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) {
+                final ExifAttribute exifAttribute = entry.getValue();
                 final int size = exifAttribute.size();
                 if (size > 4) {
                     sum += size;
@@ -3303,12 +3307,11 @@
 
                 // Write entry info
                 int dataOffset = ifdOffsets[ifdType] + 2 + mAttributes[ifdType].size() * 12 + 4;
-                for (Map.Entry entry : (Set<Map.Entry>) mAttributes[ifdType].entrySet()) {
+                for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) {
                     // Convert tag name to tag number.
-                    final ExifTag tag =
-                            (ExifTag) sExifTagMapsForWriting[ifdType].get(entry.getKey());
+                    final ExifTag tag = sExifTagMapsForWriting[ifdType].get(entry.getKey());
                     final int tagNumber = tag.number;
-                    final ExifAttribute attribute = (ExifAttribute) entry.getValue();
+                    final ExifAttribute attribute = entry.getValue();
                     final int size = attribute.size();
 
                     dataOutputStream.writeUnsignedShort(tagNumber);
@@ -3338,8 +3341,8 @@
                 }
 
                 // Write values of data field exceeding 4 bytes after the next offset.
-                for (Map.Entry entry : (Set<Map.Entry>) mAttributes[ifdType].entrySet()) {
-                    ExifAttribute attribute = (ExifAttribute) entry.getValue();
+                for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) {
+                    ExifAttribute attribute = entry.getValue();
 
                     if (attribute.bytes.length > 4) {
                         dataOutputStream.write(attribute.bytes, 0, attribute.bytes.length);
@@ -3378,12 +3381,12 @@
             for (int i = 1; i < entryValues.length; ++i) {
                 final Pair<Integer, Integer> guessDataFormat = guessDataFormat(entryValues[i]);
                 int first = -1, second = -1;
-                if (guessDataFormat.first == dataFormat.first
-                        || guessDataFormat.second == dataFormat.first) {
+                if (guessDataFormat.first.equals(dataFormat.first)
+                        || guessDataFormat.second.equals(dataFormat.first)) {
                     first = dataFormat.first;
                 }
-                if (dataFormat.second != -1 && (guessDataFormat.first == dataFormat.second
-                        || guessDataFormat.second == dataFormat.second)) {
+                if (dataFormat.second != -1 && (guessDataFormat.first.equals(dataFormat.second)
+                        || guessDataFormat.second.equals(dataFormat.second))) {
                     second = dataFormat.second;
                 }
                 if (first == -1 && second == -1) {
@@ -3448,13 +3451,11 @@
         private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
 
         private DataInputStream mDataInputStream;
-        private InputStream mInputStream;
         private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
         private final int mLength;
         private int mPosition;
 
         public ByteOrderedDataInputStream(InputStream in) throws IOException {
-            mInputStream = in;
             mDataInputStream = new DataInputStream(in);
             mLength = mDataInputStream.available();
             mPosition = 0;
@@ -3499,6 +3500,13 @@
         }
 
         @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            int bytesRead = mDataInputStream.read(b, off, len);
+            mPosition += bytesRead;
+            return bytesRead;
+        }
+
+        @Override
         public int readUnsignedByte() throws IOException {
             ++mPosition;
             return mDataInputStream.readUnsignedByte();
@@ -3775,7 +3783,7 @@
 
             if (firstImageLengthValue < secondImageLengthValue &&
                     firstImageWidthValue < secondImageWidthValue) {
-                HashMap tempMap = mAttributes[firstIfdType];
+                HashMap<String, ExifAttribute> tempMap = mAttributes[firstIfdType];
                 mAttributes[firstIfdType] = mAttributes[secondIfdType];
                 mAttributes[secondIfdType] = tempMap;
             }
diff --git a/fragment/java/android/support/v4/app/FragmentHostCallback.java b/fragment/java/android/support/v4/app/FragmentHostCallback.java
index fa51ccd..7dc9f59 100644
--- a/fragment/java/android/support/v4/app/FragmentHostCallback.java
+++ b/fragment/java/android/support/v4/app/FragmentHostCallback.java
@@ -308,6 +308,8 @@
         if (lm == null && create) {
             lm = new LoaderManagerImpl(who, this, started);
             mAllLoaderManagers.put(who, lm);
+        } else if (started && lm != null && !lm.mStarted) {
+            lm.doStart();
         }
         return lm;
     }
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 0d311c0..8302203 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -3160,7 +3160,7 @@
         if (mLifecycleCallbacks == null) {
             mLifecycleCallbacks = new CopyOnWriteArrayList<>();
         }
-        mLifecycleCallbacks.add(new Pair(cb, recursive));
+        mLifecycleCallbacks.add(new Pair<>(cb, recursive));
     }
 
     @Override
diff --git a/fragment/java/android/support/v4/app/LoaderManager.java b/fragment/java/android/support/v4/app/LoaderManager.java
index 72718ae..521b218 100644
--- a/fragment/java/android/support/v4/app/LoaderManager.java
+++ b/fragment/java/android/support/v4/app/LoaderManager.java
@@ -839,6 +839,7 @@
             mInactiveLoaders.valueAt(i).destroy();
         }
         mInactiveLoaders.clear();
+        mHost = null;
     }
 
     @Override
diff --git a/fragment/tests/AndroidManifest.xml b/fragment/tests/AndroidManifest.xml
index d983969..fb45ecf 100644
--- a/fragment/tests/AndroidManifest.xml
+++ b/fragment/tests/AndroidManifest.xml
@@ -36,6 +36,8 @@
         <activity android:name="android.support.v4.app.test.EmptyFragmentTestActivity" />
 
         <activity android:name="android.support.v4.app.test.FragmentResultActivity" />
+
+        <activity android:name="android.support.v4.app.test.LoaderActivity" />
     </application>
 
 </manifest>
diff --git a/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java b/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java
index a37b82e..7c7ea39 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java
@@ -19,6 +19,7 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Parcelable;
@@ -30,6 +31,9 @@
 import android.view.ViewGroup;
 import android.view.animation.Animation;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
 public class FragmentTestUtil {
     private static final Runnable DO_NOTHING = new Runnable() {
         @Override
@@ -64,14 +68,18 @@
     }
 
     public static boolean executePendingTransactions(
-            final ActivityTestRule<FragmentTestActivity> rule) {
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+            final ActivityTestRule<? extends FragmentActivity> rule) {
+        FragmentManager fragmentManager = rule.getActivity().getSupportFragmentManager();
+        return executePendingTransactions(rule, fragmentManager);
+    }
+
+    public static boolean executePendingTransactions(
+            final ActivityTestRule<? extends Activity> rule, final FragmentManager fm) {
         final boolean[] ret = new boolean[1];
-        instrumentation.runOnMainSync(new Runnable() {
+        runOnUiThreadRethrow(rule, new Runnable() {
             @Override
             public void run() {
-                ret[0] =
-                        rule.getActivity().getSupportFragmentManager().executePendingTransactions();
+                ret[0] = fm.executePendingTransactions();
             }
         });
         return ret[0];
@@ -211,4 +219,27 @@
         } while (!hasEnded[0] && SystemClock.uptimeMillis() < endTime);
         return hasEnded[0];
     }
+
+    /**
+     * Allocates until a garbage collection occurs.
+     */
+    public static void forceGC() {
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
+            // The following works on O+
+            Runtime.getRuntime().gc();
+            Runtime.getRuntime().gc();
+            Runtime.getRuntime().runFinalization();
+        } else {
+            // The following works on older versions
+            for (int i = 0; i < 2; i++) {
+                // Use a random index in the list to detect the garbage collection each time because
+                // .get() may accidentally trigger a strong reference during collection.
+                ArrayList<WeakReference<byte[]>> leak = new ArrayList<>();
+                do {
+                    WeakReference<byte[]> arr = new WeakReference<byte[]>(new byte[100]);
+                    leak.add(arr);
+                } while (leak.get((int) (Math.random() * leak.size())).get() != null);
+            }
+        }
+    }
 }
diff --git a/fragment/tests/java/android/support/v4/app/LoaderTest.java b/fragment/tests/java/android/support/v4/app/LoaderTest.java
new file mode 100644
index 0000000..fde9d63
--- /dev/null
+++ b/fragment/tests/java/android/support/v4/app/LoaderTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2017 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.v4.app;
+
+import static junit.framework.Assert.assertNull;
+import static junit.framework.TestCase.assertFalse;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.test.LoaderActivity;
+import android.support.v4.content.AsyncTaskLoader;
+import android.support.v4.content.Loader;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class LoaderTest {
+    private static final int DELAY_LOADER = 10;
+
+    @Rule
+    public ActivityTestRule<LoaderActivity> mActivityRule =
+            new ActivityTestRule(LoaderActivity.class);
+
+    @After
+    public void clearActivity() {
+        LoaderActivity.clearState();
+    }
+
+    /**
+     * Test to ensure that there is no Activity leak due to Loader
+     */
+    @Test
+    public void testLeak() throws Throwable {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        Intent intent = new Intent(mActivityRule.getActivity(), LoaderActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        LoaderActivity.sResumed = new CountDownLatch(1);
+        instrumentation.startActivitySync(intent);
+        assertTrue(LoaderActivity.sResumed.await(1, TimeUnit.SECONDS));
+
+        LoaderFragment fragment = new LoaderFragment();
+        FragmentManager fm = LoaderActivity.sActivity.getSupportFragmentManager();
+
+        fm.beginTransaction()
+                .add(fragment, "1")
+                .commit();
+
+        FragmentTestUtil.executePendingTransactions(mActivityRule, fm);
+
+        fm.beginTransaction()
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.executePendingTransactions(mActivityRule, fm);
+
+        WeakReference<LoaderActivity> weakActivity = new WeakReference(LoaderActivity.sActivity);
+
+        if (!switchOrientation()) {
+            return; // can't switch orientation for square screens
+        }
+
+        // Wait for everything to settle. We have to make sure that the old Activity
+        // is ready to be collected.
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // Force a garbage collection.
+        FragmentTestUtil.forceGC();
+        assertNull(weakActivity.get());
+    }
+
+    /**
+     * When a LoaderManager is reused, it should notify in onResume
+     */
+    @Test
+    public void startWhenReused() throws Throwable {
+        LoaderActivity activity = mActivityRule.getActivity();
+
+        assertEquals("Loaded!", activity.textView.getText().toString());
+
+        if (!switchOrientation()) {
+            return; // can't switch orientation for square screens
+        }
+
+        // After orientation change, the text should still be loaded properly
+        activity = LoaderActivity.sActivity;
+        assertEquals("Loaded!", activity.textView.getText().toString());
+    }
+
+    /**
+     * When a change is interrupted with stop, the data in the LoaderManager remains stale.
+     */
+    //@Test
+    public void noStaleData() throws Throwable {
+        final LoaderActivity activity = mActivityRule.getActivity();
+        final String[] value = new String[] { "First Value" };
+
+        final CountDownLatch[] loadedLatch = new CountDownLatch[] { new CountDownLatch(1) };
+        final Loader<String>[] loaders = new Loader[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final Loader<String> loader =
+                        activity.getSupportLoaderManager().initLoader(DELAY_LOADER, null,
+                                new LoaderManager.LoaderCallbacks<String>() {
+                                    @Override
+                                    public Loader<String> onCreateLoader(int id, Bundle args) {
+                                        return new AsyncTaskLoader<String>(activity) {
+                                            @Override
+                                            protected void onStopLoading() {
+                                                cancelLoad();
+                                            }
+
+                                            @Override
+                                            public String loadInBackground() {
+                                                SystemClock.sleep(50);
+                                                return value[0];
+                                            }
+
+                                            @Override
+                                            protected void onStartLoading() {
+                                                if (takeContentChanged()) {
+                                                    forceLoad();
+                                                }
+                                                super.onStartLoading();
+                                            }
+                                        };
+                                    }
+
+                                    @Override
+                                    public void onLoadFinished(Loader<String> loader, String data) {
+                                        activity.textViewB.setText(data);
+                                        loadedLatch[0].countDown();
+                                    }
+
+                                    @Override
+                                    public void onLoaderReset(Loader<String> loader) {
+                                    }
+                                });
+                loader.forceLoad();
+                loaders[0] = loader;
+            }
+        });
+
+        assertTrue(loadedLatch[0].await(1, TimeUnit.SECONDS));
+        assertEquals("First Value", activity.textViewB.getText().toString());
+
+        loadedLatch[0] = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                value[0] = "Second Value";
+                loaders[0].onContentChanged();
+                loaders[0].stopLoading();
+            }
+        });
+
+        // Since the loader was stopped (and canceled), it shouldn't notify the change
+        assertFalse(loadedLatch[0].await(300, TimeUnit.MILLISECONDS));
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                loaders[0].startLoading();
+            }
+        });
+
+        // Since the loader was stopped (and canceled), it shouldn't notify the change
+        assertTrue(loadedLatch[0].await(1, TimeUnit.SECONDS));
+        assertEquals("Second Value", activity.textViewB.getText().toString());
+    }
+
+    private boolean switchOrientation() throws InterruptedException {
+        LoaderActivity activity = LoaderActivity.sActivity;
+
+        int currentOrientation = activity.getResources().getConfiguration().orientation;
+
+        int nextOrientation;
+        int expectedOrientation;
+        if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+            nextOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+            expectedOrientation = Configuration.ORIENTATION_PORTRAIT;
+        } else if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
+            nextOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+            expectedOrientation = Configuration.ORIENTATION_LANDSCAPE;
+        } else {
+            return false; // Don't know what to do with square or unknown orientations
+        }
+
+        // Now switch the orientation
+        LoaderActivity.sResumed = new CountDownLatch(1);
+        LoaderActivity.sDestroyed = new CountDownLatch(1);
+
+        activity.setRequestedOrientation(nextOrientation);
+        assertTrue(LoaderActivity.sResumed.await(1, TimeUnit.SECONDS));
+        assertTrue(LoaderActivity.sDestroyed.await(1, TimeUnit.SECONDS));
+
+        int switchedOrientation =
+                LoaderActivity.sActivity.getResources().getConfiguration().orientation;
+        Assert.assertEquals(expectedOrientation, switchedOrientation);
+        return true;
+    }
+
+
+    public static class LoaderFragment extends Fragment {
+        private static final int LOADER_ID = 1;
+        private final LoaderManager.LoaderCallbacks<Boolean> mLoaderCallbacks =
+                new LoaderManager.LoaderCallbacks<Boolean>() {
+                    @Override
+                    public Loader<Boolean> onCreateLoader(int id, Bundle args) {
+                        return new DummyLoader(getContext());
+                    }
+
+                    @Override
+                    public void onLoadFinished(Loader<Boolean> loader, Boolean data) {
+
+                    }
+
+                    @Override
+                    public void onLoaderReset(Loader<Boolean> loader) {
+
+                    }
+                };
+
+        @Override
+        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+            super.onActivityCreated(savedInstanceState);
+
+            getLoaderManager().initLoader(LOADER_ID, null, mLoaderCallbacks);
+        }
+    }
+
+    static class DummyLoader extends Loader<Boolean> {
+        DummyLoader(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onStartLoading() {
+            deliverResult(true);
+        }
+    }
+}
diff --git a/fragment/tests/java/android/support/v4/app/test/LoaderActivity.java b/fragment/tests/java/android/support/v4/app/test/LoaderActivity.java
new file mode 100644
index 0000000..77a71f7
--- /dev/null
+++ b/fragment/tests/java/android/support/v4/app/test/LoaderActivity.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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.v4.app.test;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.fragment.test.R;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.AsyncTaskLoader;
+import android.support.v4.content.Loader;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.concurrent.CountDownLatch;
+
+public class LoaderActivity extends FragmentActivity {
+    // These must be cleared after each test using clearState()
+    public static LoaderActivity sActivity;
+    public static CountDownLatch sResumed;
+    public static CountDownLatch sDestroyed;
+
+    public TextView textView;
+    public TextView textViewB;
+
+    public static void clearState() {
+        sActivity = null;
+        sResumed = null;
+        sDestroyed = null;
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        sActivity = this;
+
+        setContentView(R.layout.fragment_a);
+        textView = (TextView) findViewById(R.id.textA);
+        ViewGroup container = (ViewGroup) textView.getParent();
+        textViewB = new TextView(this);
+        textViewB.setId(R.id.textB);
+        container.addView(textViewB);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        getSupportLoaderManager().initLoader(0, null, new TextLoaderCallback());
+        if (sResumed != null) {
+            sResumed.countDown();
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (sDestroyed != null) {
+            sDestroyed.countDown();
+        }
+    }
+
+    class TextLoaderCallback implements LoaderManager.LoaderCallbacks<String> {
+        @Override
+        public Loader<String> onCreateLoader(int id, Bundle args) {
+            return new TextLoader(LoaderActivity.this);
+        }
+
+        @Override
+        public void onLoadFinished(Loader<String> loader, String data) {
+            textView.setText(data);
+        }
+
+        @Override
+        public void onLoaderReset(Loader<String> loader) {
+        }
+    }
+
+    static class TextLoader extends AsyncTaskLoader<String> {
+        TextLoader(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onStartLoading() {
+            forceLoad();
+        }
+
+        @Override
+        public String loadInBackground() {
+            return "Loaded!";
+        }
+    }
+}
diff --git a/gradlew b/gradlew
index 98b9f82..4c2ef38 100755
--- a/gradlew
+++ b/gradlew
@@ -62,7 +62,7 @@
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
 # Pick the correct fullsdk for this OS.
-if [ darwin ]; then
+if [ $darwin == "true" ]; then
     plat="darwin"
 else
     plat="linux"
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java
index 12b0383..c8c6fa1 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java
@@ -21,7 +21,6 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.graphics.drawable.TintAwareDrawable;
 import android.util.AttributeSet;
diff --git a/instantvideo/tests/src/android/support/media/instantvideo/preload/InstantVideoPreloadManagerTest.java b/instantvideo/tests/src/android/support/media/instantvideo/preload/InstantVideoPreloadManagerTest.java
index d50ece8..7b59d1d 100644
--- a/instantvideo/tests/src/android/support/media/instantvideo/preload/InstantVideoPreloadManagerTest.java
+++ b/instantvideo/tests/src/android/support/media/instantvideo/preload/InstantVideoPreloadManagerTest.java
@@ -15,6 +15,9 @@
  */
 package android.support.media.instantvideo.preload;
 
+import static android.support.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.when;
 
@@ -22,8 +25,12 @@
 import android.support.media.instantvideo.preload.InstantVideoPreloadManager.VideoPreloader;
 import android.support.media.instantvideo.preload.InstantVideoPreloadManager.VideoPreloaderFactory;
 import android.support.test.filters.SmallTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -31,43 +38,47 @@
  * Tests for IntentVideoPreloadManager.
  */
 @SmallTest
-public class InstantVideoPreloadManagerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class InstantVideoPreloadManagerTest {
     private static final Uri PRELOAD_VIDEO_URI_1 = Uri.parse("http://test/test1.mp4");
     private static final Uri PRELOAD_VIDEO_URI_2 = Uri.parse("http://test/test2.mp4");
 
     private InstantVideoPreloadManager mPreloadManager;
-    @Mock private VideoPreloaderFactory mMockVideoPreloaderFactory;
-    @Mock private VideoPreloader mMockVideoPreloader;
+    @Mock
+    private VideoPreloaderFactory mMockVideoPreloaderFactory;
+    @Mock
+    private VideoPreloader mMockVideoPreloader;
 
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mMockVideoPreloaderFactory.createVideoPreloader(any(Uri.class)))
                 .thenReturn(mMockVideoPreloader);
         mPreloadManager = new InstantVideoPreloadManager(getContext(), mMockVideoPreloaderFactory);
     }
 
-    @Override
-    public void tearDown() throws Exception {
+    @After
+    public void tearDown() {
         mPreloadManager.clearCache();
-        super.tearDown();
     }
 
-    public void testPreload() {
+    @Test
+    public void preload() {
         mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
         assertCacheSize(1);
         mPreloadManager.preload(PRELOAD_VIDEO_URI_2);
         assertCacheSize(2);
     }
 
-    public void testPreload_duplicate() {
+    @Test
+    public void preload_duplicate() {
         mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
         mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
         assertCacheSize(1);
     }
 
-    public void testMaxPreloadVideoCount() {
+    @Test
+    public void setMaxPreloadVideoCount() {
         mPreloadManager.setMaxPreloadVideoCount(1);
         mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
         assertCacheSize(1);
@@ -75,7 +86,8 @@
         assertCacheSize(1);
     }
 
-    public void testClearCache() {
+    @Test
+    public void clearCache() {
         mPreloadManager.preload(PRELOAD_VIDEO_URI_1);
         mPreloadManager.preload(PRELOAD_VIDEO_URI_2);
         mPreloadManager.clearCache();
diff --git a/media-compat/api26/android/support/v4/media/session/MediaControllerCompatApi26.java b/media-compat/api26/android/support/v4/media/session/MediaControllerCompatApi26.java
index 33829e7..34ed628 100644
--- a/media-compat/api26/android/support/v4/media/session/MediaControllerCompatApi26.java
+++ b/media-compat/api26/android/support/v4/media/session/MediaControllerCompatApi26.java
@@ -16,8 +16,9 @@
 
 package android.support.v4.media.session;
 
-import android.support.annotation.RequiresApi;
+import android.media.MediaDescription;
 import android.media.session.MediaController;
+import android.support.annotation.RequiresApi;
 
 @RequiresApi(26)
 class MediaControllerCompatApi26 {
@@ -33,6 +34,22 @@
         return ((MediaController) controllerObj).isShuffleModeEnabled();
     }
 
+    public static void addQueueItem(Object controllerObj, Object descriptionObj) {
+        ((MediaController) controllerObj).addQueueItem((MediaDescription) descriptionObj);
+    }
+
+    public static void addQueueItem(Object controllerObj, Object descriptionObj, int index) {
+        ((MediaController) controllerObj).addQueueItem((MediaDescription) descriptionObj, index);
+    }
+
+    public static void removeQueueItem(Object controllerObj, Object descriptionObj) {
+        ((MediaController) controllerObj).removeQueueItem((MediaDescription) descriptionObj);
+    }
+
+    public static void removeQueueItemAt(Object controllerObj, int index) {
+        ((MediaController) controllerObj).removeQueueItemAt(index);
+    }
+
     public static class TransportControls extends MediaControllerCompatApi23.TransportControls {
         public static void setRepeatMode(Object controlsObj, int repeatMode) {
             ((MediaController.TransportControls) controlsObj).setRepeatMode(repeatMode);
diff --git a/media-compat/api26/android/support/v4/media/session/MediaSessionCompatApi26.java b/media-compat/api26/android/support/v4/media/session/MediaSessionCompatApi26.java
index 6d7ba4f..8289702 100644
--- a/media-compat/api26/android/support/v4/media/session/MediaSessionCompatApi26.java
+++ b/media-compat/api26/android/support/v4/media/session/MediaSessionCompatApi26.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.media.session;
 
+import android.media.MediaDescription;
 import android.media.session.MediaSession;
 import android.support.annotation.RequiresApi;
 
@@ -37,6 +38,10 @@
     public interface Callback extends MediaSessionCompatApi24.Callback {
         void onSetRepeatMode(int repeatMode);
         void onSetShuffleModeEnabled(boolean enabled);
+        void onAddQueueItem(Object descriptionObject);
+        void onAddQueueItem(Object descriptionObject, int index);
+        void onRemoveQueueItem(Object descriptionObject);
+        void onRemoveQueueItemAt(int index);
     }
 
     static class CallbackProxy<T extends Callback>
@@ -54,5 +59,25 @@
         public void onSetShuffleModeEnabled(boolean enabled) {
             mCallback.onSetShuffleModeEnabled(enabled);
         }
+
+        @Override
+        public void onAddQueueItem(MediaDescription description) {
+            mCallback.onAddQueueItem(description);
+        }
+
+        @Override
+        public void onAddQueueItem(MediaDescription description, int index) {
+            mCallback.onAddQueueItem(description, index);
+        }
+
+        @Override
+        public void onRemoveQueueItem(MediaDescription description) {
+            mCallback.onRemoveQueueItem(description);
+        }
+
+        @Override
+        public void onRemoveQueueItemAt(int index) {
+            mCallback.onRemoveQueueItemAt(index);
+        }
     }
 }
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index 6379429..355ee1a 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -14,6 +14,7 @@
     androidTestCompile libs.mockito_core
     androidTestCompile libs.dexmaker
     androidTestCompile libs.dexmaker_mockito
+    androidTestCompile project(':support-testutils')
 }
 
 android {
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
index 24ec335..be9c1de 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
@@ -38,6 +38,7 @@
 import static android.support.v4.media.MediaBrowserProtocol.DATA_SEARCH_QUERY;
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_CLIENT_VERSION;
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_MESSENGER_BINDER;
+import static android.support.v4.media.MediaBrowserProtocol.EXTRA_SESSION_BINDER;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT_FAILED;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_LOAD_CHILDREN;
@@ -63,6 +64,7 @@
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.support.v4.app.BundleCompat;
+import android.support.v4.media.session.IMediaSession;
 import android.support.v4.media.session.MediaControllerCompat.TransportControls;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.os.BuildCompat;
@@ -340,6 +342,7 @@
      * @param extras The bundle of service-specific arguments to send to the media browser service.
      *            The contents of this bundle may affect the search result.
      * @param callback The callback to receive the search result. Must be non-null.
+     * @throws IllegalStateException if the browser is not connected to the media browser service.
      */
     public void search(@NonNull final String query, final Bundle extras,
             @NonNull SearchCallback callback) {
@@ -671,7 +674,7 @@
         }
 
         private void setSubscription(Subscription subscription) {
-            mSubscriptionRef = new WeakReference(subscription);
+            mSubscriptionRef = new WeakReference<>(subscription);
         }
 
         private class StubApi21 implements MediaBrowserCompatApi21.SubscriptionCallback {
@@ -808,8 +811,10 @@
     public abstract static class SearchCallback {
         final Object mSearchCallbackObj;
 
+        @SuppressLint("NewApi")
         public SearchCallback() {
-            if (Build.VERSION.SDK_INT >= 26 || BuildCompat.isAtLeastO()) {
+            if (BuildCompat.isAtLeastO()) {
+                //noinspection AndroidLintNewApi
                 mSearchCallbackObj = MediaBrowserCompatApi26.createSearchCallback(new StubApi26());
             } else {
                 mSearchCallbackObj = null;
@@ -1150,7 +1155,7 @@
             try {
                 mServiceBinderWrapper.getMediaItem(mediaId, receiver, mCallbacksMessenger);
             } catch (RemoteException e) {
-                Log.i(TAG, "Remote error getting media item.");
+                Log.i(TAG, "Remote error getting media item: " + mediaId);
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
@@ -1164,14 +1169,8 @@
         public void search(@NonNull final String query, final Bundle extras,
                 @NonNull final SearchCallback callback) {
             if (!isConnected()) {
-                Log.i(TAG, "Not connected, unable to search.");
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        callback.onError(query, extras);
-                    }
-                });
-                return;
+                throw new IllegalStateException("search() called while not connected"
+                        + " (state=" + getStateLabel(mState) + ")");
             }
 
             ResultReceiver receiver = new SearchResultReceiver(query, extras, callback, mHandler);
@@ -1465,6 +1464,7 @@
 
         protected ServiceBinderWrapper mServiceBinderWrapper;
         protected Messenger mCallbacksMessenger;
+        private MediaSessionCompat.Token mMediaSessionToken;
 
         public MediaBrowserImplApi21(Context context, ComponentName serviceComponent,
                 ConnectionCallback callback, Bundle rootHints) {
@@ -1526,8 +1526,11 @@
         @NonNull
         @Override
         public MediaSessionCompat.Token getSessionToken() {
-            return MediaSessionCompat.Token.fromToken(
-                    MediaBrowserCompatApi21.getSessionToken(mBrowserObj));
+            if (mMediaSessionToken == null) {
+                mMediaSessionToken = MediaSessionCompat.Token.fromToken(
+                        MediaBrowserCompatApi21.getSessionToken(mBrowserObj));
+            }
+            return mMediaSessionToken;
         }
 
         @Override
@@ -1660,14 +1663,7 @@
         public void search(@NonNull final String query, final Bundle extras,
                 @NonNull final SearchCallback callback) {
             if (!isConnected()) {
-                Log.i(TAG, "Not connected, unable to search.");
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        callback.onError(query, extras);
-                    }
-                });
-                return;
+                throw new IllegalStateException("search() called while not connected");
             }
             if (mServiceBinderWrapper == null) {
                 Log.i(TAG, "The connected service doesn't support search.");
@@ -1712,12 +1708,19 @@
                     Log.i(TAG, "Remote error registering client messenger." );
                 }
             }
+            IMediaSession sessionToken = (IMediaSession) BundleCompat.getBinder(
+                    extras, EXTRA_SESSION_BINDER);
+            if (sessionToken != null) {
+                mMediaSessionToken = MediaSessionCompat.Token.fromToken(
+                        MediaBrowserCompatApi21.getSessionToken(mBrowserObj), sessionToken);
+            }
         }
 
         @Override
         public void onConnectionSuspended() {
             mServiceBinderWrapper = null;
             mCallbacksMessenger = null;
+            mMediaSessionToken = null;
             mHandler.setCallbacksMessenger(null);
         }
 
@@ -1831,8 +1834,8 @@
         private final List<Bundle> mOptionsList;
 
         public Subscription() {
-            mCallbacks = new ArrayList();
-            mOptionsList = new ArrayList();
+            mCallbacks = new ArrayList<>();
+            mOptionsList = new ArrayList<>();
         }
 
         public boolean isEmpty() {
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java b/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java
index 2401d09..b90dc05 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java
@@ -35,6 +35,7 @@
     public static final String EXTRA_CLIENT_VERSION = "extra_client_version";
     public static final String EXTRA_SERVICE_VERSION = "extra_service_version";
     public static final String EXTRA_MESSENGER_BINDER = "extra_messenger";
+    public static final String EXTRA_SESSION_BINDER = "extra_session_binder";
 
     /**
      * MediaBrowserCompat will check the version of the connected MediaBrowserServiceCompat,
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
index c94f74c..9ade9cf 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -39,6 +39,7 @@
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_CLIENT_VERSION;
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_MESSENGER_BINDER;
 import static android.support.v4.media.MediaBrowserProtocol.EXTRA_SERVICE_VERSION;
+import static android.support.v4.media.MediaBrowserProtocol.EXTRA_SESSION_BINDER;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT_FAILED;
 import static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_LOAD_CHILDREN;
@@ -296,6 +297,8 @@
                 rootExtras = new Bundle();
                 rootExtras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT);
                 BundleCompat.putBinder(rootExtras, EXTRA_MESSENGER_BINDER, mMessenger.getBinder());
+                BundleCompat.putBinder(rootExtras, EXTRA_SESSION_BINDER,
+                        (IBinder) mSession.getExtraBinder());
             }
             BrowserRoot root = MediaBrowserServiceCompat.this.onGetRoot(
                     clientPackageName, clientUid, rootHints);
@@ -537,7 +540,7 @@
         Bundle rootHints;
         ServiceCallbacks callbacks;
         BrowserRoot root;
-        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap();
+        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
 
         ConnectionRecord() {
         }
@@ -1351,8 +1354,9 @@
          * @see #EXTRA_RECENT
          * @see #EXTRA_OFFLINE
          * @see #EXTRA_SUGGESTED
-         * @deprecated Use {@link MediaBrowserCompat#search(String, Bundle,
-         *             MediaBrowserCompat.SearchCallback)} instead.
+         * @deprecated The search functionality is now supported by the methods
+         *             {@link MediaBrowserCompat#search} and {@link #onSearch}. Use those methods
+         *             instead.
          */
         @Deprecated
         public static final String EXTRA_SUGGESTION_KEYWORDS
diff --git a/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl b/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl
index d1d143d..ac0de3d 100644
--- a/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl
+++ b/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl
@@ -39,4 +39,5 @@
     void onVolumeInfoChanged(in ParcelableVolumeInfo info);
     void onRepeatModeChanged(int repeatMode);
     void onShuffleModeChanged(boolean enabled);
+    void onCaptioningEnabledChanged(boolean enabled);
 }
diff --git a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
index 969b803..39cfbe6 100644
--- a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
+++ b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
@@ -34,7 +34,7 @@
  * @hide
  */
 interface IMediaSession {
-    // Next ID: 44
+    // Next ID: 46
     void sendCommand(String command, in Bundle args, in MediaSessionCompat.ResultReceiverWrapper cb) = 0;
     boolean sendMediaButton(in KeyEvent mediaButton) = 1;
     void registerCallbackListener(in IMediaControllerCallback cb) = 2;
@@ -53,6 +53,7 @@
     CharSequence getQueueTitle() = 29;
     Bundle getExtras() = 30;
     int getRatingType() = 31;
+    boolean isCaptioningEnabled() = 44;
     int getRepeatMode() = 36;
     boolean isShuffleModeEnabled() = 37;
     void addQueueItem(in MediaDescriptionCompat description) = 40;
@@ -78,6 +79,7 @@
     void rewind() = 22;
     void seekTo(long pos) = 23;
     void rate(in RatingCompat rating) = 24;
+    void setCaptioningEnabled(boolean enabled) = 45;
     void setRepeatMode(int repeatMode) = 38;
     void setShuffleModeEnabled(boolean shuffleMode) = 39;
     void sendCustomAction(String action, in Bundle args) = 25;
diff --git a/media-compat/java/android/support/v4/media/session/MediaButtonReceiver.java b/media-compat/java/android/support/v4/media/session/MediaButtonReceiver.java
index 1e05889..0cd8ff9 100644
--- a/media-compat/java/android/support/v4/media/session/MediaButtonReceiver.java
+++ b/media-compat/java/android/support/v4/media/session/MediaButtonReceiver.java
@@ -17,13 +17,14 @@
 package android.support.v4.media.session;
 
 import android.app.PendingIntent;
-import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.RemoteException;
+import android.support.v4.media.MediaBrowserCompat;
 import android.support.v4.media.MediaBrowserServiceCompat;
 import android.support.v4.media.session.PlaybackStateCompat.MediaKeyAction;
 import android.util.Log;
@@ -45,93 +46,111 @@
  *   &lt;/intent-filter&gt;
  * &lt;/receiver&gt;
  * </pre>
- * This class assumes you have a {@link Service} in your app that controls
+ * This class assumes you have a media browser service implementation in your app that controls
  * media playback via a {@link MediaSessionCompat} - all {@link Intent}s received by
- * the MediaButtonReceiver will be forwarded to that service.
+ * the MediaButtonReceiver will be forwarded to the {@link MediaSessionCompat}
+ * associated with the token set via {@link MediaBrowserServiceCompat#setSessionToken}.
  * <p />
- * First priority is given to a {@link Service}
- * that includes an intent filter that handles {@link Intent#ACTION_MEDIA_BUTTON}:
- * <pre>
- * &lt;service android:name="com.example.android.MediaPlaybackService" &gt;
- *   &lt;intent-filter&gt;
- *     &lt;action android:name="android.intent.action.MEDIA_BUTTON" /&gt;
- *   &lt;/intent-filter&gt;
- * &lt;/service&gt;
- * </pre>
- *
- * If such a {@link Service} is not found, MediaButtonReceiver will attempt to
- * find a media browser service implementation.
- * If neither is available or more than one valid service/media browser service is found, an
+ * If more than one valid media browser service is found, an
  * {@link IllegalStateException} will be thrown.
- * <p />
- * Events can then be handled in {@link Service#onStartCommand(Intent, int, int)} by calling
- * {@link MediaButtonReceiver#handleIntent(MediaSessionCompat, Intent)}, passing in
- * your current {@link MediaSessionCompat}:
- * <pre>
- * private MediaSessionCompat mMediaSessionCompat = ...;
- *
- * public int onStartCommand(Intent intent, int flags, int startId) {
- *   MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent);
- *   return super.onStartCommand(intent, flags, startId);
- * }
- * </pre>
- *
- * This ensures that the correct callbacks to {@link MediaSessionCompat.Callback}
- * will be triggered based on the incoming {@link KeyEvent}.
  */
 public class MediaButtonReceiver extends BroadcastReceiver {
     private static final String TAG = "MediaButtonReceiver";
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        Intent queryIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        if (intent == null
+                || !Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
+                || !intent.hasExtra(Intent.EXTRA_KEY_EVENT)) {
+            Log.d(TAG, "Ignore unsupported intent: " + intent);
+            return;
+        }
+        Intent queryIntent = new Intent(MediaBrowserServiceCompat.SERVICE_INTERFACE);
         queryIntent.setPackage(context.getPackageName());
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> resolveInfos = pm.queryIntentServices(queryIntent, 0);
         if (resolveInfos.isEmpty()) {
-            // Fall back to looking for any available media browser service
-            queryIntent.setAction(MediaBrowserServiceCompat.SERVICE_INTERFACE);
-            resolveInfos = pm.queryIntentServices(queryIntent, 0);
-        }
-        if (resolveInfos.isEmpty()) {
-            throw new IllegalStateException("Could not find any Service that handles " +
-                    Intent.ACTION_MEDIA_BUTTON + " or a media browser service implementation");
+            throw new IllegalStateException("Could not find any "
+                    + "media browser service implementation");
         } else if (resolveInfos.size() != 1) {
-            throw new IllegalStateException("Expected 1 Service that handles " +
-                    queryIntent.getAction() + ", found " + resolveInfos.size() );
+            throw new IllegalStateException("Expected 1 media browser service implementation"
+                    + ", found " + resolveInfos.size());
         }
         ResolveInfo resolveInfo = resolveInfos.get(0);
         ComponentName componentName = new ComponentName(resolveInfo.serviceInfo.packageName,
                 resolveInfo.serviceInfo.name);
-        intent.setComponent(componentName);
-        context.startService(intent);
+        PendingResult pendingResult = goAsync();
+        Context applicationContext = context.getApplicationContext();
+        MediaButtonConnectionCallback connectionCallback =
+                new MediaButtonConnectionCallback(applicationContext, intent, pendingResult);
+        MediaBrowserCompat mediaBrowser = new MediaBrowserCompat(applicationContext,
+                componentName, connectionCallback, null);
+        connectionCallback.setMediaBrowser(mediaBrowser);
+        mediaBrowser.connect();
     }
 
+    private static class MediaButtonConnectionCallback extends
+            MediaBrowserCompat.ConnectionCallback {
+        private final Context mContext;
+        private final Intent mIntent;
+        private final PendingResult mPendingResult;
+
+        private MediaBrowserCompat mMediaBrowser;
+
+        MediaButtonConnectionCallback(Context context, Intent intent, PendingResult pendingResult) {
+            mContext = context;
+            mIntent = intent;
+            mPendingResult = pendingResult;
+        }
+
+        void setMediaBrowser(MediaBrowserCompat mediaBrowser) {
+            mMediaBrowser = mediaBrowser;
+        }
+
+        @Override
+        public void onConnected() {
+            try {
+                MediaControllerCompat mediaController = new MediaControllerCompat(mContext,
+                        mMediaBrowser.getSessionToken());
+                KeyEvent ke = mIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+                mediaController.dispatchMediaButtonEvent(ke);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to create a media controller", e);
+            }
+            finish();
+        }
+
+        @Override
+        public void onConnectionSuspended() {
+            finish();
+        }
+
+        @Override
+        public void onConnectionFailed() {
+            finish();
+        }
+
+        private void finish() {
+            mMediaBrowser.disconnect();
+            mPendingResult.finish();
+        }
+    };
+
     /**
      * Extracts any available {@link KeyEvent} from an {@link Intent#ACTION_MEDIA_BUTTON}
      * intent, passing it onto the {@link MediaSessionCompat} using
      * {@link MediaControllerCompat#dispatchMediaButtonEvent(KeyEvent)}, which in turn
      * will trigger callbacks to the {@link MediaSessionCompat.Callback} registered via
      * {@link MediaSessionCompat#setCallback(MediaSessionCompat.Callback)}.
-     * <p />
-     * The returned {@link KeyEvent} is non-null if any {@link KeyEvent} is found and can
-     * be used if any additional processing is needed beyond what is done in the
-     * {@link MediaSessionCompat.Callback}. An example of is to prevent redelivery of a
-     * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE} Intent in the case of the Service being
-     * restarted (which, by default, will redeliver the last received Intent).
-     * <pre>
-     * KeyEvent keyEvent = MediaButtonReceiver.handleIntent(mediaSession, intent);
-     * if (keyEvent != null && keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
-     *   Intent emptyIntent = new Intent(intent);
-     *   emptyIntent.setAction("");
-     *   startService(emptyIntent);
-     * }
-     * </pre>
      * @param mediaSessionCompat A {@link MediaSessionCompat} that has a
      *            {@link MediaSessionCompat.Callback} set.
      * @param intent The intent to parse.
      * @return The extracted {@link KeyEvent} if found, or null.
+     * @deprecated This call is no longer required. MediaButtonReceiver automatically
+     *            forwards the {@link KeyEvent} to the {@link MediaSessionCompat} associated with
+     *            the token set via {@link MediaBrowserServiceCompat#setSessionToken}.
      */
+    @Deprecated
     public static KeyEvent handleIntent(MediaSessionCompat mediaSessionCompat, Intent intent) {
         if (mediaSessionCompat == null || intent == null
                 || !Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
diff --git a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
index 3e28274..402df13 100644
--- a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.media.session;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -29,7 +30,6 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.support.annotation.RequiresApi;
-import android.support.annotation.VisibleForTesting;
 import android.support.v4.app.BundleCompat;
 import android.support.v4.app.SupportActivity;
 import android.support.v4.media.MediaDescriptionCompat;
@@ -38,6 +38,7 @@
 import android.support.v4.media.VolumeProviderCompat;
 import android.support.v4.media.session.MediaSessionCompat.QueueItem;
 import android.support.v4.media.session.PlaybackStateCompat.CustomAction;
+import android.support.v4.os.BuildCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -159,13 +160,14 @@
      *
      * @param session The session to be controlled.
      */
+    @SuppressLint("NewApi")
     public MediaControllerCompat(Context context, MediaSessionCompat session) {
         if (session == null) {
             throw new IllegalArgumentException("session must not be null");
         }
         mToken = session.getSessionToken();
 
-        if (android.os.Build.VERSION.SDK_INT >= 26) {
+        if (BuildCompat.isAtLeastO()) {
             mImpl = new MediaControllerImplApi26(context, session);
         } else if (android.os.Build.VERSION.SDK_INT >= 24) {
             mImpl = new MediaControllerImplApi24(context, session);
@@ -185,6 +187,7 @@
      * @param sessionToken The token of the session to be controlled.
      * @throws RemoteException if the session is not accessible.
      */
+    @SuppressLint("NewApi")
     public MediaControllerCompat(Context context, MediaSessionCompat.Token sessionToken)
             throws RemoteException {
         if (sessionToken == null) {
@@ -192,7 +195,7 @@
         }
         mToken = sessionToken;
 
-        if (android.os.Build.VERSION.SDK_INT >= 26) {
+        if (BuildCompat.isAtLeastO()) {
             mImpl = new MediaControllerImplApi26(context, sessionToken);
         } else if (android.os.Build.VERSION.SDK_INT >= 24) {
             mImpl = new MediaControllerImplApi24(context, sessionToken);
@@ -258,11 +261,14 @@
 
     /**
      * Add a queue item from the given {@code description} at the end of the play queue
-     * of this session. Not all sessions may support this.
+     * of this session. Not all sessions may support this. To know whether the session supports
+     * this, get the session's flags with {@link #getFlags()} and check that the flag
+     * {@link MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS} is set.
      *
      * @param description The {@link MediaDescriptionCompat} for creating the
      *            {@link MediaSessionCompat.QueueItem} to be inserted.
      * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see #getFlags()
      * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
      */
     public void addQueueItem(MediaDescriptionCompat description) {
@@ -273,13 +279,16 @@
      * Add a queue item from the given {@code description} at the specified position
      * in the play queue of this session. Shifts the queue item currently at that position
      * (if any) and any subsequent queue items to the right (adds one to their indices).
-     * Not all sessions may support this.
+     * Not all sessions may support this. To know whether the session supports this,
+     * get the session's flags with {@link #getFlags()} and check that the flag
+     * {@link MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS} is set.
      *
      * @param description The {@link MediaDescriptionCompat} for creating the
      *            {@link MediaSessionCompat.QueueItem} to be inserted.
      * @param index The index at which the created {@link MediaSessionCompat.QueueItem}
      *            is to be inserted.
      * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see #getFlags()
      * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
      */
     public void addQueueItem(MediaDescriptionCompat description, int index) {
@@ -289,11 +298,14 @@
     /**
      * Remove the first occurrence of the specified {@link MediaSessionCompat.QueueItem}
      * with the given {@link MediaDescriptionCompat description} in the play queue of the
-     * associated session. Not all sessions may support this.
+     * associated session. Not all sessions may support this. To know whether the session supports
+     * this, get the session's flags with {@link #getFlags()} and check that the flag
+     * {@link MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS} is set.
      *
      * @param description The {@link MediaDescriptionCompat} for denoting the
      *            {@link MediaSessionCompat.QueueItem} to be removed.
      * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see #getFlags()
      * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
      */
     public void removeQueueItem(MediaDescriptionCompat description) {
@@ -302,10 +314,13 @@
 
     /**
      * Remove an queue item at the specified position in the play queue
-     * of this session. Not all sessions may support this.
+     * of this session. Not all sessions may support this. To know whether the session supports
+     * this, get the session's flags with {@link #getFlags()} and check that the flag
+     * {@link MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS} is set.
      *
      * @param index The index of the element to be removed.
      * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see #getFlags()
      * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
      */
     public void removeQueueItemAt(int index) {
@@ -345,6 +360,15 @@
     }
 
     /**
+     * Return whether captioning is enabled for this session.
+     *
+     * @return {@code true} if captioning is enabled, {@code false} if disabled or not set.
+     */
+    public boolean isCaptioningEnabled() {
+        return mImpl.isCaptioningEnabled();
+    }
+
+    /**
      * Get the repeat mode for this session.
      *
      * @return The latest repeat mode set to the session, or
@@ -499,15 +523,6 @@
         return mImpl.getPackageName();
     }
 
-    @VisibleForTesting
-    boolean isExtraBinderReady() {
-        if (mImpl instanceof MediaControllerImplApi21) {
-            return ((MediaControllerImplApi21) mImpl).mExtraBinder != null;
-        } else {
-            return false;
-        }
-    }
-
     /**
      * Gets the underlying framework
      * {@link android.media.session.MediaController} object.
@@ -533,8 +548,9 @@
 
         boolean mRegistered = false;
 
+        @SuppressLint("NewApi")
         public Callback() {
-            if (android.os.Build.VERSION.SDK_INT >= 26) {
+            if (BuildCompat.isAtLeastO()) {
                 mCallbackObj = MediaControllerCompatApi26.createCallback(new StubApi26());
             } else if (android.os.Build.VERSION.SDK_INT >= 21) {
                 mCallbackObj = MediaControllerCompatApi21.createCallback(new StubApi21());
@@ -617,6 +633,14 @@
         }
 
         /**
+         * Override to handle changes to the captioning enabled status.
+         *
+         * @param enabled {@code true} if captioning is enabled, {@code false} otherwise.
+         */
+        public void onCaptioningEnabledChanged(boolean enabled) {
+        }
+
+        /**
          * Override to handle changes to the repeat mode.
          *
          * @param repeatMode The repeat mode. It should be one of followings:
@@ -751,6 +775,11 @@
             }
 
             @Override
+            public void onCaptioningEnabledChanged(boolean enabled) throws RemoteException {
+                mHandler.post(MessageHandler.MSG_UPDATE_CAPTIONING_ENABLED, enabled, null);
+            }
+
+            @Override
             public void onRepeatModeChanged(int repeatMode) throws RemoteException {
                 mHandler.post(MessageHandler.MSG_UPDATE_REPEAT_MODE, repeatMode, null);
             }
@@ -787,6 +816,7 @@
             private static final int MSG_DESTROYED = 8;
             private static final int MSG_UPDATE_REPEAT_MODE = 9;
             private static final int MSG_UPDATE_SHUFFLE_MODE = 10;
+            private static final int MSG_UPDATE_CAPTIONING_ENABLED = 11;
 
             public MessageHandler(Looper looper) {
                 super(looper);
@@ -813,6 +843,9 @@
                     case MSG_UPDATE_QUEUE_TITLE:
                         onQueueTitleChanged((CharSequence) msg.obj);
                         break;
+                    case MSG_UPDATE_CAPTIONING_ENABLED:
+                        onCaptioningEnabledChanged((boolean) msg.obj);
+                        break;
                     case MSG_UPDATE_REPEAT_MODE:
                         onRepeatModeChanged((int) msg.obj);
                         break;
@@ -994,6 +1027,13 @@
         public abstract void setRating(RatingCompat rating);
 
         /**
+         * Enable/disable captioning for this session.
+         *
+         * @param enabled {@code true} to enable captioning, {@code false} to disable.
+         */
+        public abstract void setCaptioningEnabled(boolean enabled);
+
+        /**
          * Set the repeat mode for this session.
          *
          * @param repeatMode The repeat mode. Must be one of the followings:
@@ -1026,6 +1066,8 @@
          *
          * @see #sendCustomAction(PlaybackStateCompat.CustomAction action,
          *      Bundle args)
+         * @see MediaSessionCompat#ACTION_FLAG_AS_INAPPROPRIATE
+         * @see MediaSessionCompat#ACTION_SKIP_AD
          * @param action The action identifier of the
          *            {@link PlaybackStateCompat.CustomAction} as specified by
          *            the {@link MediaSessionCompat}.
@@ -1139,6 +1181,7 @@
         CharSequence getQueueTitle();
         Bundle getExtras();
         int getRatingType();
+        boolean isCaptioningEnabled();
         int getRepeatMode();
         boolean isShuffleModeEnabled();
         long getFlags();
@@ -1154,12 +1197,10 @@
     }
 
     static class MediaControllerImplBase implements MediaControllerImpl {
-        private MediaSessionCompat.Token mToken;
         private IMediaSession mBinder;
         private TransportControls mTransportControls;
 
         public MediaControllerImplBase(MediaSessionCompat.Token token) {
-            mToken = token;
             mBinder = IMediaSession.Stub.asInterface((IBinder) token.getToken());
         }
 
@@ -1333,6 +1374,16 @@
         }
 
         @Override
+        public boolean isCaptioningEnabled() {
+            try {
+                return mBinder.isCaptioningEnabled();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in isCaptioningEnabled.", e);
+            }
+            return false;
+        }
+
+        @Override
         public int getRepeatMode() {
             try {
                 return mBinder.getRepeatMode();
@@ -1590,6 +1641,15 @@
         }
 
         @Override
+        public void setCaptioningEnabled(boolean enabled) {
+            try {
+                mBinder.setCaptioningEnabled(enabled);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in setCaptioningEnabled.", e);
+            }
+        }
+
+        @Override
         public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
             try {
                 mBinder.setRepeatMode(repeatMode);
@@ -1635,7 +1695,10 @@
         public MediaControllerImplApi21(Context context, MediaSessionCompat session) {
             mControllerObj = MediaControllerCompatApi21.fromToken(context,
                     session.getSessionToken().getToken());
-            requestExtraBinder();
+            mExtraBinder = session.getSessionToken().getExtraBinder();
+            if (mExtraBinder == null) {
+                requestExtraBinder();
+            }
         }
 
         public MediaControllerImplApi21(Context context, MediaSessionCompat.Token sessionToken)
@@ -1643,7 +1706,10 @@
             mControllerObj = MediaControllerCompatApi21.fromToken(context,
                     sessionToken.getToken());
             if (mControllerObj == null) throw new RemoteException();
-            requestExtraBinder();
+            mExtraBinder = sessionToken.getExtraBinder();
+            if (mExtraBinder == null) {
+                requestExtraBinder();
+            }
         }
 
         @Override
@@ -1726,6 +1792,11 @@
 
         @Override
         public void addQueueItem(MediaDescriptionCompat description) {
+            long flags = getFlags();
+            if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
             Bundle params = new Bundle();
             params.putParcelable(COMMAND_ARGUMENT_MEDIA_DESCRIPTION, description);
             sendCommand(COMMAND_ADD_QUEUE_ITEM, params, null);
@@ -1733,6 +1804,11 @@
 
         @Override
         public void addQueueItem(MediaDescriptionCompat description, int index) {
+            long flags = getFlags();
+            if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
             Bundle params = new Bundle();
             params.putParcelable(COMMAND_ARGUMENT_MEDIA_DESCRIPTION, description);
             params.putInt(COMMAND_ARGUMENT_INDEX, index);
@@ -1741,6 +1817,11 @@
 
         @Override
         public void removeQueueItem(MediaDescriptionCompat description) {
+            long flags = getFlags();
+            if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
             Bundle params = new Bundle();
             params.putParcelable(COMMAND_ARGUMENT_MEDIA_DESCRIPTION, description);
             sendCommand(COMMAND_REMOVE_QUEUE_ITEM, params, null);
@@ -1748,6 +1829,11 @@
 
         @Override
         public void removeQueueItemAt(int index) {
+            long flags = getFlags();
+            if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
             Bundle params = new Bundle();
             params.putInt(COMMAND_ARGUMENT_INDEX, index);
             sendCommand(COMMAND_REMOVE_QUEUE_ITEM_AT, params, null);
@@ -1776,6 +1862,18 @@
         }
 
         @Override
+        public boolean isCaptioningEnabled() {
+            if (mExtraBinder != null) {
+                try {
+                    return mExtraBinder.isCaptioningEnabled();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Dead object in isCaptioningEnabled.", e);
+                }
+            }
+            return false;
+        }
+
+        @Override
         public int getRepeatMode() {
             if (mExtraBinder != null) {
                 try {
@@ -1845,7 +1943,6 @@
             return mControllerObj;
         }
 
-        // TODO: Handle the case of calling other methods before receiving the extra binder.
         private void requestExtraBinder() {
             sendCommand(COMMAND_GET_EXTRA_BINDER, null,
                     new ExtraBinderRequestResultReceiver(this, new Handler()));
@@ -1945,6 +2042,16 @@
             }
 
             @Override
+            public void onCaptioningEnabledChanged(final boolean enabled) throws RemoteException {
+                mCallback.mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onCaptioningEnabledChanged(enabled);
+                    }
+                });
+            }
+
+            @Override
             public void onRepeatModeChanged(final int repeatMode) throws RemoteException {
                 mCallback.mHandler.post(new Runnable() {
                     @Override
@@ -2061,6 +2168,13 @@
         }
 
         @Override
+        public void setCaptioningEnabled(boolean enabled) {
+            Bundle bundle = new Bundle();
+            bundle.putBoolean(MediaSessionCompat.ACTION_ARGUMENT_CAPTIONING_ENABLED, enabled);
+            sendCustomAction(MediaSessionCompat.ACTION_SET_CAPTIONING_ENABLED, bundle);
+        }
+
+        @Override
         public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
             Bundle bundle = new Bundle();
             bundle.putInt(MediaSessionCompat.ACTION_ARGUMENT_REPEAT_MODE, repeatMode);
@@ -2225,6 +2339,33 @@
         public boolean isShuffleModeEnabled() {
             return MediaControllerCompatApi26.isShuffleModeEnabled(mControllerObj);
         }
+
+        @Override
+        public void addQueueItem(MediaDescriptionCompat description) {
+            MediaControllerCompatApi26.addQueueItem(
+                    mControllerObj,
+                    description == null ? null : description.getMediaDescription());
+        }
+
+        @Override
+        public void addQueueItem(MediaDescriptionCompat description, int index) {
+            MediaControllerCompatApi26.addQueueItem(
+                    mControllerObj,
+                    description == null ? null : description.getMediaDescription(),
+                    index);
+        }
+
+        @Override
+        public void removeQueueItem(MediaDescriptionCompat description) {
+            MediaControllerCompatApi26.removeQueueItem(
+                    mControllerObj,
+                    description == null ? null : description.getMediaDescription());
+        }
+
+        @Override
+        public void removeQueueItemAt(int index) {
+            MediaControllerCompatApi26.removeQueueItemAt(mControllerObj, index);
+        }
     }
 
     @RequiresApi(26)
diff --git a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
index 710de2b..fdea9cf 100644
--- a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -19,6 +19,7 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -52,6 +53,7 @@
 import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.RatingCompat;
 import android.support.v4.media.VolumeProviderCompat;
+import android.support.v4.os.BuildCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.TypedValue;
@@ -126,6 +128,22 @@
     public static final int FLAG_HANDLES_QUEUE_COMMANDS = 1 << 2;
 
     /**
+     * Predefined custom action to flag the media that is currently playing as inappropriate.
+     *
+     * @see Callback#onCustomAction
+     */
+    public static final String ACTION_FLAG_AS_INAPPROPRIATE =
+            "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
+
+    /**
+     * Predefined custom action to skip the advertisement that is currently playing.
+     *
+     * @see Callback#onCustomAction
+     */
+    public static final String ACTION_SKIP_AD =
+            "android.support.v4.media.session.action.SKIP_AD";
+
+    /**
      * Custom action to invoke playFromUri() for the forward compatibility.
      */
     static final String ACTION_PLAY_FROM_URI =
@@ -155,6 +173,12 @@
             "android.support.v4.media.session.action.PREPARE_FROM_URI";
 
     /**
+     * Custom action to invoke setCaptioningEnabled() for the forward compatibility.
+     */
+    static final String ACTION_SET_CAPTIONING_ENABLED =
+            "android.support.v4.media.session.action.SET_CAPTIONING_ENABLED";
+
+    /**
      * Custom action to invoke setRepeatMode() for the forward compatibility.
      */
     static final String ACTION_SET_REPEAT_MODE =
@@ -192,6 +216,13 @@
             "android.support.v4.media.session.action.ARGUMENT_EXTRAS";
 
     /**
+     * Argument for use with {@link #ACTION_SET_CAPTIONING_ENABLED} indicating whether captioning is
+     * enabled.
+     */
+    static final String ACTION_ARGUMENT_CAPTIONING_ENABLED =
+            "android.support.v4.media.session.action.ARGUMENT_CAPTIONING_ENABLED";
+
+    /**
      * Argument for use with {@link #ACTION_SET_REPEAT_MODE} indicating repeat mode.
      */
     static final String ACTION_ARGUMENT_REPEAT_MODE =
@@ -549,6 +580,15 @@
     }
 
     /**
+     * Enable/disable captioning for this session.
+     *
+     * @param enabled {@code true} to enable captioning, {@code false} to disable.
+     */
+    public void setCaptioningEnabled(boolean enabled) {
+        mImpl.setCaptioningEnabled(enabled);
+    }
+
+    /**
      * Set the repeat mode for this session.
      * <p>
      * Note that if this method is not called before, {@link MediaControllerCompat#getRepeatMode}
@@ -695,8 +735,9 @@
         final Object mCallbackObj;
         WeakReference<MediaSessionImpl> mSessionImpl;
 
+        @SuppressLint("NewApi")
         public Callback() {
-            if (android.os.Build.VERSION.SDK_INT >= 26) {
+            if (BuildCompat.isAtLeastO()) {
                 mCallbackObj = MediaSessionCompatApi26.createCallback(new StubApi26());
             } else if (android.os.Build.VERSION.SDK_INT >= 24) {
                 mCallbackObj = MediaSessionCompatApi24.createCallback(new StubApi24());
@@ -864,6 +905,14 @@
         }
 
         /**
+         * Override to handle requests to enable/disable captioning.
+         *
+         * @param enabled {@code true} to enable captioning, {@code false} to disable.
+         */
+        public void onSetCaptioningEnabled(boolean enabled) {
+        }
+
+        /**
          * Override to handle the setting of the repeat mode.
          * <p>
          * You should call {@link #setRepeatMode} before end of this method in order to notify
@@ -898,6 +947,8 @@
          *            {@link PlaybackStateCompat.CustomAction}.
          * @param extras Optional extras specified by the
          *            {@link MediaControllerCompat}.
+         * @see #ACTION_FLAG_AS_INAPPROPRIATE
+         * @see #ACTION_SKIP_AD
          */
         public void onCustomAction(String action, Bundle extras) {
         }
@@ -956,7 +1007,8 @@
                     MediaSessionImplApi21 impl = (MediaSessionImplApi21) mSessionImpl.get();
                     if (impl != null) {
                         Bundle result = new Bundle();
-                        BundleCompat.putBinder(result, EXTRA_BINDER, impl.getExtraSessionBinder());
+                        BundleCompat.putBinder(result, EXTRA_BINDER,
+                                (IBinder) impl.getSessionToken().getExtraBinder());
                         cb.send(0, result);
                     }
                 } else if (command.equals(MediaControllerCompat.COMMAND_ADD_QUEUE_ITEM)) {
@@ -1068,6 +1120,9 @@
                     Uri uri = extras.getParcelable(ACTION_ARGUMENT_URI);
                     Bundle bundle = extras.getBundle(ACTION_ARGUMENT_EXTRAS);
                     Callback.this.onPrepareFromUri(uri, bundle);
+                } else if (action.equals(ACTION_SET_CAPTIONING_ENABLED)) {
+                    boolean enabled = extras.getBoolean(ACTION_ARGUMENT_CAPTIONING_ENABLED);
+                    Callback.this.onSetCaptioningEnabled(enabled);
                 } else if (action.equals(ACTION_SET_REPEAT_MODE)) {
                     int repeatMode = extras.getInt(ACTION_ARGUMENT_REPEAT_MODE);
                     Callback.this.onSetRepeatMode(repeatMode);
@@ -1130,6 +1185,29 @@
             public void onSetShuffleModeEnabled(boolean enabled) {
                 Callback.this.onSetShuffleModeEnabled(enabled);
             }
+
+            @Override
+            public void onAddQueueItem(Object descriptionObject) {
+                Callback.this.onAddQueueItem(
+                        MediaDescriptionCompat.fromMediaDescription(descriptionObject));
+            }
+
+            @Override
+            public void onAddQueueItem(Object descriptionObject, int index) {
+                Callback.this.onAddQueueItem(
+                        MediaDescriptionCompat.fromMediaDescription(descriptionObject), index);
+            }
+
+            @Override
+            public void onRemoveQueueItem(Object descriptionObject) {
+                Callback.this.onRemoveQueueItem(
+                        MediaDescriptionCompat.fromMediaDescription(descriptionObject));
+            }
+
+            @Override
+            public void onRemoveQueueItemAt(int index) {
+                Callback.this.onRemoveQueueItemAt(index);
+            }
         }
     }
 
@@ -1140,9 +1218,15 @@
      */
     public static final class Token implements Parcelable {
         private final Object mInner;
+        private final IMediaSession mExtraBinder;
 
         Token(Object inner) {
+            this(inner, null);
+        }
+
+        Token(Object inner, IMediaSession extraBinder) {
             mInner = inner;
+            mExtraBinder = extraBinder;
         }
 
         /**
@@ -1157,8 +1241,26 @@
          * @return A compat Token for use with {@link MediaControllerCompat}.
          */
         public static Token fromToken(Object token) {
+            return fromToken(token, null);
+        }
+
+        /**
+         * Creates a compat Token from a framework
+         * {@link android.media.session.MediaSession.Token} object, and the extra binder.
+         * <p>
+         * This method is only supported on
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later.
+         * </p>
+         *
+         * @param token The framework token object.
+         * @param extraBinder The extra binder.
+         * @return A compat Token for use with {@link MediaControllerCompat}.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public static Token fromToken(Object token, IMediaSession extraBinder) {
             if (token != null && android.os.Build.VERSION.SDK_INT >= 21) {
-                return new Token(MediaSessionCompatApi21.verifyToken(token));
+                return new Token(MediaSessionCompatApi21.verifyToken(token), extraBinder);
             }
             return null;
         }
@@ -1172,6 +1274,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             if (android.os.Build.VERSION.SDK_INT >= 21) {
                 dest.writeParcelable((Parcelable) mInner, flags);
+                dest.writeStrongBinder((IBinder) mExtraBinder);
             } else {
                 dest.writeStrongBinder((IBinder) mInner);
             }
@@ -1217,23 +1320,33 @@
             return mInner;
         }
 
+        /**
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public IMediaSession getExtraBinder() {
+            return mExtraBinder;
+        }
+
         public static final Parcelable.Creator<Token> CREATOR
                 = new Parcelable.Creator<Token>() {
-            @Override
-            public Token createFromParcel(Parcel in) {
-                Object inner;
-                if (android.os.Build.VERSION.SDK_INT >= 21) {
-                    inner = in.readParcelable(null);
-                } else {
-                    inner = in.readStrongBinder();
-                }
-                return new Token(inner);
-            }
+                    @Override
+                    public Token createFromParcel(Parcel in) {
+                        Object inner;
+                        IMediaSession extraBinder = null;
+                        if (android.os.Build.VERSION.SDK_INT >= 21) {
+                            inner = in.readParcelable(null);
+                            extraBinder = (IMediaSession) in.readStrongBinder();
+                        } else {
+                            inner = in.readStrongBinder();
+                        }
+                        return new Token(inner, extraBinder);
+                    }
 
-            @Override
-            public Token[] newArray(int size) {
-                return new Token[size];
-            }
+                    @Override
+                    public Token[] newArray(int size) {
+                        return new Token[size];
+                    }
         };
     }
 
@@ -1468,6 +1581,7 @@
         void setQueueTitle(CharSequence title);
 
         void setRatingType(@RatingCompat.Style int type);
+        void setCaptioningEnabled(boolean enabled);
         void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode);
         void setShuffleModeEnabled(boolean enabled);
         void setExtras(Bundle extras);
@@ -1512,6 +1626,7 @@
         List<QueueItem> mQueue;
         CharSequence mQueueTitle;
         @RatingCompat.Style int mRatingType;
+        boolean mCaptioningEnabled;
         @PlaybackStateCompat.RepeatMode int mRepeatMode;
         boolean mShuffleModeEnabled;
         Bundle mExtras;
@@ -1889,6 +2004,14 @@
         }
 
         @Override
+        public void setCaptioningEnabled(boolean enabled) {
+            if (mCaptioningEnabled != enabled) {
+                mCaptioningEnabled = enabled;
+                sendCaptioningEnabled(enabled);
+            }
+        }
+
+        @Override
         public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
             if (mRepeatMode != repeatMode) {
                 mRepeatMode = repeatMode;
@@ -2108,6 +2231,18 @@
             mControllerCallbacks.finishBroadcast();
         }
 
+        private void sendCaptioningEnabled(boolean enabled) {
+            int size = mControllerCallbacks.beginBroadcast();
+            for (int i = size - 1; i >= 0; i--) {
+                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
+                try {
+                    cb.onCaptioningEnabledChanged(enabled);
+                } catch (RemoteException e) {
+                }
+            }
+            mControllerCallbacks.finishBroadcast();
+        }
+
         private void sendRepeatMode(int repeatMode) {
             int size = mControllerCallbacks.beginBroadcast();
             for (int i = size - 1; i >= 0; i--) {
@@ -2328,6 +2463,11 @@
             }
 
             @Override
+            public void setCaptioningEnabled(boolean enabled) throws RemoteException {
+                postToHandler(MessageHandler.MSG_SET_CAPTIONING_ENABLED, enabled);
+            }
+
+            @Override
             public void setRepeatMode(int repeatMode) throws RemoteException {
                 postToHandler(MessageHandler.MSG_SET_REPEAT_MODE, repeatMode);
             }
@@ -2399,6 +2539,11 @@
             }
 
             @Override
+            public boolean isCaptioningEnabled() {
+                return mCaptioningEnabled;
+            }
+
+            @Override
             @PlaybackStateCompat.RepeatMode
             public int getRepeatMode() {
                 return mRepeatMode;
@@ -2457,6 +2602,7 @@
             private static final int MSG_ADD_QUEUE_ITEM_AT = 26;
             private static final int MSG_REMOVE_QUEUE_ITEM = 27;
             private static final int MSG_REMOVE_QUEUE_ITEM_AT = 28;
+            private static final int MSG_SET_CAPTIONING_ENABLED = 29;
 
             // KeyEvent constants only available on API 11+
             private static final int KEYCODE_MEDIA_PAUSE = 127;
@@ -2576,6 +2722,9 @@
                     case MSG_SET_VOLUME:
                         setVolumeTo(msg.arg1, 0);
                         break;
+                    case MSG_SET_CAPTIONING_ENABLED:
+                        cb.onSetCaptioningEnabled((boolean) msg.obj);
+                        break;
                     case MSG_SET_REPEAT_MODE:
                         cb.onSetRepeatMode(msg.arg1);
                         break;
@@ -2802,23 +2951,25 @@
         private final Token mToken;
 
         private boolean mDestroyed = false;
-        private ExtraSession mExtraSessionBinder;
         private final RemoteCallbackList<IMediaControllerCallback> mExtraControllerCallbacks =
                 new RemoteCallbackList<>();
 
         private PlaybackStateCompat mPlaybackState;
         @RatingCompat.Style int mRatingType;
+        boolean mCaptioningEnabled;
         @PlaybackStateCompat.RepeatMode int mRepeatMode;
         boolean mShuffleModeEnabled;
 
         public MediaSessionImplApi21(Context context, String tag) {
             mSessionObj = MediaSessionCompatApi21.createSession(context, tag);
-            mToken = new Token(MediaSessionCompatApi21.getSessionToken(mSessionObj));
+            mToken = new Token(MediaSessionCompatApi21.getSessionToken(mSessionObj),
+                    new ExtraSession());
         }
 
         public MediaSessionImplApi21(Object mediaSession) {
             mSessionObj = MediaSessionCompatApi21.verifySession(mediaSession);
-            mToken = new Token(MediaSessionCompatApi21.getSessionToken(mSessionObj));
+            mToken = new Token(MediaSessionCompatApi21.getSessionToken(mSessionObj),
+                    new ExtraSession());
         }
 
         @Override
@@ -2942,6 +3093,22 @@
         }
 
         @Override
+        public void setCaptioningEnabled(boolean enabled) {
+            if (mCaptioningEnabled != enabled) {
+                mCaptioningEnabled = enabled;
+                int size = mExtraControllerCallbacks.beginBroadcast();
+                for (int i = size - 1; i >= 0; i--) {
+                    IMediaControllerCallback cb = mExtraControllerCallbacks.getBroadcastItem(i);
+                    try {
+                        cb.onCaptioningEnabledChanged(enabled);
+                    } catch (RemoteException e) {
+                    }
+                }
+                mExtraControllerCallbacks.finishBroadcast();
+            }
+        }
+
+        @Override
         public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
             if (android.os.Build.VERSION.SDK_INT < 26) {
                 if (mRepeatMode != repeatMode) {
@@ -3005,13 +3172,6 @@
             }
         }
 
-        ExtraSession getExtraSessionBinder() {
-            if (mExtraSessionBinder == null) {
-                mExtraSessionBinder = new ExtraSession();
-            }
-            return mExtraSessionBinder;
-        }
-
         class ExtraSession extends IMediaSession.Stub {
             @Override
             public void sendCommand(String command, Bundle args, ResultReceiverWrapper cb) {
@@ -3183,6 +3343,12 @@
             }
 
             @Override
+            public void setCaptioningEnabled(boolean enabled) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
             public void setRepeatMode(int repeatMode) throws RemoteException {
                 // Will not be called.
                 throw new AssertionError();
@@ -3260,6 +3426,11 @@
             }
 
             @Override
+            public boolean isCaptioningEnabled() {
+                return mCaptioningEnabled;
+            }
+
+            @Override
             @PlaybackStateCompat.RepeatMode
             public int getRepeatMode() {
                 return mRepeatMode;
diff --git a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
index ab85133..5d9f84e 100644
--- a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
+++ b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
@@ -50,7 +50,7 @@
             ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
             ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
             ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI,
-            ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE_ENABLED})
+            ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE_ENABLED, ACTION_SET_CAPTIONING_ENABLED})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Actions {}
 
@@ -204,6 +204,13 @@
     public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 1 << 19;
 
     /**
+     * Indicates this session supports the set captioning enabled command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SET_CAPTIONING_ENABLED = 1 << 20;
+
+    /**
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
@@ -625,6 +632,7 @@
      * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_URI}</li>
      * <li> {@link PlaybackStateCompat#ACTION_SET_REPEAT_MODE}</li>
      * <li> {@link PlaybackStateCompat#ACTION_SET_SHUFFLE_MODE_ENABLED}</li>
+     * <li> {@link PlaybackStateCompat#ACTION_SET_CAPTIONING_ENABLED}</li>
      * </ul>
      */
     @Actions
@@ -1169,6 +1177,7 @@
          * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_URI}</li>
          * <li> {@link PlaybackStateCompat#ACTION_SET_REPEAT_MODE}</li>
          * <li> {@link PlaybackStateCompat#ACTION_SET_SHUFFLE_MODE_ENABLED}</li>
+         * <li> {@link PlaybackStateCompat#ACTION_SET_CAPTIONING_ENABLED}</li>
          * </ul>
          *
          * @return this
diff --git a/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java b/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
index fd87a76..5be500d 100644
--- a/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.testutils.PollingCheck;
 import android.support.v4.media.MediaBrowserCompat.MediaItem;
 
 import org.junit.Test;
diff --git a/media-compat/tests/src/android/support/v4/media/PollingCheck.java b/media-compat/tests/src/android/support/v4/media/PollingCheck.java
deleted file mode 100644
index 222753f..0000000
--- a/media-compat/tests/src/android/support/v4/media/PollingCheck.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.v4.media;
-
-import junit.framework.Assert;
-
-import java.util.concurrent.Callable;
-
-public abstract class PollingCheck {
-    private static final long TIME_SLICE = 50;
-    private long mTimeout = 3000;
-
-    public interface PollingCheckCondition {
-        boolean canProceed();
-    }
-
-    public PollingCheck() {
-    }
-
-    public PollingCheck(long timeout) {
-        mTimeout = timeout;
-    }
-
-    protected abstract boolean check();
-
-    public void run() {
-        if (check()) {
-            return;
-        }
-
-        long timeout = mTimeout;
-        while (timeout > 0) {
-            try {
-                Thread.sleep(TIME_SLICE);
-            } catch (InterruptedException e) {
-                Assert.fail("unexpected InterruptedException");
-            }
-
-            if (check()) {
-                return;
-            }
-
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail("unexpected timeout");
-    }
-
-    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
-            throws Exception {
-        while (timeout > 0) {
-            if (condition.call()) {
-                return;
-            }
-
-            Thread.sleep(TIME_SLICE);
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail(message.toString());
-    }
-
-    public static void waitFor(final PollingCheckCondition condition) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return condition.canProceed();
-            }
-        }.run();
-    }
-
-    public static void waitFor(long timeout, final PollingCheckCondition condition) {
-        new PollingCheck(timeout) {
-            @Override
-            protected boolean check() {
-                return condition.canProceed();
-            }
-        }.run();
-    }
-}
diff --git a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java b/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
index 2598bef..a1d18d0 100644
--- a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
@@ -21,10 +21,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.media.AudioManager;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -32,7 +32,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.media.MediaDescriptionCompat;
-import android.support.v4.media.PollingCheck;
 import android.support.v4.media.RatingCompat;
 import android.support.v4.media.VolumeProviderCompat;
 
@@ -52,6 +51,8 @@
     private static final String EXTRAS_KEY = "test-key";
     private static final String EXTRAS_VALUE = "test-val";
     private static final float DELTA = 1e-4f;
+    private static final boolean ENABLED = true;
+    private static final boolean DISABLED = false;
 
     private final Object mWaitLock = new Object();
     private Handler mHandler = new Handler(Looper.getMainLooper());
@@ -90,15 +91,6 @@
                 RatingCompat.RATING_NONE, mController.getRatingType());
 
         mSession.setRatingType(RatingCompat.RATING_5_STARS);
-        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
-            // Wait until the extra binder is ready.
-            new PollingCheck(TIME_OUT_MS) {
-                @Override
-                protected boolean check() {
-                    return mController.getRatingType() != RatingCompat.RATING_NONE;
-                }
-            }.run();
-        }
         assertEquals(RatingCompat.RATING_5_STARS, mController.getRatingType());
     }
 
@@ -162,6 +154,15 @@
             assertTrue(mCallback.mOnRemoveQueueItemCalled);
             assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
             assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
+
+            // Try to modify the queue when the session does not support queue management.
+            mSession.setFlags(0);
+            try {
+                mController.addQueueItem(itemDescription);
+                fail();
+            } catch (UnsupportedOperationException e) {
+                // Expected.
+            }
         }
     }
 
@@ -349,6 +350,12 @@
             assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
 
             mCallback.reset();
+            controls.setCaptioningEnabled(ENABLED);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
+            assertEquals(ENABLED, mCallback.mCaptioningEnabled);
+
+            mCallback.reset();
             final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
             controls.setRepeatMode(repeatMode);
             mWaitLock.wait(TIME_OUT_MS);
@@ -356,11 +363,10 @@
             assertEquals(repeatMode, mCallback.mRepeatMode);
 
             mCallback.reset();
-            final boolean shuffleModeEnabled = true;
-            controls.setShuffleModeEnabled(shuffleModeEnabled);
+            controls.setShuffleModeEnabled(ENABLED);
             mWaitLock.wait(TIME_OUT_MS);
             assertTrue(mCallback.mOnSetShuffleModeEnabledCalled);
-            assertEquals(shuffleModeEnabled, mCallback.mShuffleModeEnabled);
+            assertEquals(ENABLED, mCallback.mShuffleModeEnabled);
         }
     }
 
@@ -394,6 +400,7 @@
         private String mCommand;
         private Bundle mExtras;
         private ResultReceiver mCommandCallback;
+        private boolean mCaptioningEnabled;
         private int mRepeatMode;
         private boolean mShuffleModeEnabled;
         private int mQueueIndex;
@@ -418,6 +425,7 @@
         private boolean mOnPrepareFromMediaIdCalled;
         private boolean mOnPrepareFromSearchCalled;
         private boolean mOnPrepareFromUriCalled;
+        private boolean mOnSetCaptioningEnabledCalled;
         private boolean mOnSetRepeatModeCalled;
         private boolean mOnSetShuffleModeEnabledCalled;
         private boolean mOnAddQueueItemCalled;
@@ -436,6 +444,7 @@
             mExtras = null;
             mCommand = null;
             mCommandCallback = null;
+            mCaptioningEnabled = false;
             mShuffleModeEnabled = false;
             mRepeatMode = PlaybackStateCompat.REPEAT_MODE_NONE;
             mQueueIndex = -1;
@@ -460,6 +469,7 @@
             mOnPrepareFromMediaIdCalled = false;
             mOnPrepareFromSearchCalled = false;
             mOnPrepareFromUriCalled = false;
+            mOnSetCaptioningEnabledCalled = false;
             mOnSetRepeatModeCalled = false;
             mOnSetShuffleModeEnabledCalled = false;
             mOnAddQueueItemCalled = false;
@@ -678,6 +688,15 @@
         }
 
         @Override
+        public void onSetCaptioningEnabled(boolean enabled) {
+            synchronized (mWaitLock) {
+                mOnSetCaptioningEnabledCalled = true;
+                mCaptioningEnabled = enabled;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
         public void onSetShuffleModeEnabled(boolean enabled) {
             synchronized (mWaitLock) {
                 mOnSetShuffleModeEnabledCalled = true;
diff --git a/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java b/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
index 0e85c1c..1e22669 100644
--- a/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
@@ -31,14 +31,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.AudioManager;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Parcel;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.media.PollingCheck;
 import android.support.v4.media.MediaDescriptionCompat;
 import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.RatingCompat;
@@ -213,9 +211,6 @@
     @SmallTest
     public void testSetPlaybackState() throws Exception {
         MediaControllerCompat controller = mSession.getController();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            waitUntilExtraBinderReady(controller);
-        }
         controller.registerCallback(mCallback, mHandler);
         synchronized (mWaitLock) {
             mCallback.resetLocked();
@@ -310,15 +305,37 @@
     }
 
     /**
+     * Tests {@link MediaSessionCompat#setCaptioningEnabled}.
+     */
+    @Test
+    @SmallTest
+    public void testSetCaptioningEnabled() throws Exception {
+        MediaControllerCompat controller = mSession.getController();
+        controller.registerCallback(mCallback, mHandler);
+        synchronized (mWaitLock) {
+            mCallback.resetLocked();
+            mSession.setCaptioningEnabled(true);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnCaptioningEnabledChangedCalled);
+            assertEquals(true, mCallback.mCaptioningEnabled);
+            assertEquals(true, controller.isCaptioningEnabled());
+
+            mCallback.resetLocked();
+            mSession.setCaptioningEnabled(false);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnCaptioningEnabledChangedCalled);
+            assertEquals(false, mCallback.mCaptioningEnabled);
+            assertEquals(false, controller.isCaptioningEnabled());
+        }
+    }
+
+    /**
      * Tests {@link MediaSessionCompat#setRepeatMode}.
      */
     @Test
     @SmallTest
     public void testSetRepeatMode() throws Exception {
         MediaControllerCompat controller = mSession.getController();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            waitUntilExtraBinderReady(controller);
-        }
         controller.registerCallback(mCallback, mHandler);
         synchronized (mWaitLock) {
             mCallback.resetLocked();
@@ -339,13 +356,9 @@
     public void testSetShuffleModeEnabled() throws Exception {
         final boolean shuffleModeEnabled = true;
         MediaControllerCompat controller = mSession.getController();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            waitUntilExtraBinderReady(controller);
-        }
         controller.registerCallback(mCallback, mHandler);
         synchronized (mWaitLock) {
             mCallback.resetLocked();
-            final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
             mSession.setShuffleModeEnabled(shuffleModeEnabled);
             mWaitLock.wait(TIME_OUT_MS);
             assertTrue(mCallback.mOnShuffleModeChangedCalled);
@@ -361,10 +374,6 @@
     @SmallTest
     public void testSendSessionEvent() throws Exception {
         MediaControllerCompat controller = mSession.getController();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
-                Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-            waitUntilExtraBinderReady(controller);
-        }
         controller.registerCallback(mCallback, mHandler);
         synchronized (mWaitLock) {
             mCallback.resetLocked();
@@ -620,15 +629,6 @@
         controller.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
     }
 
-    private void waitUntilExtraBinderReady(final MediaControllerCompat controller) {
-        new PollingCheck(TIME_OUT_MS) {
-            @Override
-            protected boolean check() {
-                return controller.isExtraBinderReady();
-            }
-        }.run();
-    }
-
     private class MediaControllerCallback extends MediaControllerCompat.Callback {
         private volatile boolean mOnPlaybackStateChangedCalled;
         private volatile boolean mOnMetadataChangedCalled;
@@ -638,6 +638,7 @@
         private volatile boolean mOnAudioInfoChangedCalled;
         private volatile boolean mOnSessionDestroyedCalled;
         private volatile boolean mOnSessionEventCalled;
+        private volatile boolean mOnCaptioningEnabledChangedCalled;
         private volatile boolean mOnRepeatModeChangedCalled;
         private volatile boolean mOnShuffleModeChangedCalled;
 
@@ -648,6 +649,7 @@
         private volatile String mEvent;
         private volatile Bundle mExtras;
         private volatile MediaControllerCompat.PlaybackInfo mPlaybackInfo;
+        private volatile boolean mCaptioningEnabled;
         private volatile int mRepeatMode;
         private volatile boolean mShuffleModeEnabled;
 
@@ -669,6 +671,7 @@
             mTitle = null;
             mExtras = null;
             mPlaybackInfo = null;
+            mCaptioningEnabled = false;
             mRepeatMode = PlaybackStateCompat.REPEAT_MODE_NONE;
             mShuffleModeEnabled = false;
         }
@@ -746,6 +749,15 @@
         }
 
         @Override
+        public void onCaptioningEnabledChanged(boolean enabled) {
+            synchronized (mWaitLock) {
+                mOnCaptioningEnabledChangedCalled = true;
+                mCaptioningEnabled = enabled;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
         public void onRepeatModeChanged(int repeatMode) {
             synchronized (mWaitLock) {
                 mOnRepeatModeChangedCalled = true;
diff --git a/previewsdk/Android.mk b/previewsdk/Android.mk
deleted file mode 100644
index ccd0547..0000000
--- a/previewsdk/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-include $(CLEAR_VARS)
-
-previewsdk_generate_constants_exe := $(LOCAL_PATH)/previewconstants.sh
-previewsdk_gen_java_files := $(TARGET_OUT_COMMON_GEN)/previewsdk/PreviewSdkConstants.java
-
-$(previewsdk_gen_java_files): $(previewsdk_generate_constants_exe)
-	$(hide) mkdir -p $(dir $@)
-	$(hide) PLATFORM_PREVIEW_SDK_VERSION="$(PLATFORM_PREVIEW_SDK_VERSION)" \
-		bash $< > $@
-
-LOCAL_MODULE := android-support-previewsdk
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_GENERATED_SOURCES := $(previewsdk_gen_java_files)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/previewsdk/previewconstants.sh b/previewsdk/previewconstants.sh
deleted file mode 100755
index de94f84..0000000
--- a/previewsdk/previewconstants.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-echo "/** Begin preview constants"
-echo " * autogenerated by previewconstants.sh */"
-echo "package android.support.previewsdk;"
-echo "class PreviewConstants {"
-echo "    public static final int PREVIEW_SDK_VERSION = $PLATFORM_PREVIEW_SDK_VERSION;"
-echo "}"
diff --git a/previewsdk/src/android/support/previewsdk/PreviewSdk.java b/previewsdk/src/android/support/previewsdk/PreviewSdk.java
deleted file mode 100644
index 8b494c7..0000000
--- a/previewsdk/src/android/support/previewsdk/PreviewSdk.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 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.previewsdk;
-
-import android.os.Build;
-
-/**
- * Utility class for performing version checks on Android platform preview SDKs.
- *
- * <p>Apps must be very careful when targeting preview builds because binary compatibility
- * is not guaranteed. APIs can be renamed or drastically changed before they are finalized
- * into a new API level. The new SDK constant <code>Build.VERSION.PREVIEW_SDK_INT</code>
- * marks a precise snapshot version of prerelease API.</p>
- *
- * <p>{@link #isKnownPreviewDevice()} will return <code>true</code> if the current device
- * is running a preview build with the same SDK snapshot this support lib was built with.
- * If it returns <code>true</code> it is safe to call prerelease APIs. If not, the app
- * should fall back to only assuming the presence of the latest public, final API level.</p>
- */
-public class PreviewSdk {
-    /**
-     * Check if the current device is running a prerelease platform preview build matching
-     * the SDK this library was built for. If it returns true, it is safe to call prerelease
-     * APIs known to this SDK.
-     *
-     * @return true if the device is running a preview build that matches the SDK.
-     */
-    public static boolean isKnownPreviewDevice() {
-        return "MNC".equals(Build.VERSION.CODENAME)
-                && Build.VERSION.PREVIEW_SDK_INT == PreviewConstants.PREVIEW_SDK_VERSION;
-    }
-}
diff --git a/recommendation/Android.mk b/recommendation/Android.mk
index 0e0a9d7..2a68de6 100644
--- a/recommendation/Android.mk
+++ b/recommendation/Android.mk
@@ -55,7 +55,7 @@
 
 LOCAL_SDK_VERSION := 21
 LOCAL_IS_HOST_MODULE := false
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := external/doclava/res/assets/templates-sdk
 
 LOCAL_SHARED_ANDROID_LIBRARIES := $(recommendation.docs.java_libraries)
 
diff --git a/samples/Support13Demos/Android.mk b/samples/Support13Demos/Android.mk
deleted file mode 100644
index a227e10..0000000
--- a/samples/Support13Demos/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := samples tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_ANDROID_LIBRARIES += android-support-v13
-
-LOCAL_PACKAGE_NAME := Support13Demos
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MIN_SDK_VERSION := 13
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
-
-# Use the folloing include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/Support4Demos/Android.mk b/samples/Support4Demos/Android.mk
deleted file mode 100644
index 0ba19b0..0000000
--- a/samples/Support4Demos/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := samples tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_ANDROID_LIBRARIES += android-support-v4
-
-LOCAL_PACKAGE_NAME := Support4Demos
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 4
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
index 5150363..487e8db 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/view/ViewPagerActivity.java
@@ -16,8 +16,6 @@
 
 package com.example.android.supportv4.view;
 
-import com.example.android.supportv4.R;
-
 import android.app.Activity;
 import android.graphics.Color;
 import android.os.Bundle;
@@ -28,6 +26,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.example.android.supportv4.R;
+
 import java.util.ArrayList;
 
 public class ViewPagerActivity extends Activity {
@@ -56,7 +56,7 @@
         private ArrayList<Pair<String, Integer>> mEntries = new ArrayList<>();
 
         public void add(String title, int color) {
-            mEntries.add(new Pair(title, color));
+            mEntries.add(new Pair<>(title, color));
         }
 
         @Override
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
index 1403a94..c617507 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
@@ -16,8 +16,6 @@
 
 package com.example.android.supportv4.widget;
 
-import com.example.android.supportv4.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Handler;
@@ -27,9 +25,8 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
+
+import com.example.android.supportv4.R;
 
 /**
  * Example of using the SwipeRefreshLayout.
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
index 08c14dc..c5f86aa 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
@@ -17,17 +17,13 @@
 package com.example.android.supportv4.widget;
 
 import android.app.Activity;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
 import android.os.Bundle;
-import android.os.Handler;
 import android.support.v4.widget.ContentLoadingProgressBar;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewTreeObserver;
-import android.view.Window;
+import android.widget.Button;
+import android.widget.TextView;
 
 import com.example.android.supportv4.R;
 
diff --git a/samples/Support7Demos/Android.mk b/samples/Support7Demos/Android.mk
deleted file mode 100644
index fbea278..0000000
--- a/samples/Support7Demos/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the samples.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := Support7Demos
-LOCAL_MODULE_TAGS := samples tests
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 7
-LOCAL_DEX_PREOPT := false
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-support-v7-appcompat \
-    android-support-v7-gridlayout \
-    android-support-v7-mediarouter \
-    android-support-v7-cardview \
-    android-support-design \
-    android-support-v7-recyclerview \
-    android-support-v7-palette \
-    android-support-v4
-LOCAL_AAPT_FLAGS := --no-version-vectors
-include $(BUILD_PACKAGE)
diff --git a/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml b/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml
index 1c60d90..517f4fa 100644
--- a/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml
+++ b/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml
@@ -29,8 +29,25 @@
         <android.support.v7.widget.SwitchCompat
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
+                android:text="SwitchCompat"/>
+
+        <android.support.v7.widget.SwitchCompat
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:enabled="false"
+                android:text="SwitchCompat disabled"/>
+
+        <Switch
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
                 android:text="Switch"/>
 
+        <Switch
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:enabled="false"
+                android:text="Switch disabled"/>
+
         <CheckBox
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
diff --git a/samples/Support7Demos/res/menu/actions.xml b/samples/Support7Demos/res/menu/actions.xml
index f3b0b85..d558365 100644
--- a/samples/Support7Demos/res/menu/actions.xml
+++ b/samples/Support7Demos/res/menu/actions.xml
@@ -18,21 +18,26 @@
     <item android:id="@+id/action_search"
           android:title="@string/action_bar_search"
           android:icon="@drawable/ic_search"
+          android:alphabeticShortcut="s"
+          app:alphabeticModifiers="ALT"
           app:showAsAction="ifRoom|collapseActionView"
           app:actionViewClass="android.support.v7.widget.SearchView" />
     <item android:id="@+id/action_add"
           android:icon="@android:drawable/ic_menu_add"
           android:title="@string/action_bar_add"
+          android:alphabeticShortcut="a"
           app:contentDescription="@string/action_bar_add_description"
           app:tooltipText="@string/action_bar_add_tooltip" />
     <item android:id="@+id/action_edit"
           android:icon="@android:drawable/ic_menu_edit"
           android:title="@string/action_bar_edit"
+          android:alphabeticShortcut="e"
           app:showAsAction="always" />
     <item android:id="@+id/action_share"
           android:icon="@android:drawable/ic_menu_share"
           android:title="@string/action_bar_share"
           android:enabled="false"
+          android:alphabeticShortcut="s"
           app:showAsAction="ifRoom" />
     <item android:id="@+id/action_sort"
           android:icon="@android:drawable/ic_menu_sort_by_size"
@@ -41,10 +46,14 @@
         <menu>
             <item android:id="@+id/action_sort_size"
                   android:icon="@android:drawable/ic_menu_sort_by_size"
-                  android:title="@string/action_bar_sort_size" />
+                  android:title="@string/action_bar_sort_size"
+                  android:alphabeticShortcut="s"
+                  app:alphabeticModifiers="CTRL|SHIFT" />
             <item android:id="@+id/action_sort_alpha"
                   android:icon="@android:drawable/ic_menu_sort_alphabetically"
-                  android:title="@string/action_bar_sort_alpha" />
+                  android:title="@string/action_bar_sort_alpha"
+                  android:alphabeticShortcut="a"
+                  app:alphabeticModifiers="CTRL|SHIFT" />
         </menu>
     </item>
 </menu>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java
index 6edf593..e263945 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarActionMode.java
@@ -16,22 +16,16 @@
 
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.view.ActionMode;
-import android.support.v7.widget.SearchView;
-import android.text.TextUtils;
 import android.view.Menu;
-import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.widget.TextView;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of an action mode.
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
index 276465b..91da0f4 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
@@ -15,16 +15,15 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v7.app.AlertDialog;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDelegate;
-import android.support.v7.app.AppCompatDialog;
 import android.view.View;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of AlertDialog with Theme.AppCompat.DayNight
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java
index d923a92..7a0608e 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatNightModeDialog.java
@@ -15,21 +15,14 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
-import android.support.v4.view.WindowCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDelegate;
 import android.support.v7.app.AppCompatDialog;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View;
-import android.widget.Spinner;
-import android.widget.Toast;
+
+import com.example.android.supportv7.R;
 
 /**
  * This demonstrates idiomatic usage of Dialog with Theme.AppCompat.DayNight
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java
index f44a0df..4661a06 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogFragmentUsage.java
@@ -15,13 +15,8 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
-import android.support.v4.view.WindowCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDialog;
 import android.support.v7.app.AppCompatDialogFragment;
@@ -34,6 +29,8 @@
 import android.widget.Spinner;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of AppCompatDialogFragment.
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java
index ea1a07d..e2d770b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/DialogUsage.java
@@ -15,12 +15,9 @@
  */
 package com.example.android.supportv7.app;
 
-import com.example.android.supportv7.R;
-
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v4.view.WindowCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.AppCompatDialog;
 import android.view.Menu;
@@ -29,6 +26,8 @@
 import android.widget.Spinner;
 import android.widget.Toast;
 
+import com.example.android.supportv7.R;
+
 /**
  * This demonstrates idiomatic usage of AppCompatDialog.
  */
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
index a4c01d1..28d7860 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
@@ -16,14 +16,7 @@
 
 package com.example.android.supportv7.widget;
 
-import com.example.android.supportv7.Cheeses;
-import com.example.android.supportv7.R;
-import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
-import com.example.android.supportv7.widget.util.ConfigToggle;
-import com.example.android.supportv7.widget.util.ConfigViewHolder;
-
 import android.app.Activity;
-import android.content.Context;
 import android.os.Bundle;
 import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.LinearLayoutManager;
@@ -33,11 +26,16 @@
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.CheckBox;
-import android.widget.CompoundButton;
 import android.widget.EditText;
 import android.widget.Spinner;
 import android.widget.TextView;
 
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+import com.example.android.supportv7.widget.util.ConfigViewHolder;
+
 /**
  * A simple activity that can be extended to demonstrate LayoutManagers.
  * <p>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java
index 70216f5..a538408 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/StableIdActivity.java
@@ -117,7 +117,7 @@
                     final int pos = viewHolder.getAdapterPosition();
                     if (pos != RecyclerView.NO_POSITION) {
                         // swap item to top, and notify data set changed
-                        Pair d = mData.remove(pos);
+                        Pair<Integer, String> d = mData.remove(pos);
                         mData.add(0, d);
 
                         notifyDataSetChanged();
diff --git a/samples/SupportAnimationDemos/AndroidManifest.xml b/samples/SupportAnimationDemos/AndroidManifest.xml
new file mode 100644
index 0000000..25e5ec8
--- /dev/null
+++ b/samples/SupportAnimationDemos/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.support.animation">
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="25" />
+
+    <application android:label="@string/activity_sample_code"
+            android:supportsRtl="true"
+            android:icon="@drawable/app_sample_code"
+            android:theme="@style/android:Theme.Holo.Light">
+        <activity android:name=".MainActivity"
+                  android:label="ChainedSpringDemo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".BrowseActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".SpringActivity"
+                  android:label="SpringDemo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/samples/SupportAnimationDemos/build.gradle b/samples/SupportAnimationDemos/build.gradle
new file mode 100644
index 0000000..dd3e350
--- /dev/null
+++ b/samples/SupportAnimationDemos/build.gradle
@@ -0,0 +1,30 @@
+apply plugin: 'com.android.application'
+
+dependencies {
+    compile project(':support-dynamic-animation')
+}
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 16
+    }
+
+    sourceSets {
+        main.manifest.srcFile 'AndroidManifest.xml'
+        main.java.srcDirs = ['src']
+        main.aidl.srcDirs = ['src']
+        main.res.srcDirs = ['res']
+    }
+
+    lintOptions {
+        abortOnError true
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
+}
+
diff --git a/samples/SupportAnimationDemos/res/drawable-hdpi/app_sample_code.png b/samples/SupportAnimationDemos/res/drawable-hdpi/app_sample_code.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/samples/SupportAnimationDemos/res/drawable-hdpi/app_sample_code.png
Binary files differ
diff --git a/samples/SupportAnimationDemos/res/drawable-mdpi/app_sample_code.png b/samples/SupportAnimationDemos/res/drawable-mdpi/app_sample_code.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/samples/SupportAnimationDemos/res/drawable-mdpi/app_sample_code.png
Binary files differ
diff --git a/dynamic-animation/AndroidManifest-make.xml b/samples/SupportAnimationDemos/res/drawable/circle.xml
similarity index 68%
copy from dynamic-animation/AndroidManifest-make.xml
copy to samples/SupportAnimationDemos/res/drawable/circle.xml
index bfe97cc..a343f54 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/samples/SupportAnimationDemos/res/drawable/circle.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2017 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.
@@ -13,7 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <size
+        android:width="40dp"
+        android:height="40dp"/>
+    <solid
+        android:color="#2E7D32"/>
+</shape>
\ No newline at end of file
diff --git a/dynamic-animation/AndroidManifest-make.xml b/samples/SupportAnimationDemos/res/drawable/green_circle.xml
similarity index 68%
copy from dynamic-animation/AndroidManifest-make.xml
copy to samples/SupportAnimationDemos/res/drawable/green_circle.xml
index bfe97cc..833fc9e 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/samples/SupportAnimationDemos/res/drawable/green_circle.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2017 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.
@@ -13,7 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <size
+        android:width="40dp"
+        android:height="40dp"/>
+    <solid
+        android:color="#4CAF50"/>
+</shape>
diff --git a/dynamic-animation/AndroidManifest-make.xml b/samples/SupportAnimationDemos/res/drawable/light_green_circle.xml
similarity index 68%
copy from dynamic-animation/AndroidManifest-make.xml
copy to samples/SupportAnimationDemos/res/drawable/light_green_circle.xml
index bfe97cc..c181576 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/samples/SupportAnimationDemos/res/drawable/light_green_circle.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2017 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.
@@ -13,7 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <size
+        android:width="40dp"
+        android:height="40dp"/>
+    <solid
+        android:color="#A5D6A7"/>
+</shape>
diff --git a/dynamic-animation/AndroidManifest-make.xml b/samples/SupportAnimationDemos/res/drawable/spring_demo_circle.xml
similarity index 65%
copy from dynamic-animation/AndroidManifest-make.xml
copy to samples/SupportAnimationDemos/res/drawable/spring_demo_circle.xml
index bfe97cc..d370267 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/samples/SupportAnimationDemos/res/drawable/spring_demo_circle.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2017 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.
@@ -13,7 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <size
+        android:width="40dp"
+        android:height="40dp"/>
+    <solid
+        android:color="@android:color/holo_green_light"></solid>
+</shape>
\ No newline at end of file
diff --git a/samples/SupportAnimationDemos/res/layout/activity_chained_springs.xml b/samples/SupportAnimationDemos/res/layout/activity_chained_springs.xml
new file mode 100644
index 0000000..ff8a7f7
--- /dev/null
+++ b/samples/SupportAnimationDemos/res/layout/activity_chained_springs.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent" android:layout_height="match_parent">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:layout_gravity="bottom"
+        android:layout_marginBottom="50dp"
+        android:orientation="horizontal">
+        <LinearLayout
+            android:layout_width="100dp"
+            android:layout_height="match_parent"
+            android:gravity="center_horizontal"
+            android:orientation="vertical">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Damping Ratio:"/>
+            <TextView
+                android:id="@+id/damping_ratio_txt"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"/>
+        </LinearLayout>
+        <SeekBar
+            android:id="@+id/damping_ratio"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:layout_gravity="bottom"
+        android:orientation="horizontal">
+        <LinearLayout
+            android:layout_width="100dp"
+            android:layout_height="match_parent"
+            android:gravity="center_horizontal"
+            android:orientation="vertical">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Stiffness:"/>
+            <TextView
+                android:id="@+id/stiffness_txt"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"/>
+        </LinearLayout>
+        <SeekBar
+            android:id="@+id/stiffness"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"/>
+    </LinearLayout>
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center_horizontal"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/lead"
+            android:layout_width="60dp"
+            android:layout_height="60dp"
+            android:layout_margin="20dp"
+            android:background="@drawable/circle"
+            android:gravity="center"
+            android:text="Drag\n Me"
+            android:textColor="#FFFFAD"/>
+        <ImageView
+            android:id="@+id/follow1"
+            android:layout_width="60dp"
+            android:layout_height="60dp"
+            android:layout_margin="20dp"
+            android:src="@drawable/green_circle"/>
+        <ImageView
+            android:id="@+id/follow2"
+            android:layout_width="60dp"
+            android:layout_height="60dp"
+            android:layout_margin="20dp"
+            android:src="@drawable/light_green_circle"/>
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/SupportAnimationDemos/res/layout/activity_main.xml b/samples/SupportAnimationDemos/res/layout/activity_main.xml
new file mode 100644
index 0000000..4e8d9b4
--- /dev/null
+++ b/samples/SupportAnimationDemos/res/layout/activity_main.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/activity_main"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context="com.example.android.support.animation.SpringActivity">
+
+    <FrameLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <com.example.android.support.animation.SpringView
+            android:id="@+id/actual_spring"
+            android:layout_width="100dp"
+            android:layout_height="match_parent"
+            android:layout_gravity="center_horizontal"/>
+        <ImageView
+            android:id="@+id/imageView"
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="50dp"
+            android:src="@drawable/spring_demo_circle"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="50dp"
+            android:layout_gravity="bottom"
+            android:layout_marginBottom="50dp"
+            android:orientation="horizontal">
+            <LinearLayout
+                android:layout_width="100dp"
+                android:layout_height="match_parent"
+                android:gravity="center_horizontal"
+                android:orientation="vertical">
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Damping Ratio:"/>
+                <TextView
+                    android:id="@+id/damping_ratio_txt"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_horizontal"/>
+            </LinearLayout>
+            <SeekBar
+                android:id="@+id/damping_ratio"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"/>
+        </LinearLayout>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="50dp"
+            android:layout_gravity="bottom"
+            android:orientation="horizontal">
+            <LinearLayout
+                android:layout_width="100dp"
+                android:layout_height="match_parent"
+                android:gravity="center_horizontal"
+                android:orientation="vertical">
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Stiffness:"/>
+                <TextView
+                    android:id="@+id/stiffness_txt"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_horizontal"/>
+            </LinearLayout>
+            <SeekBar
+                android:id="@+id/stiffness"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"/>
+        </LinearLayout>
+
+    </FrameLayout>
+</RelativeLayout>
diff --git a/samples/SupportAnimationDemos/res/values-w820dp/dimens.xml b/samples/SupportAnimationDemos/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..3ef1782
--- /dev/null
+++ b/samples/SupportAnimationDemos/res/values-w820dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+<resources>
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+         (such as screen margins) for screens with more than 820dp of available width. This
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/dynamic-animation/AndroidManifest-make.xml b/samples/SupportAnimationDemos/res/values/colors.xml
similarity index 71%
copy from dynamic-animation/AndroidManifest-make.xml
copy to samples/SupportAnimationDemos/res/values/colors.xml
index bfe97cc..7141433 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/samples/SupportAnimationDemos/res/values/colors.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2017 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.
@@ -13,7 +14,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<resources>
+    <color name="springColor">#ff0099cc</color>
+</resources>
diff --git a/dynamic-animation/AndroidManifest-make.xml b/samples/SupportAnimationDemos/res/values/dimens.xml
similarity index 68%
copy from dynamic-animation/AndroidManifest-make.xml
copy to samples/SupportAnimationDemos/res/values/dimens.xml
index bfe97cc..f5b011c 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/samples/SupportAnimationDemos/res/values/dimens.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2017 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.
@@ -13,7 +14,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/dynamic-animation/AndroidManifest-make.xml b/samples/SupportAnimationDemos/res/values/strings.xml
similarity index 71%
copy from dynamic-animation/AndroidManifest-make.xml
copy to samples/SupportAnimationDemos/res/values/strings.xml
index bfe97cc..3412861 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/samples/SupportAnimationDemos/res/values/strings.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2017 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.
@@ -13,7 +14,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<resources>
+    <string name="activity_sample_code">Support Animation Demos</string>
+</resources>
diff --git a/samples/SupportAnimationDemos/src/com/example/android/support/animation/BrowseActivity.java b/samples/SupportAnimationDemos/src/com/example/android/support/animation/BrowseActivity.java
new file mode 100644
index 0000000..e330302
--- /dev/null
+++ b/samples/SupportAnimationDemos/src/com/example/android/support/animation/BrowseActivity.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 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 com.example.android.support.animation;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This activity lists all the activities in this application.
+ */
+public class BrowseActivity extends ListActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+        String path = intent.getStringExtra("com.example.android.support.animation");
+
+        if (path == null) {
+            path = "";
+        }
+
+        setListAdapter(new SimpleAdapter(this, getData(path),
+                android.R.layout.simple_list_item_1, new String[] { "title" },
+                new int[] { android.R.id.text1 }));
+        getListView().setTextFilterEnabled(true);
+    }
+
+    protected List<Map<String, Object>> getData(String prefix) {
+        List<Map<String, Object>> myData = new ArrayList<Map<String, Object>>();
+
+        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+        mainIntent.addCategory(Intent.CATEGORY_SAMPLE_CODE);
+
+        PackageManager pm = getPackageManager();
+        List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
+
+        if (null == list) {
+            return myData;
+        }
+
+        String[] prefixPath;
+        String prefixWithSlash = prefix;
+
+        if (prefix.equals("")) {
+            prefixPath = null;
+        } else {
+            prefixPath = prefix.split("/");
+            prefixWithSlash = prefix + "/";
+        }
+
+        int len = list.size();
+
+        Map<String, Boolean> entries = new HashMap<String, Boolean>();
+
+        for (int i = 0; i < len; i++) {
+            ResolveInfo info = list.get(i);
+            CharSequence labelSeq = info.loadLabel(pm);
+            String label = labelSeq != null ? labelSeq.toString() : info.activityInfo.name;
+
+            if (prefixWithSlash.length() == 0 || label.startsWith(prefixWithSlash)) {
+
+                String[] labelPath = label.split("/");
+
+                String nextLabel = prefixPath == null ? labelPath[0] : labelPath[prefixPath.length];
+
+                if ((prefixPath != null ? prefixPath.length : 0) == labelPath.length - 1) {
+                    addItem(myData, nextLabel, activityIntent(
+                            info.activityInfo.applicationInfo.packageName,
+                            info.activityInfo.name));
+                } else {
+                    if (entries.get(nextLabel) == null) {
+                        addItem(myData, nextLabel, browseIntent(prefix.equals("")
+                                ? nextLabel : prefix + "/" + nextLabel));
+                        entries.put(nextLabel, true);
+                    }
+                }
+            }
+        }
+
+        Collections.sort(myData, sDisplayNameComparator);
+        return myData;
+    }
+
+    private static final Comparator<Map<String, Object>> sDisplayNameComparator =
+            new Comparator<Map<String, Object>>() {
+                public final Collator collator = Collator.getInstance();
+
+                public int compare(Map<String, Object> map1, Map<String, Object> map2) {
+                    return collator.compare(map1.get("title"), map2.get("title"));
+                }
+            };
+
+    protected Intent activityIntent(String pkg, String componentName) {
+        Intent result = new Intent();
+        result.setClassName(pkg, componentName);
+        return result;
+    }
+
+    protected Intent browseIntent(String path) {
+        Intent result = new Intent();
+        result.setClass(this, BrowseActivity.class);
+        result.putExtra("com.example.android.support.animation", path);
+        return result;
+    }
+
+    protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {
+        Map<String, Object> temp = new HashMap<String, Object>();
+        temp.put("title", name);
+        temp.put("intent", intent);
+        data.add(temp);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        Map<String, Object> map = (Map<String, Object>) l.getItemAtPosition(position);
+
+        Intent intent = new Intent((Intent) map.get("intent"));
+        intent.addCategory(Intent.CATEGORY_SAMPLE_CODE);
+        startActivity(intent);
+    }
+}
+
+
diff --git a/samples/SupportAnimationDemos/src/com/example/android/support/animation/MainActivity.java b/samples/SupportAnimationDemos/src/com/example/android/support/animation/MainActivity.java
new file mode 100644
index 0000000..1ded677
--- /dev/null
+++ b/samples/SupportAnimationDemos/src/com/example/android/support/animation/MainActivity.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 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 com.example.android.support.animation;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.animation.DynamicAnimation;
+import android.support.animation.SpringAnimation;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+/**
+ * Activity for chained spring animations.
+ */
+public class MainActivity extends Activity {
+    private float mDampingRatio = 1.0f;
+    private float mStiffness = 50.0f;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_chained_springs);
+        final View lead = findViewById(R.id.lead);
+        final View follow1 = findViewById(R.id.follow1);
+        final View follow2 = findViewById(R.id.follow2);
+
+        final SpringAnimation anim1X = new SpringAnimation(follow1, DynamicAnimation.TRANSLATION_X,
+                lead.getTranslationX());
+        final SpringAnimation anim1Y = new SpringAnimation(follow1, DynamicAnimation.TRANSLATION_Y,
+                lead.getTranslationY());
+        final SpringAnimation anim2X = new SpringAnimation(follow2, DynamicAnimation.TRANSLATION_X,
+                follow1.getTranslationX());
+        final SpringAnimation anim2Y = new SpringAnimation(follow2, DynamicAnimation.TRANSLATION_Y,
+                follow1.getTranslationY());
+
+        anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
+            @Override
+            public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
+                                          float velocity) {
+                anim2X.animateToFinalPosition(value);
+            }
+        });
+
+        anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
+            @Override
+            public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
+                                          float velocity) {
+                anim2Y.animateToFinalPosition(value);
+            }
+        });
+
+        ((View) lead.getParent()).setOnTouchListener(new View.OnTouchListener() {
+            public float firstDownX = 0;
+            public float firstDownY = 0;
+            public VelocityTracker tracker;
+            @Override
+            public boolean onTouch(View view, MotionEvent motionEvent) {
+                if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
+
+                    if (motionEvent.getX() < lead.getX()
+                            || motionEvent.getX() > lead.getX() + lead.getWidth()
+                            || motionEvent.getY() < lead.getY()
+                            || motionEvent.getY() > lead.getY() + lead.getHeight()) {
+                        return false;
+                    }
+
+                    // Update the stiffness and damping ratio that are configured by user from the
+                    // seekbar UI as needed.
+                    anim1X.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
+                    anim1Y.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
+                    anim2X.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
+                    anim2Y.getSpring().setStiffness(mStiffness).setDampingRatio(mDampingRatio);
+
+                    firstDownX = motionEvent.getX() - lead.getTranslationX();
+                    firstDownY = motionEvent.getY() - lead.getTranslationY();
+                    tracker = VelocityTracker.obtain();
+                    tracker.clear();
+                    tracker.addMovement(motionEvent);
+                } else if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
+                    float deltaX = motionEvent.getX() - firstDownX;
+                    float deltaY = motionEvent.getY() - firstDownY;
+
+                    // Directly manipulate the lead view.
+                    lead.setTranslationX(deltaX);
+                    lead.setTranslationY(deltaY);
+
+                    // Animate the follow views to the new final position
+                    anim1X.animateToFinalPosition(deltaX);
+                    anim1Y.animateToFinalPosition(deltaY);
+
+                    tracker.addMovement(motionEvent);
+                }
+                return true;
+            }
+        });
+        setupSeekBars();
+    }
+
+    // Setup seek bars so damping ratio and stiffness for the spring can be modified through the UI.
+    void setupSeekBars() {
+        SeekBar dr = (SeekBar) findViewById(R.id.damping_ratio);
+        dr.setMax(130);
+        final TextView drTxt = (TextView) findViewById(R.id.damping_ratio_txt);
+        dr.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+                if (i < 80) {
+                    mDampingRatio = i / 80.0f;
+                } else if (i > 90) {
+                    mDampingRatio = (float) Math.exp((i - 90) / 10.0);
+                } else {
+                    mDampingRatio = 1;
+                }
+                drTxt.setText(String.format("%.4f", (float) mDampingRatio));
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        SeekBar stiff = (SeekBar) findViewById(R.id.stiffness);
+        stiff.setMax(110);
+        final TextView nfTxt = (TextView) findViewById(R.id.stiffness_txt);
+        stiff.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+                float stiffness = (float) Math.exp(i / 10d);
+                mStiffness = stiffness;
+                nfTxt.setText(String.format("%.3f", (float) stiffness));
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+        dr.setProgress(80);
+        stiff.setProgress(60);
+
+    }
+}
diff --git a/samples/SupportAnimationDemos/src/com/example/android/support/animation/SpringActivity.java b/samples/SupportAnimationDemos/src/com/example/android/support/animation/SpringActivity.java
new file mode 100644
index 0000000..e9f2d62
--- /dev/null
+++ b/samples/SupportAnimationDemos/src/com/example/android/support/animation/SpringActivity.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 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 com.example.android.support.animation;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.animation.DynamicAnimation;
+import android.support.animation.SpringAnimation;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+/**
+ * This is a single spring animation. It provides a UI to interact with the spring, and two seek
+ * bars to tune the spring constants.
+ */
+public class SpringActivity extends Activity {
+    private float mDampingRatio;
+    private float mStiffness;
+    private SpringView mSpringView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        final View v = findViewById(R.id.container);
+        mSpringView = (SpringView) findViewById(R.id.actual_spring);
+
+        final View img = findViewById(R.id.imageView);
+        setupSeekBars();
+        final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y,
+                0 /* final position */);
+        anim.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
+            @Override
+            public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) {
+                // Update the drawing of the spring.
+                mSpringView.setMassHeight(img.getY());
+            }
+        });
+
+        ((View) img.getParent()).setOnTouchListener(new View.OnTouchListener() {
+            public float touchOffset;
+            public VelocityTracker vt;
+            @Override
+            public boolean onTouch(View v, MotionEvent motionEvent) {
+                if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                    // check whether the touch happens inside of the img view.
+                    boolean inside = motionEvent.getX() >= img.getX()
+                            && motionEvent.getX() <= img.getX() + img.getWidth()
+                            && motionEvent.getY() >= img.getY()
+                            && motionEvent.getY() <= img.getY() + img.getHeight();
+
+                    anim.cancel();
+
+                    if (!inside) {
+                        return false;
+                    }
+                    // Apply this offset to all the subsequent events
+                    touchOffset = img.getTranslationY() - motionEvent.getY();
+                    vt = VelocityTracker.obtain();
+                    vt.clear();
+                }
+
+                vt.addMovement(motionEvent);
+
+                if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
+                    img.setTranslationY(motionEvent.getY() + touchOffset);
+                    // Updates the drawing of the spring.
+                    mSpringView.setMassHeight(img.getY());
+                } else if (motionEvent.getActionMasked() == MotionEvent.ACTION_CANCEL
+                        || motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
+                    // Compute the velocity in unit: pixel/second
+                    vt.computeCurrentVelocity(1000);
+                    float velocity = vt.getYVelocity();
+                    anim.getSpring().setDampingRatio(mDampingRatio).setStiffness(mStiffness);
+                    anim.setStartVelocity(velocity).start();
+                    vt.recycle();
+                }
+                return true;
+            }
+        });
+    }
+
+    // Setup seek bars so damping ratio and stiffness for the spring can be modified through the UI.
+    void setupSeekBars() {
+        SeekBar dr = (SeekBar) findViewById(R.id.damping_ratio);
+        dr.setMax(130);
+        final TextView drTxt = (TextView) findViewById(R.id.damping_ratio_txt);
+        dr.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+                if (i < 80) {
+                    mDampingRatio = i / 80.0f;
+                } else if (i > 90) {
+                    mDampingRatio = (float) Math.exp((i - 90) / 10.0);
+                } else {
+                    mDampingRatio = 1;
+                }
+                drTxt.setText(String.format("%.4f", (float) mDampingRatio));
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        SeekBar stiff = (SeekBar) findViewById(R.id.stiffness);
+        stiff.setMax(110);
+        final TextView nfTxt = (TextView) findViewById(R.id.stiffness_txt);
+        stiff.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+                float stiffness = (float) Math.exp(i / 10d);
+                mStiffness = stiffness;
+                nfTxt.setText(String.format("%.3f", (float) stiffness));
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+        dr.setProgress(40);
+        stiff.setProgress(60);
+    }
+}
diff --git a/samples/SupportAnimationDemos/src/com/example/android/support/animation/SpringView.java b/samples/SupportAnimationDemos/src/com/example/android/support/animation/SpringView.java
new file mode 100644
index 0000000..14a0fd0
--- /dev/null
+++ b/samples/SupportAnimationDemos/src/com/example/android/support/animation/SpringView.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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 com.example.android.support.animation;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * The view that draws the spring as it reacts (i.e. expands/compresses) to the user touch.
+ */
+public class SpringView extends View {
+    final Paint mPaint = new Paint();
+    private float mLastHeight = 175;
+
+    public SpringView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWillNotDraw(false);
+        mPaint.setColor(context.getResources().getColor(R.color.springColor));
+        mPaint.setStrokeWidth(10);
+    }
+
+    /**
+     * Sets the other end of the spring.
+     *
+     * @param height height of the mass, which is used to derive how to draw the spring
+     */
+    public void setMassHeight(float height) {
+        mLastHeight = height;
+        invalidate();
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        // Draws the spring
+        // 30px long, 15 sections
+        int num = 20;
+        float sectionLen = 150; // px
+        final float x = canvas.getWidth() / 2;
+        float y = 0;
+        float sectionHeight = mLastHeight / num;
+        float sectionWidth = (float) Math.sqrt(sectionLen * sectionLen
+                - sectionHeight * sectionHeight);
+        canvas.drawLine(x, 0, x + sectionWidth / 2, sectionHeight / 2, mPaint);
+        float lastX = x + sectionWidth / 2;
+        float lastY = sectionHeight / 2;
+        for (int i = 1; i < num; i++) {
+            canvas.drawLine(lastX, lastY, 2 * x - lastX, lastY + sectionHeight, mPaint);
+            lastX = 2 * x - lastX;
+            lastY = lastY + sectionHeight;
+        }
+        canvas.drawLine(lastX, lastY, x, mLastHeight, mPaint);
+    }
+}
diff --git a/samples/SupportAppNavigation/Android.mk b/samples/SupportAppNavigation/Android.mk
deleted file mode 100644
index ea9322f..0000000
--- a/samples/SupportAppNavigation/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := samples tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := SupportAppNavigation
-
-LOCAL_STATIC_ANDROID_LIBRARIES += android-support-v4
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MIN_SDK_VERSION := 8
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/SupportAppNavigation/build.gradle b/samples/SupportAppNavigation/build.gradle
new file mode 100644
index 0000000..fdbad1b
--- /dev/null
+++ b/samples/SupportAppNavigation/build.gradle
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+apply plugin: 'com.android.application'
+
+dependencies {
+    compile project(':support-v4')
+}
+
+android {
+    compileSdkVersion project.ext.currentSdk
+
+    defaultConfig {
+        minSdkVersion 14
+    }
+
+    sourceSets {
+        main.manifest.srcFile 'AndroidManifest.xml'
+        main.java.srcDirs = ['src']
+        main.res.srcDirs = ['res']
+    }
+
+    lintOptions {
+        abortOnError true
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
+}
diff --git a/samples/SupportDesignDemos/Android.mk b/samples/SupportDesignDemos/Android.mk
deleted file mode 100644
index 4c74ad2..0000000
--- a/samples/SupportDesignDemos/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the samples.
-# We need to add some special AAPT flags to generate R classes
-# for resources that are included from the libraries.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := SupportDesignDemos
-LOCAL_MODULE_TAGS := samples
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 7
-LOCAL_DEX_PREOPT := false
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-v4 \
-        android-support-v7-appcompat \
-        android-support-v7-recyclerview \
-        android-support-transition \
-        android-support-design
-LOCAL_AAPT_FLAGS := --no-version-vectors
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-include $(BUILD_PACKAGE)
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java
index 2f9b79f..3bd06f3 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SimpleStringRecyclerViewAdapter.java
@@ -16,17 +16,15 @@
 
 package com.example.android.support.design.widget;
 
-import com.example.android.support.design.R;
-
 import android.content.Context;
-import android.graphics.Color;
 import android.support.v7.widget.RecyclerView;
-import android.text.Layout;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import com.example.android.support.design.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java
index 1b79543..14df2b1 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/SnackbarWithFloatingActionButton.java
@@ -18,12 +18,6 @@
 
 import com.example.android.support.design.R;
 
-import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.ViewGroup;
-
 /**
  * This demonstrates idiomatic usage of Snackbar with a Floating Action Button present
  */
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java
index 7e51de3..ba38f3e 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutLayoutItemsUsage.java
@@ -16,24 +16,11 @@
 
 package com.example.android.support.design.widget;
 
-import com.example.android.support.design.Cheeses;
-import com.example.android.support.design.R;
-
 import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Random;
+import com.example.android.support.design.R;
 
 /**
  * This demonstrates idiomatic usage of TabLayout with items inflated from the layout
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
index 12e1842..b276305 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
@@ -29,11 +29,11 @@
 import android.widget.RadioButton;
 import android.widget.RadioGroup;
 import android.widget.TextView;
+
 import com.example.android.support.design.Cheeses;
 import com.example.android.support.design.R;
 
 import java.util.ArrayList;
-import java.util.Random;
 
 /**
  * This demonstrates idiomatic usage of TabLayout with a ViewPager
diff --git a/samples/SupportLeanbackDemos/Android.mk b/samples/SupportLeanbackDemos/Android.mk
deleted file mode 100644
index 5a8d110..0000000
--- a/samples/SupportLeanbackDemos/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the samples.
-# We need to add some special AAPT flags to generate R classes
-# for resources that are included from the libraries.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := SupportLeanbackDemos
-LOCAL_MODULE_TAGS := samples tests
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 17
-LOCAL_DEX_PREOPT := false
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-compat \
-        android-support-core-ui \
-        android-support-media-compat \
-        android-support-fragment \
-        android-support-v7-recyclerview \
-        android-support-v17-leanback \
-        android-support-v17-preference-leanback \
-        android-support-v7-preference \
-        android-support-v14-preference
-
-include $(BUILD_PACKAGE)
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
index 2f0e861..7b3f8f7 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
@@ -14,7 +14,6 @@
 package com.example.android.leanback;
 
 import android.app.Fragment;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
index c78319d..395c498 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
@@ -17,7 +17,6 @@
 package com.example.android.leanback;
 
 import android.support.v4.app.Fragment;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java
index 6d376f0..57eae06 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsDescriptionPresenter.java
@@ -14,7 +14,6 @@
 package com.example.android.leanback;
 
 import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
-import android.support.v17.leanback.widget.DetailsOverviewRow;
 
 public class DetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter {
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
index 3807de1..6d4deb0 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
@@ -230,6 +230,10 @@
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
+                final Context context = getActivity();
+                if (context == null) {
+                    return;
+                }
                 if (TEST_OVERVIEW_ROW_ON_SECOND) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
                     listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
@@ -240,7 +244,6 @@
                     mRowsAdapter.add(0, new ListRow(header, listRowAdapter));
                 }
 
-                final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
                 dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
                         mPhotoItem.getImageResourceId(), context.getTheme()));
@@ -262,6 +265,9 @@
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
+                if (getActivity() == null) {
+                    return;
+                }
                 for (int i = 0; i < NUM_ROWS; ++i) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
                     listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
index 697b1e0..6c14029 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
@@ -233,6 +233,10 @@
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
+                final Context context = getActivity();
+                if (context == null) {
+                    return;
+                }
                 if (TEST_OVERVIEW_ROW_ON_SECOND) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
                     listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
@@ -243,7 +247,6 @@
                     mRowsAdapter.add(0, new ListRow(header, listRowAdapter));
                 }
 
-                final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
                 dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
                         mPhotoItem.getImageResourceId(), context.getTheme()));
@@ -265,6 +268,9 @@
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
+                if (getActivity() == null) {
+                    return;
+                }
                 for (int i = 0; i < NUM_ROWS; ++i) {
                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
                     listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java
index 2fe9bb9..a30a3fd 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingActivity.java
@@ -15,7 +15,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.ViewTreeObserver;
 
 public class OnboardingActivity extends Activity {
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java
index f0a2275..177eced 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingSupportActivity.java
@@ -18,7 +18,6 @@
 
 import android.support.v4.app.FragmentActivity;
 import android.os.Bundle;
-import android.view.ViewTreeObserver;
 
 public class OnboardingSupportActivity extends FragmentActivity {
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
index 2687d70..aeab26d 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
@@ -22,12 +22,10 @@
 import android.support.v17.leanback.app.PlaybackFragmentGlueHost;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.util.Log;
 
@@ -57,7 +55,6 @@
     private static final int ROW_CONTROLS = 0;
 
     private PlaybackControlGlue mGlue;
-    private ListRowPresenter mListRowPresenter;
 
     @Override
     public SparseArrayObjectAdapter getAdapter() {
@@ -104,22 +101,10 @@
         };
 
         mGlue.setHost(new PlaybackFragmentGlueHost(this));
-        mListRowPresenter = new ListRowPresenter();
+        ClassPresenterSelector classPresenterSelector = new ClassPresenterSelector();
+        classPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
 
-        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object object) {
-                if (object instanceof PlaybackControlsRow) {
-                    return mGlue.getControlsRowPresenter();
-                } else if (object instanceof ListRow) {
-                    return mListRowPresenter;
-                }
-                throw new IllegalArgumentException("Unhandled object: " + object);
-            }
-        }));
-
-        // Add the controls row
-        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
+        setAdapter(new SparseArrayObjectAdapter(classPresenterSelector));
 
         // Add related content rows
         for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index 21086d9..87b5983 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -19,6 +19,7 @@
 import android.os.Handler;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
@@ -27,7 +28,6 @@
 import android.support.v17.leanback.widget.PlaybackControlsRow;
 import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
@@ -56,8 +56,6 @@
     private static final int ROW_CONTROLS = 0;
 
     private PlaybackControlHelper mGlue;
-    private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
-    private ListRowPresenter mListRowPresenter;
     final Handler mHandler = new Handler();
 
     // Artificial delay to simulate a media being prepared. The onRowChanged callback should be
@@ -143,21 +141,14 @@
         }, MEDIA_PREPARATION_DELAY);
         mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
 
-        mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
-        mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
-        mListRowPresenter = new ListRowPresenter();
+        PlaybackControlsRowPresenter playbackControlsRowPresenter =
+                mGlue.createControlsRowAndPresenter();
+        playbackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
+        ClassPresenterSelector selector = new ClassPresenterSelector();
+        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
+        selector.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
 
-        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object object) {
-                if (object instanceof PlaybackControlsRow) {
-                    return mPlaybackControlsRowPresenter;
-                } else if (object instanceof ListRow) {
-                    return mListRowPresenter;
-                }
-                throw new IllegalArgumentException("Unhandled object: " + object);
-            }
-        }));
+        setAdapter(new SparseArrayObjectAdapter(selector));
 
         // Add the controls row
         getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
index 879ee69..7e5e8f9 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
@@ -30,7 +31,6 @@
 import android.support.v17.leanback.widget.PlaybackControlsRow;
 import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
@@ -59,8 +59,6 @@
     private static final int ROW_CONTROLS = 0;
 
     private PlaybackControlSupportHelper mGlue;
-    private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
-    private ListRowPresenter mListRowPresenter;
     final Handler mHandler = new Handler();
 
     // Artificial delay to simulate a media being prepared. The onRowChanged callback should be
@@ -146,21 +144,14 @@
         }, MEDIA_PREPARATION_DELAY);
         mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
 
-        mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
-        mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
-        mListRowPresenter = new ListRowPresenter();
+        PlaybackControlsRowPresenter playbackControlsRowPresenter =
+                mGlue.createControlsRowAndPresenter();
+        playbackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
+        ClassPresenterSelector selector = new ClassPresenterSelector();
+        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
+        selector.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
 
-        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object object) {
-                if (object instanceof PlaybackControlsRow) {
-                    return mPlaybackControlsRowPresenter;
-                } else if (object instanceof ListRow) {
-                    return mListRowPresenter;
-                }
-                throw new IllegalArgumentException("Unhandled object: " + object);
-            }
-        }));
+        setAdapter(new SparseArrayObjectAdapter(selector));
 
         // Add the controls row
         getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
index d83f917..4315a05 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
@@ -25,12 +25,10 @@
 import android.support.v17.leanback.app.PlaybackSupportFragmentGlueHost;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.util.Log;
 
@@ -60,7 +58,6 @@
     private static final int ROW_CONTROLS = 0;
 
     private PlaybackControlGlue mGlue;
-    private ListRowPresenter mListRowPresenter;
 
     @Override
     public SparseArrayObjectAdapter getAdapter() {
@@ -107,22 +104,10 @@
         };
 
         mGlue.setHost(new PlaybackSupportFragmentGlueHost(this));
-        mListRowPresenter = new ListRowPresenter();
+        ClassPresenterSelector classPresenterSelector = new ClassPresenterSelector();
+        classPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
 
-        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object object) {
-                if (object instanceof PlaybackControlsRow) {
-                    return mGlue.getControlsRowPresenter();
-                } else if (object instanceof ListRow) {
-                    return mListRowPresenter;
-                }
-                throw new IllegalArgumentException("Unhandled object: " + object);
-            }
-        }));
-
-        // Add the controls row
-        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
+        setAdapter(new SparseArrayObjectAdapter(classPresenterSelector));
 
         // Add related content rows
         for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
diff --git a/samples/SupportLeanbackJank/Android.mk b/samples/SupportLeanbackJank/Android.mk
deleted file mode 100644
index 21e3f31..0000000
--- a/samples/SupportLeanbackJank/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the samples.
-# We need to add some special AAPT flags to generate R classes
-# for resources that are included from the libraries.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := SupportLeanbackJank
-LOCAL_MODULE_TAGS := samples tests
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 17
-LOCAL_DEX_PREOPT := false
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := glide
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-compat \
-        android-support-core-ui \
-        android-support-media-compat \
-        android-support-fragment \
-        android-support-v7-recyclerview \
-        android-support-v17-leanback \
-        android-support-v17-preference-leanback \
-        android-support-v7-preference \
-        android-support-v14-preference
-
-include $(BUILD_PACKAGE)
diff --git a/samples/SupportLeanbackShowcase/app/src/main/Android.mk b/samples/SupportLeanbackShowcase/app/src/main/Android.mk
deleted file mode 100644
index 76c933e..0000000
--- a/samples/SupportLeanbackShowcase/app/src/main/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-#LOCAL_JACK_FLAGS := -D jack.import.jar.debug-info=false
-
-# Build the samples.
-# We need to add some special AAPT flags to generate R classes
-# for resources that are included from the libraries.
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := SupportLeanbackShowcase
-LOCAL_MODULE_TAGS := samples tests
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 17
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-        android-support-v4 \
-        android-support-v7-recyclerview \
-        android-support-v7-preference \
-        android-support-v7-appcompat \
-        android-support-v14-preference \
-        android-support-v17-preference-leanback \
-        android-support-v17-leanback \
-	gson-x \
-	picasso-x
-LOCAL_RESOURCE_DIR = \
-        $(LOCAL_PATH)/res \
-        frameworks/support/v17/preference-leanback/res \
-        frameworks/support/v7/preference/res \
-        frameworks/support/v7/appcompat/res \
-        frameworks/support/v14/preference/res \
-        frameworks/support/v17/leanback/res \
-        frameworks/support/v7/recyclerview/res
-LOCAL_AAPT_FLAGS := \
-        --auto-add-overlay \
-        --extra-packages android.support.v17.leanback \
-        --extra-packages android.support.v17.preference \
-        --extra-packages android.support.v7.preference \
-        --extra-packages android.support.v14.preference \
-        --extra-packages android.support.v7.appcompat \
-        --extra-packages android.support.v7.recyclerview
-include $(BUILD_PACKAGE)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
-	gson-x:../../../libs/gson-1.7.2.jar \
-	picasso-x:../../../libs/picasso-2.5.2.jar \
-
-include $(BUILD_MULTI_PREBUILT)
diff --git a/samples/SupportPercentDemos/Android.mk b/samples/SupportPercentDemos/Android.mk
deleted file mode 100644
index 54c980f..0000000
--- a/samples/SupportPercentDemos/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the samples.
-# We need to add some special AAPT flags to generate R classes
-# for resources that are included from the libraries.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := SupportPercentDemos
-LOCAL_MODULE_TAGS := samples
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 7
-LOCAL_DEX_PREOPT := false
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-percent \
-        android-support-v4 \
-        android-support-v13
-include $(BUILD_PACKAGE)
diff --git a/samples/SupportPreferenceDemos/Android.mk b/samples/SupportPreferenceDemos/Android.mk
deleted file mode 100644
index f131aa0..0000000
--- a/samples/SupportPreferenceDemos/Android.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the samples.
-# We need to add some special AAPT flags to generate R classes
-# for resources that are included from the libraries.
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := SupportPreferenceDemos
-LOCAL_MODULE_TAGS := samples
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 14
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    android-support-v4 \
-    android-support-v7-appcompat \
-    android-support-v7-preference \
-    android-support-v7-recyclerview \
-    android-support-v14-preference \
-    android-support-v17-leanback \
-    android-support-v17-preference-leanback \
-
-LOCAL_RESOURCE_DIR = \
-    $(LOCAL_PATH)/res \
-    frameworks/support/v7/appcompat/res \
-    frameworks/support/v7/preference/res \
-    frameworks/support/v7/recyclerview/res \
-    frameworks/support/v14/preference/res \
-    frameworks/support/v17/leanback/res \
-    frameworks/support/v17/preference-leanback/res
-
-LOCAL_AAPT_FLAGS := \
-        --auto-add-overlay \
-        --extra-packages android.support.v7.appcompat \
-        --extra-packages android.support.v7.preference \
-        --extra-packages android.support.v7.recyclerview \
-        --extra-packages android.support.v14.preference \
-        --extra-packages android.support.v17.leanback \
-        --extra-packages android.support.v17.preference \
-        --no-version-vectors
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-include $(BUILD_PACKAGE)
diff --git a/samples/SupportTransitionDemos/Android.mk b/samples/SupportTransitionDemos/Android.mk
deleted file mode 100644
index e822a0a..0000000
--- a/samples/SupportTransitionDemos/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build the samples.
-# We need to add some special AAPT flags to generate R classes
-# for resources that are included from the libraries.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := SupportTransitionDemos
-LOCAL_MODULE_TAGS := samples
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 14
-LOCAL_DEX_PREOPT := false
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-v4 \
-        android-support-v7-appcompat \
-        android-support-transition
-LOCAL_AAPT_FLAGS := --no-version-vectors --no-version-transitions
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-include $(BUILD_PACKAGE)
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
index 0a085f2..f375e4d 100644
--- a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
@@ -16,18 +16,12 @@
 
 package com.example.android.support.transition.widget;
 
-import android.support.annotation.LayoutRes;
-import com.example.android.support.transition.R;
-
 import android.os.Bundle;
-import android.support.transition.Scene;
-import android.support.transition.TransitionManager;
+import android.support.annotation.LayoutRes;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
+
+import com.example.android.support.transition.R;
 
 /**
  * Base class for usages of the Transition API.
diff --git a/samples/SupportVectorDrawableDemos/Android.mk b/samples/SupportVectorDrawableDemos/Android.mk
deleted file mode 100644
index 376f841..0000000
--- a/samples/SupportVectorDrawableDemos/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := samples tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MIN_SDK_VERSION := 14
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := SupportVectorDrawableDemos
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-v7-appcompat \
-        android-support-animatedvectordrawable \
-        android-support-vectordrawable \
-        android-support-v4
-
-LOCAL_AAPT_FLAGS += --no-version-vectors
-
-include $(BUILD_PACKAGE)
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/settings.gradle b/settings.gradle
index 1597c2e..b6c8b40 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -97,6 +97,15 @@
 include ':support-instantvideo'
 project(':support-instantvideo').projectDir = new File(rootDir, 'instantvideo')
 
+include ':support-emoji'
+project(':support-emoji').projectDir = new File(rootDir, 'emoji/core')
+
+include ':support-emoji-typeface'
+project(':support-emoji-typeface').projectDir = new File(rootDir, 'emoji/bundled-typeface')
+
+include ':support-emoji-appcompat'
+project(':support-emoji-appcompat').projectDir = new File(rootDir, 'emoji/appcompat')
+
 /////////////////////////////
 //
 // Samples
@@ -135,6 +144,21 @@
 include ':support-vector-drawable-demos'
 project(':support-vector-drawable-demos').projectDir = new File(samplesRoot, 'SupportVectorDrawableDemos')
 
+include ':support-animation-demos'
+project(':support-animation-demos').projectDir = new File(samplesRoot, 'SupportAnimationDemos')
+
+include ':support-app-navigation'
+project(':support-app-navigation').projectDir = new File(samplesRoot, 'SupportAppNavigation')
+
+/////////////////////////////
+//
+// Testing libraries
+//
+/////////////////////////////
+
+include ':support-testutils'
+project(':support-testutils').projectDir = new File(rootDir, 'testutils')
+
 /////////////////////////////
 //
 // External
@@ -148,3 +172,7 @@
 
 include ':jdiff'
 project(':jdiff').projectDir = new File(externalRoot, 'jdiff')
+
+///// FLATFOOT START
+
+///// FLATFOOT END
\ No newline at end of file
diff --git a/samples/Android.mk b/testutils/NO_DOCS
similarity index 69%
rename from samples/Android.mk
rename to testutils/NO_DOCS
index cc329fe..4dad694 100644
--- a/samples/Android.mk
+++ b/testutils/NO_DOCS
@@ -1,4 +1,4 @@
-# Copyright (C) 2016 The Android Open Source Project
+# Copyright (C) 2017 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.
@@ -12,6 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
+Having this file, named NO_DOCS, in a directory will prevent
+Android javadocs from being generated for java files under
+the directory. This is especially useful for test projects.
diff --git a/testutils/build.gradle b/testutils/build.gradle
new file mode 100644
index 0000000..f155ded
--- /dev/null
+++ b/testutils/build.gradle
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+apply plugin: 'java'
+
+dependencies {
+    compile libs.junit
+}
+
+targetCompatibility = '1.7'
+sourceCompatibility = '1.7'
diff --git a/customtabs/tests/src/android/support/customtabs/PollingCheck.java b/testutils/src/main/java/android/support/testutils/PollingCheck.java
similarity index 68%
rename from customtabs/tests/src/android/support/customtabs/PollingCheck.java
rename to testutils/src/main/java/android/support/testutils/PollingCheck.java
index 0163e94..8e85896 100644
--- a/customtabs/tests/src/android/support/customtabs/PollingCheck.java
+++ b/testutils/src/main/java/android/support/testutils/PollingCheck.java
@@ -14,29 +14,37 @@
  * limitations under the License.
  */
 
-package android.support.customtabs;
+package android.support.testutils;
 
-import junit.framework.Assert;
+import org.junit.Assert;
 
-import java.util.concurrent.Callable;
-
+/**
+ * Utility used for testing that allows to poll for a certain condition to happen within a timeout.
+ */
 public abstract class PollingCheck {
+    private static final long DEFAULT_TIMEOUT = 3000;
     private static final long TIME_SLICE = 50;
-    private long mTimeout = 3000;
+    private final long mTimeout;
 
+    /**
+     * The condition that the PollingCheck should use to proceed successfully.
+     */
     public interface PollingCheckCondition {
+        /**
+         * @return Whether the polling condition has been met.
+         */
         boolean canProceed();
     }
 
-    public PollingCheck() {
-    }
-
     public PollingCheck(long timeout) {
         mTimeout = timeout;
     }
 
     protected abstract boolean check();
 
+    /**
+     * Start running the polling check.
+     */
     public void run() {
         if (check()) {
             return;
@@ -60,22 +68,12 @@
         Assert.fail("unexpected timeout");
     }
 
-    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
-            throws Exception {
-        while (timeout > 0) {
-            if (condition.call()) {
-                return;
-            }
-
-            Thread.sleep(TIME_SLICE);
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail(message.toString());
-    }
-
+    /**
+     * Instantiate and start polling for a given condition with a default 3000ms timeout.
+     * @param condition The condition to check for success.
+     */
     public static void waitFor(final PollingCheckCondition condition) {
-        new PollingCheck() {
+        new PollingCheck(DEFAULT_TIMEOUT) {
             @Override
             protected boolean check() {
                 return condition.canProceed();
@@ -83,6 +81,11 @@
         }.run();
     }
 
+    /**
+     * Instantiate and start polling for a given condition.
+     * @param timeout Time out in ms
+     * @param condition The condition to check for success.
+     */
     public static void waitFor(long timeout, final PollingCheckCondition condition) {
         new PollingCheck(timeout) {
             @Override
diff --git a/tv-provider/src/android/support/media/tv/Channel.java b/tv-provider/src/android/support/media/tv/Channel.java
index 5e158e2..460a6a7 100644
--- a/tv-provider/src/android/support/media/tv/Channel.java
+++ b/tv-provider/src/android/support/media/tv/Channel.java
@@ -31,9 +31,36 @@
 import android.text.TextUtils;
 
 import java.net.URISyntaxException;
+import java.nio.charset.Charset;
 
 /**
- * A convenience class to create and insert channel entries into the database.
+ * A convenience class to access {@link TvContractCompat.Channels} entries in the system content
+ * provider.
+ *
+ * <p>This class makes it easy to insert or retrieve a channel from the system content provider,
+ * which is defined in {@link TvContractCompat}.
+ *
+ * <p>Usage example when inserting a channel:
+ * <pre>
+ * Channel channel = new Channel.Builder()
+ *         .setDisplayName("Channel Name")
+ *         .setDescription("Channel description")
+ *         .setType(Channels.TYPE_PREVIEW)
+ *         // Set more attributes...
+ *         .build();
+ * Uri channelUri = getContentResolver().insert(Channels.CONTENT_URI, channel.toContentValues());
+ * </pre>
+ *
+ * <p>Usage example when retrieving a channel:
+ * <pre>
+ * Channel channel;
+ * try (Cursor cursor = resolver.query(channelUri, null, null, null, null)) {
+ *     if (cursor != null && cursor.getCount() != 0) {
+ *         cursor.moveToNext();
+ *         channel = Channel.fromCursor(cursor);
+ *     }
+ * }
+ * </pre>
  */
 public final class Channel {
     /**
@@ -54,7 +81,6 @@
     private final String mDisplayNumber;
     private final String mDisplayName;
     private final String mDescription;
-    private final String mChannelLogo;
     private final String mVideoFormat;
     private final int mOriginalNetworkId;
     private final int mTransportStreamId;
@@ -91,7 +117,6 @@
         mAppLinkIconUri = builder.mAppLinkIconUri;
         mAppLinkPosterArtUri = builder.mAppLinkPosterArtUri;
         mAppLinkIntentUri = builder.mAppLinkIntentUri;
-        mChannelLogo = builder.mChannelLogo;
         mInternalProviderData = builder.mInternalProviderData;
         mNetworkAffiliation = builder.mNetworkAffiliation;
         mSearchable = builder.mSearchable;
@@ -224,13 +249,6 @@
 
 
     /**
-     * @return The value of {@link Channels.Logo} for the channel.
-     */
-    public String getChannelLogo() {
-        return mChannelLogo;
-    }
-
-    /**
      * @return The value of {@link Channels#COLUMN_NETWORK_AFFILIATION} for the channel.
      */
     public String getNetworkAffiliation() {
@@ -309,7 +327,6 @@
                 + ", displayNumber=" + mDisplayNumber
                 + ", displayName=" + mDisplayName
                 + ", description=" + mDescription
-                + ", channelLogo=" + mChannelLogo
                 + ", videoFormat=" + mVideoFormat
                 + ", appLinkText=" + mAppLinkText + "}";
     }
@@ -580,7 +597,6 @@
         private String mDisplayNumber;
         private String mDisplayName;
         private String mDescription;
-        private String mChannelLogo;
         private String mVideoFormat;
         private int mOriginalNetworkId = INVALID_INTEGER_VALUE;
         private int mTransportStreamId;
@@ -620,7 +636,6 @@
             mAppLinkIconUri = other.mAppLinkIconUri;
             mAppLinkPosterArtUri = other.mAppLinkPosterArtUri;
             mAppLinkIntentUri = other.mAppLinkIntentUri;
-            mChannelLogo = other.mChannelLogo;
             mInternalProviderData = other.mInternalProviderData;
             mNetworkAffiliation = other.mNetworkAffiliation;
             mSearchable = other.mSearchable;
@@ -648,8 +663,10 @@
          *
          * @param packageName The value of {@link Channels#COLUMN_PACKAGE_NAME} for the channel.
          * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
          */
-        public Builder setPackageName(String packageName) {
+        @RestrictTo(LIBRARY_GROUP)
+        Builder setPackageName(String packageName) {
             mPackageName = packageName;
             return this;
         }
@@ -710,18 +727,6 @@
         }
 
         /**
-         * Sets the logo of the channel.
-         *
-         * @param channelLogo The Uri corresponding to the logo for the channel.
-         * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Channels.Logo
-         */
-        public Builder setChannelLogo(String channelLogo) {
-            mChannelLogo = channelLogo;
-            return this;
-        }
-
-        /**
          * Sets the video format of the Channel.
          *
          * @param videoFormat The value of {@link Channels#COLUMN_VIDEO_FORMAT} for the channel.
@@ -787,7 +792,7 @@
          * @return This Builder object to allow for chaining of calls to builder methods.
          */
         public Builder setInternalProviderData(String internalProviderData) {
-            mInternalProviderData = internalProviderData.getBytes();
+            mInternalProviderData = internalProviderData.getBytes(Charset.defaultCharset());
             return this;
         }
 
diff --git a/tv-provider/src/android/support/media/tv/Program.java b/tv-provider/src/android/support/media/tv/Program.java
index 71c51fb..453e21a 100644
--- a/tv-provider/src/android/support/media/tv/Program.java
+++ b/tv-provider/src/android/support/media/tv/Program.java
@@ -43,7 +43,34 @@
 import java.util.Objects;
 
 /**
- * A convenience class to create and insert program information into the database.
+ * A convenience class to access {@link TvContractCompat.Programs} entries in the system content
+ * provider.
+ *
+ * <p>This class makes it easy to insert or retrieve a program from the system content provider,
+ * which is defined in {@link TvContractCompat}.
+ *
+ * <p>Usage example when inserting a program:
+ * <pre>
+ * Program program = new Program.Builder()
+ *         .setChannelId(channel.getId())
+ *         .setTitle("Program Title")
+ *         .setDescription("Program Description")
+ *         .setPosterArtUri(Uri.parse("http://example.com/poster_art.png"))
+ *         // Set more attributes...
+ *         .build();
+ * Uri programUri = getContentResolver().insert(Programs.CONTENT_URI, program.toContentValues());
+ * </pre>
+ *
+ * <p>Usage example when retrieving a program:
+ * <pre>
+ * Program program;
+ * try (Cursor cursor = resolver.query(programUri, null, null, null, null)) {
+ *     if (cursor != null && cursor.getCount() != 0) {
+ *         cursor.moveToNext();
+ *         program = Program.fromCursor(cursor);
+ *     }
+ * }
+ * </pre>
  */
 public final class Program implements Comparable<Program> {
     /**
@@ -546,16 +573,16 @@
                 && Arrays.equals(mContentRatings, program.mContentRatings)
                 && Arrays.equals(mAudioLanguages, program.mAudioLanguages)
                 && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
-                        || Objects.equals(mSearchable, program.mSearchable)
+                        || (Objects.equals(mSearchable, program.mSearchable)
                         && Objects.equals(mInternalProviderFlag1, program.mInternalProviderFlag1)
                         && Objects.equals(mInternalProviderFlag2, program.mInternalProviderFlag2)
                         && Objects.equals(mInternalProviderFlag3, program.mInternalProviderFlag3)
-                        && Objects.equals(mInternalProviderFlag4, program.mInternalProviderFlag4))
+                        && Objects.equals(mInternalProviderFlag4, program.mInternalProviderFlag4)))
                 && (Build.VERSION.SDK_INT < Build.VERSION_CODES.N
-                        || Objects.equals(mSeasonTitle, program.mSeasonTitle)
-                        && Objects.equals(mRecordingProhibited, program.mRecordingProhibited))
+                        || (Objects.equals(mSeasonTitle, program.mSeasonTitle)
+                        && Objects.equals(mRecordingProhibited, program.mRecordingProhibited)))
                 && (!BuildCompat.isAtLeastO()
-                        || Objects.equals(mInternalProviderId, program.mInternalProviderId)
+                        || (Objects.equals(mInternalProviderId, program.mInternalProviderId)
                         && Objects.equals(mPreviewVideoUri, program.mPreviewVideoUri)
                         && Objects.equals(mLastPlaybackPositionMillis,
                                 program.mLastPlaybackPositionMillis)
@@ -579,7 +606,7 @@
                         && Objects.equals(mInteractionCount, program.mInteractionCount)
                         && Objects.equals(mAuthor, program.mAuthor)
                         && Objects.equals(mReviewRatingStyle, program.mReviewRatingStyle)
-                        && Objects.equals(mReviewRating, program.mReviewRating));
+                        && Objects.equals(mReviewRating, program.mReviewRating)));
     }
 
     /**
diff --git a/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java b/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
index 901bf06..6b394e6 100644
--- a/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
+++ b/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
@@ -267,6 +267,7 @@
         return result;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
         setValues(restoreValue ? getPersistedStringSet(mValues) : (Set<String>) defaultValue);
diff --git a/v17/leanback/Android.mk b/v17/leanback/Android.mk
index c6a50b4..6e62436 100644
--- a/v17/leanback/Android.mk
+++ b/v17/leanback/Android.mk
@@ -66,7 +66,7 @@
     android-support-v17-leanback
 LOCAL_ADDITIONAL_JAVA_DIR := $(call intermediates-dir-for,JAVA_LIBRARIES,android-support-v17-leanback-res,,COMMON)/src
 LOCAL_IS_HOST_MODULE := false
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := external/doclava/res/assets/templates-sdk
 LOCAL_DROIDDOC_OPTIONS := \
     -offlinemode \
     -hdf android.whichdoc offline \
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
index 38a80f2..211e8fc 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
@@ -26,12 +26,10 @@
 import android.transition.TransitionManager;
 import android.transition.TransitionSet;
 import android.transition.TransitionValues;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.view.View;
 import android.view.ViewGroup;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 
 @RequiresApi(19)
diff --git a/v17/leanback/res/layout/lb_playback_controls_row.xml b/v17/leanback/res/layout/lb_playback_controls_row.xml
index e3893b3..b449fa9 100644
--- a/v17/leanback/res/layout/lb_playback_controls_row.xml
+++ b/v17/leanback/res/layout/lb_playback_controls_row.xml
@@ -46,6 +46,7 @@
 
         <LinearLayout
             android:id="@+id/controls_card_right_panel"
+            android:layout_gravity="bottom"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:clipChildren="false"
diff --git a/v17/leanback/res/values-af/strings.xml b/v17/leanback/res/values-af/strings.xml
index 2f2ca18..3ced389 100644
--- a/v17/leanback/res/values-af/strings.xml
+++ b/v17/leanback/res/values-af/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktiveer onderskrifte"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiveer onderskrifte"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Voer prent in prentmodus in"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediakontroles word gewys"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediakontroles word versteek; druk D-paneel om te wys"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooi"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Gaan voort"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-am/strings.xml b/v17/leanback/res/values-am/strings.xml
index c4b461a..8729a23 100644
--- a/v17/leanback/res/values-am/strings.xml
+++ b/v17/leanback/res/values-am/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አንቃ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አሰናክል"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ስዕሉን በስዕል ሁነታ ውስጥ ያክሉ"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"የሚዲያ መቆጣጠሪያዎች እንዲታዩ ተደርገዋል"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"የሚዲያ መቆጣጠሪያዎች ተደብቀዋል። d-pad ን ለማሳየት ይጫኑ"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ጨርስ"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ቀጥል"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ar/strings.xml b/v17/leanback/res/values-ar/strings.xml
index cda830c..4c86a05 100644
--- a/v17/leanback/res/values-ar/strings.xml
+++ b/v17/leanback/res/values-ar/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"تمكين الترجمة المصاحبة"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"تعطيل الترجمة المصاحبة"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"إدخال صورة في وضع الصورة"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"تم إظهار عناصر التحكم في الوسائط"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"‏تم إخفاء عناصر التحكم في الوسائط، يمكنك الضغط على d-pad لإظهارها"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"إنهاء"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"متابعة"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-az/strings.xml b/v17/leanback/res/values-az/strings.xml
index f9f0277..19512e4 100644
--- a/v17/leanback/res/values-az/strings.xml
+++ b/v17/leanback/res/values-az/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Qapalı çəkilişi aktiv edin"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Qapalı çəkilişi deaktiv edin"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Şəkil içində Şəkil Rejiminə daxil olun"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media idarəetmələri açıqdır"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media idarəetmələri gizlidir, göstərmək üçün d-pad\'i basın"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Bitir"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davam edin"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-b+sr+Latn/strings.xml b/v17/leanback/res/values-b+sr+Latn/strings.xml
index 5c466fb..1ae1bd4 100644
--- a/v17/leanback/res/values-b+sr+Latn/strings.xml
+++ b/v17/leanback/res/values-b+sr+Latn/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogući titlove"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogući titlove"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Uđi u režim Slika u slici"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrole za medije su prikazane"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrole za medije su skrivene, pritisnite kontrole za kretanje da biste ih prikazali"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dovrši"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastavi"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-be/strings.xml b/v17/leanback/res/values-be/strings.xml
index b9e72bb..0857ec1 100644
--- a/v17/leanback/res/values-be/strings.xml
+++ b/v17/leanback/res/values-be/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Уключыць схаваныя цітры"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Адключыць схаваныя цітры"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Калі ласка, увядзіце выяву ў рэжыме Выяў"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Элементы кіравання мультымедыя паказаны"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Элементы кіравання мультымедыя схаваны. Каб паказаць іх, націсніце пераключальнік напрамкаў"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Завяршыць"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Далей"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-bg/strings.xml b/v17/leanback/res/values-bg/strings.xml
index 642abc5..32fa30b 100644
--- a/v17/leanback/res/values-bg/strings.xml
+++ b/v17/leanback/res/values-bg/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Активиране на субтитрите"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Деактивиране на субтитрите"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Вход в режима „Картина в картина“"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Контролите за мултимедия са показани"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Контролите за мултимедия са скрити. Натиснете контролния пад, за да се покажат"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Край"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Напред"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-bn/strings.xml b/v17/leanback/res/values-bn/strings.xml
index be98f58..f3d37a1 100644
--- a/v17/leanback/res/values-bn/strings.xml
+++ b/v17/leanback/res/values-bn/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"সাবটাইটেল সক্ষম করুন"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"সাবটাইটেল অক্ষম করুন"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ছবি মোডে ছবি লগান"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"মিডিয়ার নিয়ন্ত্রণগুলি দেখানো হয়েছে"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"মিডিয়ার নিয়ন্ত্রণগুলি লুকানো আছে, দেখার জন্য ডি-প্যাড টিপুন"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"শেষ করুন"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"চালিয়ে যান"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-bs/strings.xml b/v17/leanback/res/values-bs/strings.xml
index 63a76e2..6d17dff 100644
--- a/v17/leanback/res/values-bs/strings.xml
+++ b/v17/leanback/res/values-bs/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Uključi titlove"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Isključi titlove"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Uđi u način rada Slika u slici"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrole za medije su prikazane"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrole za medije su skrivene. Pritisnite d-pad da ih prikažete"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Završiti"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastaviti"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ca/strings.xml b/v17/leanback/res/values-ca/strings.xml
index 5567e23..ef0b2d2 100644
--- a/v17/leanback/res/values-ca/strings.xml
+++ b/v17/leanback/res/values-ca/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activa els subtítols tancats"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactiva els subtítols tancats"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entra al mode d\'imatge en imatge"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Es mostren els controls multimèdia"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"S\'han amagat els controls multimèdia; prem el teclat direccional per mostrar-los"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalitza"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-cs/strings.xml b/v17/leanback/res/values-cs/strings.xml
index a5fbfb5..54e5b55 100644
--- a/v17/leanback/res/values-cs/strings.xml
+++ b/v17/leanback/res/values-cs/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnout titulky"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnout titulky"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Přejít do režimu Obraz v obraze"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Ovládací prvky médií jsou zobrazeny"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Ovládací prvky médií jsou skryty, zobrazíte je stisknutím směrového přepínače"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončit"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovat"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-da/strings.xml b/v17/leanback/res/values-da/strings.xml
index 76062f5..cf0e26e 100644
--- a/v17/leanback/res/values-da/strings.xml
+++ b/v17/leanback/res/values-da/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér undertekster"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver undertekster"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Tilføj billedet i billedtilstand"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Knapperne til afspilning er synlige"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Knapperne til afspilning er skjult. Tryk på D-pad for at se dem"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Afslut"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsæt"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-de/strings.xml b/v17/leanback/res/values-de/strings.xml
index 53ad13a..b16548d 100644
--- a/v17/leanback/res/values-de/strings.xml
+++ b/v17/leanback/res/values-de/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Untertitel aktivieren"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Untertitel deaktivieren"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Bild-in-Bild-Modus aktivieren"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediensteuerelemente eingeblendet"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediensteuerelemente ausgeblendet. Drücke das Steuerkreuz, um die Steuerelemente wieder einzublenden."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fertigstellen"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Weiter"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-el/strings.xml b/v17/leanback/res/values-el/strings.xml
index 6dc20ef..39a6c21 100644
--- a/v17/leanback/res/values-el/strings.xml
+++ b/v17/leanback/res/values-el/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ενεργοποίηση υποτίτλων"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Απενεργοποίηση υποτίτλων"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Εισαγωγή εικόνας στη Λειτουργία εικόνας"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Εμφάνιση στοιχείων ελέγχου μέσων"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Απόκρυψη στοιχείων ελέγχου μέσων, πιέστε το d-pad για εμφάνιση"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Τέλος"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Συνέχεια"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-en-rAU/strings.xml b/v17/leanback/res/values-en-rAU/strings.xml
index 8032f7d..ddd47d0 100644
--- a/v17/leanback/res/values-en-rAU/strings.xml
+++ b/v17/leanback/res/values-en-rAU/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Enter Picture In Picture Mode"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media controls shown"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media controls hidden, press d-pad to show"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-en-rGB/strings.xml b/v17/leanback/res/values-en-rGB/strings.xml
index 8032f7d..ddd47d0 100644
--- a/v17/leanback/res/values-en-rGB/strings.xml
+++ b/v17/leanback/res/values-en-rGB/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Enter Picture In Picture Mode"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media controls shown"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media controls hidden, press d-pad to show"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-en-rIN/strings.xml b/v17/leanback/res/values-en-rIN/strings.xml
index 8032f7d..ddd47d0 100644
--- a/v17/leanback/res/values-en-rIN/strings.xml
+++ b/v17/leanback/res/values-en-rIN/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Enter Picture In Picture Mode"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media controls shown"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media controls hidden, press d-pad to show"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-es-rUS/strings.xml b/v17/leanback/res/values-es-rUS/strings.xml
index 8a81040..2969100 100644
--- a/v17/leanback/res/values-es-rUS/strings.xml
+++ b/v17/leanback/res/values-es-rUS/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activar el modo Imagen en imagen"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Se muestran los controles de medios"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Los controles de medios están ocultos; presiona el control direccional para mostrarlos"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-es/strings.xml b/v17/leanback/res/values-es/strings.xml
index 59f707b..94608a7 100644
--- a/v17/leanback/res/values-es/strings.xml
+++ b/v17/leanback/res/values-es/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activar modo Imagen en imagen"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Controles multimedia mostrados"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Controles multimedia ocultos (pulsa la cruceta para mostrarlos)"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-et/strings.xml b/v17/leanback/res/values-et/strings.xml
index 6d6bac8..44b9fc6 100644
--- a/v17/leanback/res/values-et/strings.xml
+++ b/v17/leanback/res/values-et/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Luba subtiitrid"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Keela subtiitrid"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Sisene režiimi Pilt pildis"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Meedia juhtnupud on kuvatud"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Meedia juhtnupud on peidetud, kuvamiseks vajutage DPAD-i"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Lõpeta"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jätka"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-eu/strings.xml b/v17/leanback/res/values-eu/strings.xml
index 98787d4..54837ed 100644
--- a/v17/leanback/res/values-eu/strings.xml
+++ b/v17/leanback/res/values-eu/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Gaitu azpitituluak"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desgaitu azpitituluak"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Aktibatu \"Argazkia argazkian\" modua"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Multimedia kontrolatzeko aukerak ikusgai"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Ezkutatuta daude multimedia kontrolatzeko aukerak. Erakusteko, sakatu nabigazio-gurutzea."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Amaitu"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jarraitu"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-fa/strings.xml b/v17/leanback/res/values-fa/strings.xml
index 3774bd2..e9f01c6 100644
--- a/v17/leanback/res/values-fa/strings.xml
+++ b/v17/leanback/res/values-fa/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"فعال کردن زیرنویس"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"غیرفعال کردن زیرنویس"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"وارد حالت تصویر در تصویر شوید"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"کنترل‌های رسانه نشان داده می‌شوند"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"‏کنترل‌های رسانه پنهان هستند، برای نمایش آن‌ها d-pad را فشار دهید"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"پایان"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ادامه"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-fi/strings.xml b/v17/leanback/res/values-fi/strings.xml
index 3444642..3ef86ee 100644
--- a/v17/leanback/res/values-fi/strings.xml
+++ b/v17/leanback/res/values-fi/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ota tekstitys käyttöön"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Poista tekstitys käytöstä"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Vaihda kuva kuvassa ‑tilaan"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediasäätimet näkyvissä"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediasäätimet piilotettu, näytä painamalla ohjaimen nuolia."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Valmis"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jatka"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-fr-rCA/strings.xml b/v17/leanback/res/values-fr-rCA/strings.xml
index 4c8cc19..34b6947 100644
--- a/v17/leanback/res/values-fr-rCA/strings.xml
+++ b/v17/leanback/res/values-fr-rCA/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer le sous-titrage"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver le sous-titrage"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activer le mode Incrustation d\'image"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Les commandes multimédias sont affichées"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Les commandes multimédias sont masquées, appuyez sur le pavé directionnel pour les afficher."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-fr/strings.xml b/v17/leanback/res/values-fr/strings.xml
index 9086fa1..0876dcc 100644
--- a/v17/leanback/res/values-fr/strings.xml
+++ b/v17/leanback/res/values-fr/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer les sous-titres"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver les sous-titres"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activer le mode PIP"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Les commandes multimédias sont affichées"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Les commandes multimédias sont masquées. Appuyez sur le pavé directionnel pour les afficher"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-gl/strings.xml b/v17/leanback/res/values-gl/strings.xml
index 2d2579b..702f5bc 100644
--- a/v17/leanback/res/values-gl/strings.xml
+++ b/v17/leanback/res/values-gl/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activar subtítulos"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactivar subtítulos"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activar o modo Imaxe superposta"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Móstranse os controis de recursos multimedia"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Os controis de recursos multimedia están ocultos. Preme d-pad para mostralos"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-gu/strings.xml b/v17/leanback/res/values-gu/strings.xml
index 569da29..bc021cb 100644
--- a/v17/leanback/res/values-gu/strings.xml
+++ b/v17/leanback/res/values-gu/strings.xml
@@ -48,6 +48,10 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ઉપશીર્ષક સક્ષમ કરો"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"વિગતવાર ઉપશીર્ષકોને અક્ષમ કરો"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ચિત્ર મોડમાં ચિત્ર દાખલ કરો"</string>
+    <!-- no translation found for lb_playback_controls_shown (6382160135512023238) -->
+    <skip />
+    <!-- no translation found for lb_playback_controls_hidden (8940984081242033574) -->
+    <skip />
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"સમાપ્ત કરો"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ચાલુ રાખો"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-hi/strings.xml b/v17/leanback/res/values-hi/strings.xml
index 1b73165..6c10c6c 100644
--- a/v17/leanback/res/values-hi/strings.xml
+++ b/v17/leanback/res/values-hi/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षक सक्षम करें"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षक अक्षम करें"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"चित्र मोड में चित्र डालें"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"मीडिया कंट्रोल दिखाए गए हैं"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"मीडिया नियंत्रण छिपे हुए हैं, दिखाने के लिए डी-पैड दबाएं"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त करें"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"जारी रखें"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-hr/strings.xml b/v17/leanback/res/values-hr/strings.xml
index 73c8dc6..06efef9 100644
--- a/v17/leanback/res/values-hr/strings.xml
+++ b/v17/leanback/res/values-hr/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogući titlove"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogući titlove"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Unos slike u načinu slike"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Medijske kontrole prikazane"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Medijske kontrole skrivene su, pritisnite D-pad za prikaz"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Završi"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastavi"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-hu/strings.xml b/v17/leanback/res/values-hu/strings.xml
index f30c4f6..7f26563 100644
--- a/v17/leanback/res/values-hu/strings.xml
+++ b/v17/leanback/res/values-hu/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Feliratok engedélyezése"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Feliratok letiltása"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Kép a képben mód indítása"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Médiavezérlők megjelenítve"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"A médiavezérlők el vannak rejtve. Megjelenítésükhöz nyomja le a d-padet."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Befejezés"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Folytatás"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-hy/strings.xml b/v17/leanback/res/values-hy/strings.xml
index edc1f47..8b612de 100644
--- a/v17/leanback/res/values-hy/strings.xml
+++ b/v17/leanback/res/values-hy/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Միացնել խորագրերը"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Անջատել խորագրերը"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Մուտք «Նկար նկարի մեջ» ռեժիմ"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Մեդիայի կառավարման տարրերը ցուցադրվում են"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Մեդիայի կառավարման տարրերը թաքցված են։ Ցուցադրելու համար սեղմեք d-pad-ը"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Վերջ"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Շարունակել"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-in/strings.xml b/v17/leanback/res/values-in/strings.xml
index 05e9dc9..bb92f5e 100644
--- a/v17/leanback/res/values-in/strings.xml
+++ b/v17/leanback/res/values-in/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktifkan Pembuatan Teks"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Nonaktifkan Pembuatan Teks"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Masukkan Foto Dalam Mode Foto"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrol media ditampilkan"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrol media disembunyikan, tekan d-pad untuk menampilkannya"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Lanjutkan"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-is/strings.xml b/v17/leanback/res/values-is/strings.xml
index 84b6430..6e8f560 100644
--- a/v17/leanback/res/values-is/strings.xml
+++ b/v17/leanback/res/values-is/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Kveikja á skjátextum"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Slökkva á skjátextum"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Skoða mynd í myndsniði"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Spilunarstýringar sýndar"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Spilunarstýringar faldar, ýttu á stefnuhnappa til að sýna þær"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Ljúka"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Halda áfram"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-it/strings.xml b/v17/leanback/res/values-it/strings.xml
index b0814d0..8127d5d 100644
--- a/v17/leanback/res/values-it/strings.xml
+++ b/v17/leanback/res/values-it/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Attiva sottotitoli"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disattiva sottotitoli"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Attiva modalità Picture-in-picture"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Controlli multimediali visualizzati"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Controlli multimediali nascosti, premi il d-pad per visualizzarli"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fine"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-iw/strings.xml b/v17/leanback/res/values-iw/strings.xml
index b94c431..4d6d7f4 100644
--- a/v17/leanback/res/values-iw/strings.xml
+++ b/v17/leanback/res/values-iw/strings.xml
@@ -48,6 +48,10 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"הפעל כתוביות"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"השבת כתוביות"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"הזן את התמונה במצב תמונה"</string>
+    <!-- no translation found for lb_playback_controls_shown (6382160135512023238) -->
+    <skip />
+    <!-- no translation found for lb_playback_controls_hidden (8940984081242033574) -->
+    <skip />
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"סיום"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"המשך"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ja/strings.xml b/v17/leanback/res/values-ja/strings.xml
index 650f4fd..95a9964 100644
--- a/v17/leanback/res/values-ja/strings.xml
+++ b/v17/leanback/res/values-ja/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"字幕を有効にする"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"字幕を無効にする"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"PIP モードに移動"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"メディア コントロールは表示されています"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"メディア コントロールは非表示になっています。表示するには D-pad を押してください"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完了"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"続行"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ka/strings.xml b/v17/leanback/res/values-ka/strings.xml
index 9962645..575c504 100644
--- a/v17/leanback/res/values-ka/strings.xml
+++ b/v17/leanback/res/values-ka/strings.xml
@@ -52,6 +52,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"დახურული წარწერების ჩართვა"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"დახურული წარწერების გაუქმება"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"რეჟიმზე „სურათი სურათში“ გადასვლა"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"ნაჩვენებია მედიის მართვის საშუალებები"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"მედიის მართვის საშუალებები დამალულია, გამოსაჩენად დააჭირეთ D-pad-ს"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"დასრულება"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"გაგრძელება"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-kk/strings.xml b/v17/leanback/res/values-kk/strings.xml
index 6f7faf2..31c92a5 100644
--- a/v17/leanback/res/values-kk/strings.xml
+++ b/v17/leanback/res/values-kk/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жасырын титрлерді қосу"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жасырын титрлерді өшіру"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Сурет ішіндегі сурет режиміне кіру"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Мультимедияны басқару элементтері көрсетілген"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Мультимедияны басқару элементтері жасырын, оларды көрсету үшін d-тақтасын басыңыз"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Аяқтау"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Жалғастыру"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-km/strings.xml b/v17/leanback/res/values-km/strings.xml
index 25abb45..ba3373a 100644
--- a/v17/leanback/res/values-km/strings.xml
+++ b/v17/leanback/res/values-km/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"បើក​ការ​ដាក់​ចំណង​ដែល​បាន​បិទ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"បិទ​ការ​ដាក់​ចំណង​ដែល​បាន​បិទ"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"បញ្ចូលរូបភាពនៅក្នុងរបៀបរូបភាព"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"ការ​គ្រប់គ្រង​មេឌៀ​ត្រូវ​បាន​បង្ហាញ"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"ការ​គ្រប់គ្រង​មេឌៀ​ត្រូវ​បាន​លាក់ សូមចុច d-pad ដើម្បី​បង្ហាញ"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"បញ្ចប់"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"បន្ត"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-kn/strings.xml b/v17/leanback/res/values-kn/strings.xml
index 92fdddd..69e0277 100644
--- a/v17/leanback/res/values-kn/strings.xml
+++ b/v17/leanback/res/values-kn/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ಚಿತ್ರವನ್ನು ಚಿತ್ರ ಮೋಡ್‌ನಲ್ಲಿ ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"ಮಾಧ್ಯಮ ನಿಯಂತ್ರಣಗಳನ್ನು ತೋರಿಸಲಾಗಿದೆ"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"ಮಾಧ್ಯಮ ನಿಯಂತ್ರಣಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ, ತೋರಿಸಲು d-pad ಒತ್ತಿರಿ"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ಪೂರ್ಣಗೊಳಿಸು"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ಮುಂದುವರಿಸು"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ko/strings.xml b/v17/leanback/res/values-ko/strings.xml
index 1696bca..485aff6 100644
--- a/v17/leanback/res/values-ko/strings.xml
+++ b/v17/leanback/res/values-ko/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"자막 사용 설정"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"자막 사용 중지"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"사진 모드에서 사진 입력"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"미디어 컨트롤이 표시되었습니다."</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"미디어 컨트롤이 숨겨져 있습니다. 표시하려면 D-Pad를 누르세요."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"완료"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"계속"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ky/strings.xml b/v17/leanback/res/values-ky/strings.xml
index e2dc200..51537b1 100644
--- a/v17/leanback/res/values-ky/strings.xml
+++ b/v17/leanback/res/values-ky/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жабык субтитрлерди иштетүү"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жабык субтитрлерди өчүрүү"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Сүрөт режиминде сүрөт киргизүү"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Медиа файлды башкаруу көрсөтүлдү"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Медиа файлды башкаруу жашырылган, көрүү үчүн d-pad көзөмөлдөө каражатын басыңыз"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Бүтүрүү"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Улантуу"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-lo/strings.xml b/v17/leanback/res/values-lo/strings.xml
index 389b1d0..3053234 100644
--- a/v17/leanback/res/values-lo/strings.xml
+++ b/v17/leanback/res/values-lo/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"​ເປີດ​ນຳ​ໃຊ້​​ຄຳ​ບັນ​ຍາຍ​ແບບ​ປິດ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"​ປິດ​ນຳ​ໃຊ້​ຄຳ​ບັນ​ຍາຍ​ແບບ​ປິດ"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ປ້ອນຮູບພາບໃນໂໝດຮູບພາບ"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"ສະແດງຕົວຄວບຄຸມມີເດຍແລ້ວ"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"ເຊື່ອງຕົວຄວບຄຸມມີເດຍແລ້ວ, ກົດປຸ່ມທິດທາງເພື່ອສະແດງ"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ສໍາເລັດ"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"​ສືບ​ຕໍ່"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-lt/strings.xml b/v17/leanback/res/values-lt/strings.xml
index 43eebb8..ee3d3f6 100644
--- a/v17/leanback/res/values-lt/strings.xml
+++ b/v17/leanback/res/values-lt/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Įgalinti subtitrus"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Išjungti subtitrus"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Įjungti vaizdo vaizde režimą"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Medijos valdikliai rodomi"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Medijos valdikliai paslėpti. Paspauskite krypčių valdiklius, kad rodytumėte"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Baigti"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tęsti"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-lv/strings.xml b/v17/leanback/res/values-lv/strings.xml
index 644d990..aa04f90 100644
--- a/v17/leanback/res/values-lv/strings.xml
+++ b/v17/leanback/res/values-lv/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Iespējot slēgtos parakstus"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Atspējot slēgtos parakstus"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Aktivizēt režīmu Attēls attēlā"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Multivides vadīklas ir redzamas."</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Multivides vadīklas ir paslēptas. Nospiediet virzienu tastatūru, lai tās tiktu parādītas."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Pabeigt"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Turpināt"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-mk/strings.xml b/v17/leanback/res/values-mk/strings.xml
index 6e506fe..f7e4d1f 100644
--- a/v17/leanback/res/values-mk/strings.xml
+++ b/v17/leanback/res/values-mk/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Овозможи затворено објаснување"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Оневозможи затворено објаснување"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Влези во режимот „Слика во слика“"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Контролите за аудио-визуелните контроли се прикажуваат"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Контролите за аудио-визуелните медиуми се скриени, притиснете на подлогата за насока за да ги прикажете"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Заврши"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Продолжи"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-ml/strings.xml b/v17/leanback/res/values-ml/strings.xml
index 0306a6a..f15aa1d 100644
--- a/v17/leanback/res/values-ml/strings.xml
+++ b/v17/leanback/res/values-ml/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"\'ചിത്രത്തിനുള്ളിൽ ചിത്രം\' മോഡിലേക്ക് പ്രവേശിക്കുക"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"മീഡിയ നിയന്ത്രണങ്ങൾ ‌കാണിച്ചിരിക്കുന്നു"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"മീഡിയ നിയന്ത്രണങ്ങൾ ‌മറച്ചിരിക്കുന്നു, കാണിക്കുന്നതിന് ഡി-‌പാഡ് അമർത്തുക"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"പൂര്‍ത്തിയാക്കുക"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"തുടരുക"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-mn/strings.xml b/v17/leanback/res/values-mn/strings.xml
index f21b649..672ed15 100644
--- a/v17/leanback/res/values-mn/strings.xml
+++ b/v17/leanback/res/values-mn/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Текст тайлбарыг идэвхжүүлэх"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Текст тайлбарыг идэвхгүйжүүлэх"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Зургийн горимд зураг оруулна уу"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Медиа удирдлага харагдаж байна"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Медиа удирдлага нуугдсан байна, харуулахын тулд d-pad-г дарна уу"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Дуусгах"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Үргэлжлүүлэх"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-mr/strings.xml b/v17/leanback/res/values-mr/strings.xml
index ef6a6a6..99f7a17 100644
--- a/v17/leanback/res/values-mr/strings.xml
+++ b/v17/leanback/res/values-mr/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षके सक्षम करा"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षके अक्षम करा"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"चित्र मोडमध्ये चित्र प्रविष्ट करा"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"मीडिया नियंत्रणे दर्शवली आहेत"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"मीडिया नियंत्रणे लपलेली आहेत, दर्शवण्‍यासाठी d-pad दाबा"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"सुरू ठेवा"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ms/strings.xml b/v17/leanback/res/values-ms/strings.xml
index 1764e52..8ee0bfb 100644
--- a/v17/leanback/res/values-ms/strings.xml
+++ b/v17/leanback/res/values-ms/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Dayakan Kapsyen Tertutup"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Lumpuhkan Kapsyen Tertutup"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Masukkan Gambar Dalam Mod Gambar"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kawalan media ditunjukkan"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kawalan media disembunyikan, tekan d-pad untuk menunjukkan"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Teruskan"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-my/strings.xml b/v17/leanback/res/values-my/strings.xml
index 645f169..f0d89d4 100644
--- a/v17/leanback/res/values-my/strings.xml
+++ b/v17/leanback/res/values-my/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"စာတမ်းထိုး ဖွင့်ရန်"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"စာတမ်းထိုးအား ပိတ်ထားရန်"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ဓာတ်ပုံမုဒ်တွင် ဓာတ်ပုံထည့်ပါ"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"မီဒီယာ ခလုတ်များကို ပြထားပါသည်"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"မီဒီယာခလုတ်များကို ဝှက်ထားပါသည်။ ပြရန် d-pad ကို နှိပ်ပါ"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ပြီးပြီ"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ဆက်လုပ်ရန်"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-nb/strings.xml b/v17/leanback/res/values-nb/strings.xml
index ae3394b..69521f1 100644
--- a/v17/leanback/res/values-nb/strings.xml
+++ b/v17/leanback/res/values-nb/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér teksting"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver teksting"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Slå på modusen Bilde-i-bilde"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediekontrollene vises"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediekontrollene er skjult – trykk på styrepilene for å vise dem"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fullfør"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsett"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-ne/strings.xml b/v17/leanback/res/values-ne/strings.xml
index e8baffb..b012d93 100644
--- a/v17/leanback/res/values-ne/strings.xml
+++ b/v17/leanback/res/values-ne/strings.xml
@@ -50,6 +50,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"बन्द क्याप्सनहरु सक्षम"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"बन्द क्याप्सनहरु असक्षम"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"चित्रलाई चित्र मोडमा प्रविष्ट गर्नुहोस्"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"मिडियाका नियन्त्रणहरू देखाएइका छन्"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"मिडियाका नियन्त्रणहरू लुकेका छन्, देखाउनका लागि d-pad लाई थिच्नुहोस्"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त गर्नुहोस्"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"जारी राख्नुहोस्"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-nl/strings.xml b/v17/leanback/res/values-nl/strings.xml
index 0a5bdce..21ae66b 100644
--- a/v17/leanback/res/values-nl/strings.xml
+++ b/v17/leanback/res/values-nl/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ondertiteling inschakelen"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Ondertiteling uitschakelen"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Beeld-in-beeld-modus openen"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Opties voor mediabediening worden weergegeven"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Opties voor mediabediening verborgen. Druk op de D-pad om ze weer te geven."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooien"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Doorgaan"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"-"</string>
diff --git a/v17/leanback/res/values-pa/strings.xml b/v17/leanback/res/values-pa/strings.xml
index b8c7591..125058d 100644
--- a/v17/leanback/res/values-pa/strings.xml
+++ b/v17/leanback/res/values-pa/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਸਮਰੱਥ ਬਣਾਓ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ਤਸਵੀਰ ਮੋਡ ਵਿੱਚ ਤਸਵੀਰ ਦਾਖਲ ਕਰੋ"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"ਮੀਡੀਆ ਕੰਟਰੋਲ ਵਿਖਾਏ ਗਏ"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"ਮੀਡੀਆ ਕੰਟਰੋਲ ਲੁਕੇ ਹੋਏ ਹਨ, ਵਿਖਾਉਣ ਲਈ ਡੀ-ਪੈਡ ਦਬਾਓ"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ਖ਼ਤਮ"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ਜਾਰੀ ਰੱਖੋ"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-pl/strings.xml b/v17/leanback/res/values-pl/strings.xml
index 15de203..e0e87b5 100644
--- a/v17/leanback/res/values-pl/strings.xml
+++ b/v17/leanback/res/values-pl/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Włącz napisy"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Wyłącz napisy"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Włącz tryb obrazu w obrazie"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Elementy sterujące multimediami są wyświetlone"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Elementy sterujące multimediami są ukryte. Naciśnij pad kierunkowy, by je wyświetlić"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Zakończ"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Dalej"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-pt-rBR/strings.xml b/v17/leanback/res/values-pt-rBR/strings.xml
index 4621809..ca688bf 100644
--- a/v17/leanback/res/values-pt-rBR/strings.xml
+++ b/v17/leanback/res/values-pt-rBR/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entrar no modo Picture in Picture"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Os controles de mídia estão sendo exibidos"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Os controles de mídia estão ocultos. Pressione o botão direcional para exibi-los"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-pt-rPT/strings.xml b/v17/leanback/res/values-pt-rPT/strings.xml
index 0df9c00..2e7dff7 100644
--- a/v17/leanback/res/values-pt-rPT/strings.xml
+++ b/v17/leanback/res/values-pt-rPT/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar legendas"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar legendas"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entrar no modo Imagem na imagem"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Controlos de multimédia apresentados"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Controlos de multimédia ocultados, prima o teclado direcional para mostrar"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-pt/strings.xml b/v17/leanback/res/values-pt/strings.xml
index 4621809..ca688bf 100644
--- a/v17/leanback/res/values-pt/strings.xml
+++ b/v17/leanback/res/values-pt/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entrar no modo Picture in Picture"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Os controles de mídia estão sendo exibidos"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Os controles de mídia estão ocultos. Pressione o botão direcional para exibi-los"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ro/strings.xml b/v17/leanback/res/values-ro/strings.xml
index 5fa64ef..03c6520 100644
--- a/v17/leanback/res/values-ro/strings.xml
+++ b/v17/leanback/res/values-ro/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activează subtitrările"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Dezactivează subtitrările"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activați modul Picture-in-Picture"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Comenzile media sunt afișate"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Comenzile media sunt ascunse. Apăsați pe butonul direcțional pentru a le afișa."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizați"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuați"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ru/strings.xml b/v17/leanback/res/values-ru/strings.xml
index c7a146f..8f96195 100644
--- a/v17/leanback/res/values-ru/strings.xml
+++ b/v17/leanback/res/values-ru/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Включить субтитры."</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Отключить субтитры."</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Включить режим \"Картинка в картинке\"."</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Элементы управления показаны"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Элементы управления скрыты. Нажмите D-pad, чтобы показать их."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Готово"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Далее"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-si/strings.xml b/v17/leanback/res/values-si/strings.xml
index 44e4f31..fb812da 100644
--- a/v17/leanback/res/values-si/strings.xml
+++ b/v17/leanback/res/values-si/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"වැසුණු ශිර්ෂ කිරීම සබල කරන ලදි"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"වැසුණු ශිර්ෂ කිරීම අබල කරන ලදි"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"පින්තූරය-තුළ-පින්තූරය ප්‍රකාරයට ඇතුළු වන්න"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"මාධ්‍ය පාලක පෙන්වා ඇත"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"මාධ්‍ය පාලක සඟවා ඇත, පෙන්වීමට d-pad ඔබන්න"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"අවසානය"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"දිගටම කර ගෙන යන්න"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-sk/strings.xml b/v17/leanback/res/values-sk/strings.xml
index bfd972a..c2f2a0a 100644
--- a/v17/leanback/res/values-sk/strings.xml
+++ b/v17/leanback/res/values-sk/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnúť skryté titulky"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnúť skryté titulky"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Vložiť obrázok v režime obrázka"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Ovládacie prvky médií sa zobrazujú"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Ovládacie prvky médií sú skryté, zobrazíte ich stlačením klávesa d-pad"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončiť"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovať"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-sl/strings.xml b/v17/leanback/res/values-sl/strings.xml
index 1919b29..6e6c5ae 100644
--- a/v17/leanback/res/values-sl/strings.xml
+++ b/v17/leanback/res/values-sl/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogoči podnapise"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogoči podnapise"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Vklop načina za sliko v sliki"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrolniki predstavnosti so prikazani"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrolniki predstavnosti so skriti, za prikaz pritisnite smerni gumb"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončaj"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Naprej"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-sq/strings.xml b/v17/leanback/res/values-sq/strings.xml
index 36cfdf3..b0904ff 100644
--- a/v17/leanback/res/values-sq/strings.xml
+++ b/v17/leanback/res/values-sq/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivizo titrat"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Çaktivizo titrat me sekuencë kohore"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Fut një fotografi në modalitetin e fotografisë"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrollet e medias të shfaqura"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrollet e medias të fshehura, shtyp bllokun e drejtimit për t\'i shfaqur"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Përfundo"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Vazhdo"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-sr/strings.xml b/v17/leanback/res/values-sr/strings.xml
index 1a9a0c4..1b69e08 100644
--- a/v17/leanback/res/values-sr/strings.xml
+++ b/v17/leanback/res/values-sr/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Омогући титлове"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Онемогући титлове"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Уђи у режим Слика у слици"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Контроле за медије су приказане"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Контроле за медије су скривене, притисните контроле за кретање да бисте их приказали"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Доврши"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Настави"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-sv/strings.xml b/v17/leanback/res/values-sv/strings.xml
index 5bdd293..5dce6ff 100644
--- a/v17/leanback/res/values-sv/strings.xml
+++ b/v17/leanback/res/values-sv/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivera textning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inaktivera textning"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Ange läget Bild-i-bild"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediakontrollerna visas"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediakontrollerna är dolda och visas om du trycker på styrkorset"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Slutför"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsätt"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-sw/strings.xml b/v17/leanback/res/values-sw/strings.xml
index 6683e46..a7bfa0f 100644
--- a/v17/leanback/res/values-sw/strings.xml
+++ b/v17/leanback/res/values-sw/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Washa manukuu"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Zima manukuu"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Weka Picha Katika Hali ya Picha"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Inaonyesha udhibiti wa maudhui"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Imeficha udhibiti wa maudhui, bonyeza d-pad ili uuonyeshe"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Kamilisha"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Endelea"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-ta/strings.xml b/v17/leanback/res/values-ta/strings.xml
index 5afde83..7b0ffaf 100644
--- a/v17/leanback/res/values-ta/strings.xml
+++ b/v17/leanback/res/values-ta/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"விரிவான வசனங்களை இயக்கு"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"விரிவான வசனங்களை முடக்கு"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"பிக்ச்சர் இன் பிக்ச்சர் பயன்முறைக்குச் செல்"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"மீடியா கட்டுப்பாடுகள் காட்டப்படுகின்றன"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"மீடியா கட்டுப்பாடுகள் மறைக்கப்பட்டுள்ளன. கட்டுப்பாடுகளைக் காட்ட, டிபேடை அழுத்தவும்"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"முடி"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"தொடர்க"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-te/strings.xml b/v17/leanback/res/values-te/strings.xml
index f74c525..e1b3ba2 100644
--- a/v17/leanback/res/values-te/strings.xml
+++ b/v17/leanback/res/values-te/strings.xml
@@ -48,6 +48,10 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"సంవృత శీర్షికలను ప్రారంభించు"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"సంవృత శీర్షికలను నిలిపివేయి"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"చిత్రంలో చిత్రం మోడ్‌లోకి ప్రవేశించండి"</string>
+    <!-- no translation found for lb_playback_controls_shown (6382160135512023238) -->
+    <skip />
+    <!-- no translation found for lb_playback_controls_hidden (8940984081242033574) -->
+    <skip />
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ముగించు"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"కొనసాగించు"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-th/strings.xml b/v17/leanback/res/values-th/strings.xml
index 8440dd9..4e8fea2 100644
--- a/v17/leanback/res/values-th/strings.xml
+++ b/v17/leanback/res/values-th/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"เปิดใช้คำบรรยาย"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ปิดใช้คำบรรยาย"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"เข้าสู่โหมดการแสดงผลหลายแหล่งพร้อมกัน"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"แสดงการควบคุมสื่ออยู่"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"ซ่อนการควบคุมสื่ออยู่ กด d-pad เพื่อแสดง"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"เสร็จสิ้น"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ต่อไป"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-tl/strings.xml b/v17/leanback/res/values-tl/strings.xml
index c2f52a4..b2795c2 100644
--- a/v17/leanback/res/values-tl/strings.xml
+++ b/v17/leanback/res/values-tl/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"I-enable ang Paglalagay ng Subtitle"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"I-disable ang Paglalagay ng Subtitle"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Pumasok sa Picture In Picture Mode"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Ipinapakita ang mga kontrol ng media"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Nakatago ang mga kontrol ng media, pindutin ang d-pad upang ipakita"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tapusin"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Magpatuloy"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-tr/strings.xml b/v17/leanback/res/values-tr/strings.xml
index 0c6431e..611998d 100644
--- a/v17/leanback/res/values-tr/strings.xml
+++ b/v17/leanback/res/values-tr/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Altyazıları Etkinleştir"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Altyazıları Devre Dışı Bırak"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Resim İçinde Resim Moduna Geç"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Medya denetimleri gösteriliyor"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Medya denetimleri gizli durumda. Görüntülemek için d-pad\'e basın."</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Son"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Devam"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-uk/strings.xml b/v17/leanback/res/values-uk/strings.xml
index bb6bde7..a6ba427 100644
--- a/v17/leanback/res/values-uk/strings.xml
+++ b/v17/leanback/res/values-uk/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Увімкнути субтитри"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Вимкнути субтитри"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Перейти в режим \"Картинка в картинці\""</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Показано елементи керування медіа"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Елементи керування медіа сховано. Натисніть цифрову панель, щоб показати їх"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Закінчити"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Продовжити"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"."</string>
diff --git a/v17/leanback/res/values-ur/strings.xml b/v17/leanback/res/values-ur/strings.xml
index f387aa3..a87ac02 100644
--- a/v17/leanback/res/values-ur/strings.xml
+++ b/v17/leanback/res/values-ur/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"سب ٹائٹلز کو فعال کریں"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"سب ٹائٹلز کو غیر فعال کریں"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"\'تصویر میں تصویر موڈ\' میں داخل ہوں"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"میڈیا کنٹرولز عیاں ہیں"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"‏میڈیا کنٹرولز مخفی ہیں، شو کرنے کیلئے d-pad دبائیں"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"مکمل کریں"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"جاری رکھیں"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-uz/strings.xml b/v17/leanback/res/values-uz/strings.xml
index 48dc067..c491358 100644
--- a/v17/leanback/res/values-uz/strings.xml
+++ b/v17/leanback/res/values-uz/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Taglavhalarni yoqish"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Taglavhalarni o‘chirib qo‘yish"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Tasvir ichida tasvir rejimiga kirish"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Boshqaruv elementlari ko‘rsatilgan"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Boshqaruv elementlari yashirilgan, ko‘rsatish uchun D-pad tugmasini bosing"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tugatish"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davom etish"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-vi/strings.xml b/v17/leanback/res/values-vi/strings.xml
index 8d8c282..296f0e8 100644
--- a/v17/leanback/res/values-vi/strings.xml
+++ b/v17/leanback/res/values-vi/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Bật phụ đề"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Tắt phụ đề"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Vào ảnh ở chế độ ảnh"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Điều khiển phương tiện được hiển thị"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Điều khiển phương tiện bị ẩn, nhấn d-pad để hiển thị"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Hoàn tất"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tiếp tục"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-zh-rCN/strings.xml b/v17/leanback/res/values-zh-rCN/strings.xml
index 611bff1..8d7ebc0 100644
--- a/v17/leanback/res/values-zh-rCN/strings.xml
+++ b/v17/leanback/res/values-zh-rCN/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"开启字幕"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"关闭字幕"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"进入画中画模式"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"媒体控件已显示"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"媒体控件已隐藏,按 D-pad 即可显示"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"继续"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-zh-rHK/strings.xml b/v17/leanback/res/values-zh-rHK/strings.xml
index c18032e..6e6688e 100644
--- a/v17/leanback/res/values-zh-rHK/strings.xml
+++ b/v17/leanback/res/values-zh-rHK/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"進入「畫中畫模式」"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"畫面已顯示媒體控制項"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"畫面已隱藏媒體控制項,按十字鍵即可顯示"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"繼續"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-zh-rTW/strings.xml b/v17/leanback/res/values-zh-rTW/strings.xml
index 1e14d0a..cdbdaa2 100644
--- a/v17/leanback/res/values-zh-rTW/strings.xml
+++ b/v17/leanback/res/values-zh-rTW/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"進入子母畫面模式"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"媒體控制項已顯示"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"媒體控制項已隱藏,按下 D-Pad 即可顯示"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"繼續"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-zu/strings.xml b/v17/leanback/res/values-zu/strings.xml
index 7fb290f..d62005b 100644
--- a/v17/leanback/res/values-zu/strings.xml
+++ b/v17/leanback/res/values-zu/strings.xml
@@ -48,6 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Nika amandla imibhalo engezansi"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Khubaza imihbalo engezansi"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Ngena isithombe kumodi yesithombe"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Izilawuli zemidiya zibonisiwe"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Izilawuli zemidiya zifihliwe, cindezela ku-d-pad ukuze uzibonise"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Qeda"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Qhubeka"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values/dimens.xml b/v17/leanback/res/values/dimens.xml
index 8d174be..4bf237d 100644
--- a/v17/leanback/res/values/dimens.xml
+++ b/v17/leanback/res/values/dimens.xml
@@ -124,9 +124,11 @@
     <dimen name="lb_action_text_size">16sp</dimen>
     <dimen name="lb_action_button_corner_radius">2dp</dimen>
 
-    <dimen name="lb_playback_controls_align_bottom">58dp</dimen>
-    <dimen name="lb_playback_controls_padding_top">216dp</dimen>
+    <!-- distance of bottom of playback row to bottom edge, used for overscan protection and
+    peeking related rows-->
     <dimen name="lb_playback_controls_padding_bottom">28dp</dimen>
+    <!-- distance of other rows' center to bottom edge, half of screen by default -->
+    <dimen name="lb_playback_other_rows_center_to_bottom">270dp</dimen>
     <dimen name="lb_playback_major_fade_translate_y">200dp</dimen>
     <dimen name="lb_playback_minor_fade_translate_y">16dp</dimen>
     <dimen name="lb_playback_controls_card_height">176dp</dimen>
diff --git a/v17/leanback/res/values/strings.xml b/v17/leanback/res/values/strings.xml
index 1ca09dd..cbf4904 100644
--- a/v17/leanback/res/values/strings.xml
+++ b/v17/leanback/res/values/strings.xml
@@ -81,6 +81,10 @@
     <!-- Talkback label for the control button to enter picture in picture mode -->
     <string name="lb_playback_controls_picture_in_picture">Enter Picture In Picture Mode</string>
 
+
+    <string name="lb_playback_controls_shown">Media controls shown</string>
+    <string name="lb_playback_controls_hidden">Media controls hidden, press d-pad to show</string>
+
     <!-- Title of standard Finish action for GuidedStepFragment -->
     <string name="lb_guidedaction_finish_title">Finish</string>
     <!-- Title of standard Continue action for GuidedStepFragment -->
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
index 1c9e5ca..ed20153 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -578,7 +578,7 @@
      * against {@link PageRow}.
      */
     public final static class MainFragmentAdapterRegistry {
-        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap();
+        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
         private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
 
         public MainFragmentAdapterRegistry() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
index c7d8de4..43e10b2 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -581,7 +581,7 @@
      * against {@link PageRow}.
      */
     public final static class MainFragmentAdapterRegistry {
-        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap();
+        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
         private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
 
         public MainFragmentAdapterRegistry() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
index 37a6bfc..5e2980d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
@@ -88,8 +88,6 @@
         mParallaxEffect = mDetailsParallax
                 .addEffect(frameTop.atFraction(maxFrameTop), frameTop.atFraction(minFrameTop))
                 .target(new ParallaxTarget() {
-
-                    float mFraction;
                     @Override
                     public void update(float fraction) {
                         if (fraction == maxFrameTop) {
@@ -97,12 +95,6 @@
                         } else {
                             updateState(PLAY_VIDEO);
                         }
-                        mFraction = fraction;
-                    }
-
-                    @Override
-                    public float getFraction() {
-                        return mFraction;
                     }
                 });
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
index 9438ce5..00a1ace 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
@@ -126,7 +126,7 @@
         final WeakReference<DetailsFragment> mRef;
 
         WaitEnterTransitionTimeout(DetailsFragment f) {
-            mRef = new WeakReference(f);
+            mRef = new WeakReference<>(f);
             f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
         }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
index 79ab727..eb78840 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -129,7 +129,7 @@
         final WeakReference<DetailsSupportFragment> mRef;
 
         WaitEnterTransitionTimeout(DetailsSupportFragment f) {
-            mRef = new WeakReference(f);
+            mRef = new WeakReference<>(f);
             f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
         }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
index 8d6367a..ed4d822 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
@@ -33,6 +33,7 @@
 import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
 import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter;
 import android.support.v17.leanback.widget.PlaybackRowPresenter;
@@ -40,6 +41,7 @@
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.support.v17.leanback.widget.VerticalGridView;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
@@ -62,8 +64,12 @@
  * of {@link RowPresenter}.
  * </p>
  * <p>
- * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
- * at position 0 in the adapter.
+ * A playback row is a row rendered by {@link PlaybackRowPresenter}.
+ * App can call {@link #setPlaybackRow(Row)} to set playback row for the first element of adapter.
+ * App can call {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} to set presenter for it.
+ * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} are
+ * optional, app can pass playback row and PlaybackRowPresenter in the adapter using
+ * {@link #setAdapter(ObjectAdapter)}.
  * </p>
  */
 public class PlaybackFragment extends Fragment {
@@ -179,8 +185,8 @@
     private static final int IN = 1;
     private static final int OUT = 2;
 
-    private int mPaddingTop;
     private int mPaddingBottom;
+    private int mOtherRowsCenterToBottom;
     private View mRootView;
     private int mBackgroundType = BG_DARK;
     private int mBgDarkColor;
@@ -594,6 +600,8 @@
                 mOtherRowFadeInAnimator.reverse();
             }
         }
+        getView().announceForAccessibility(getString(fadeIn ? R.string.lb_playback_controls_shown
+                : R.string.lb_playback_controls_hidden));
 
         // If fading in while control row is focused, set initial translationY so
         // views slide in from below.
@@ -633,31 +641,30 @@
         if (listview == null) {
             return;
         }
-        // Padding affects alignment when last row is focused
-        // (last is first when there's only one row).
-        setPadding(listview, mPaddingTop, mPaddingBottom);
 
-        // Item alignment affects focused row that isn't the last.
-        listview.setItemAlignmentOffset(0);
+        // we set the base line of alignment to -paddingBottom
+        listview.setWindowAlignmentOffset(-mPaddingBottom);
+        listview.setWindowAlignmentOffsetPercent(
+                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+
+        // align other rows that arent the last to center of screen, since our baseline is
+        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
+        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
         listview.setItemAlignmentOffsetPercent(50);
 
-        // Push rows to the bottom.
-        listview.setWindowAlignmentOffset(0);
-        listview.setWindowAlignmentOffsetPercent(50);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
-    }
-
-    private static void setPadding(View view, int paddingTop, int paddingBottom) {
-        view.setPadding(view.getPaddingLeft(), paddingTop,
-                view.getPaddingRight(), paddingBottom);
+        // Push last row to the bottom padding
+        // Padding affects alignment when last row is focused
+        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
+                listview.getPaddingRight(), mPaddingBottom);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mPaddingTop =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_top);
+        mOtherRowsCenterToBottom = getResources()
+                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
         mPaddingBottom =
                 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
         mBgDarkColor =
@@ -844,7 +851,9 @@
     }
 
     /**
-     * Sets the playback row for the playback controls.
+     * Sets the playback row for the playback controls. The row will be set as first element
+     * of adapter if the adapter is {@link ArrayObjectAdapter} or {@link SparseArrayObjectAdapter}.
+     * @param row The row that represents the playback.
      */
     public void setPlaybackRow(Row row) {
         this.mRow = row;
@@ -853,11 +862,38 @@
     }
 
     /**
-     * Sets the presenter for rendering the playback controls.
+     * Sets the presenter for rendering the playback row set by {@link #setPlaybackRow(Row)}. If
+     * adapter does not set a {@link PresenterSelector}, {@link #setAdapter(ObjectAdapter)} will
+     * create a {@link ClassPresenterSelector} by default and map from the row object class to this
+     * {@link PlaybackRowPresenter}.
+     *
+     * @param  presenter Presenter used to render {@link #setPlaybackRow(Row)}.
      */
     public void setPlaybackRowPresenter(PlaybackRowPresenter presenter) {
         this.mPresenter = presenter;
         setupPresenter();
+        setPlaybackRowPresenterAlignment();
+    }
+
+    void setPlaybackRowPresenterAlignment() {
+        if (mAdapter != null && mAdapter.getPresenterSelector() != null) {
+            Presenter[] presenters = mAdapter.getPresenterSelector().getPresenters();
+            if (presenters != null) {
+                for (int i = 0; i < presenters.length; i++) {
+                    if (presenters[i] instanceof PlaybackRowPresenter
+                            && presenters[i].getFacet(ItemAlignmentFacet.class) == null) {
+                        ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
+                        ItemAlignmentFacet.ItemAlignmentDef def =
+                                new ItemAlignmentFacet.ItemAlignmentDef();
+                        def.setItemAlignmentOffset(0);
+                        def.setItemAlignmentOffsetPercent(100);
+                        itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
+                                {def});
+                        presenters[i].setFacet(ItemAlignmentFacet.class, itemAlignment);
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -871,12 +907,19 @@
     }
 
     /**
-     * Sets the list of rows for the fragment.
+     * Sets the list of rows for the fragment. A default {@link ClassPresenterSelector} will be
+     * created if {@link ObjectAdapter#getPresenterSelector()} is null. if user provides
+     * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)},
+     * the row and presenter will be set onto the adapter.
+     *
+     * @param adapter The adapter that contains related rows and optional playback row.
      */
     public void setAdapter(ObjectAdapter adapter) {
         mAdapter = adapter;
         setupRow();
         setupPresenter();
+        setPlaybackRowPresenterAlignment();
+
         if (mRowsFragment != null) {
             mRowsFragment.setAdapter(adapter);
         }
@@ -890,6 +933,9 @@
             } else {
                 adapter.replace(0, mRow);
             }
+        } else if (mAdapter instanceof SparseArrayObjectAdapter && mRow != null) {
+            SparseArrayObjectAdapter adapter = ((SparseArrayObjectAdapter) mAdapter);
+            adapter.set(0, mRow);
         }
     }
 
@@ -898,10 +944,9 @@
             PresenterSelector selector = mAdapter.getPresenterSelector();
             if (selector == null) {
                 selector = new ClassPresenterSelector();
+                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
                 mAdapter.setPresenterSelector(selector);
-            }
-
-            if (selector instanceof ClassPresenterSelector) {
+            } else if (selector instanceof ClassPresenterSelector) {
                 ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
index c601b2e..c934f6b 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
@@ -28,10 +28,12 @@
 import android.support.v17.leanback.animation.LogAccelerateInterpolator;
 import android.support.v17.leanback.animation.LogDecelerateInterpolator;
 import android.support.v17.leanback.media.PlaybackGlueHost;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter.DataObserver;
 import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.RowPresenter;
@@ -105,7 +107,7 @@
     private static final int IN = 1;
     static final int OUT = 2;
 
-    private int mPaddingTop;
+    private int mOtherRowsCenterToBottom;
     private int mPaddingBottom;
     private View mRootView;
     private int mBackgroundType = BG_DARK;
@@ -610,6 +612,8 @@
                 mDescriptionFadeInAnimator.reverse();
             }
         }
+        getView().announceForAccessibility(getString(fadeIn ? R.string.lb_playback_controls_shown
+                : R.string.lb_playback_controls_hidden));
 
         // If fading in while control row is focused, set initial translationY so
         // views slide in from below.
@@ -638,35 +642,52 @@
     }
 
     @Override
+    protected void setupPresenter(Presenter rowPresenter) {
+        if (rowPresenter instanceof PlaybackRowPresenter) {
+            if (rowPresenter.getFacet(ItemAlignmentFacet.class) == null) {
+                ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
+                ItemAlignmentFacet.ItemAlignmentDef def =
+                        new ItemAlignmentFacet.ItemAlignmentDef();
+                def.setItemAlignmentOffset(0);
+                def.setItemAlignmentOffsetPercent(100);
+                itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
+                        {def});
+                rowPresenter.setFacet(ItemAlignmentFacet.class, itemAlignment);
+            }
+        } else {
+            super.setupPresenter(rowPresenter);
+        }
+    }
+
+    @Override
     void setVerticalGridViewLayout(VerticalGridView listview) {
         if (listview == null) {
             return;
         }
-        // Padding affects alignment when last row is focused
-        // (last is first when there's only one row).
-        setPadding(listview, mPaddingTop, mPaddingBottom);
 
-        // Item alignment affects focused row that isn't the last.
-        listview.setItemAlignmentOffset(0);
+        // we set the base line of alignment to -paddingBottom
+        listview.setWindowAlignmentOffset(-mPaddingBottom);
+        listview.setWindowAlignmentOffsetPercent(
+                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+
+        // align other rows that arent the last to center of screen, since our baseline is
+        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
+        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
         listview.setItemAlignmentOffsetPercent(50);
 
-        // Push rows to the bottom.
-        listview.setWindowAlignmentOffset(0);
-        listview.setWindowAlignmentOffsetPercent(50);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
-    }
-
-    private static void setPadding(View view, int paddingTop, int paddingBottom) {
-        view.setPadding(view.getPaddingLeft(), paddingTop,
-                view.getPaddingRight(), paddingBottom);
+        // Push last row to the bottom padding
+        // Padding affects alignment when last row is focused
+        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
+                listview.getPaddingRight(), mPaddingBottom);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mPaddingTop =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_top);
+        mOtherRowsCenterToBottom = getResources()
+                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
         mPaddingBottom =
                 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
         mBgDarkColor =
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
index b4df936..ecabdaa 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
@@ -31,10 +31,12 @@
 import android.support.v17.leanback.animation.LogAccelerateInterpolator;
 import android.support.v17.leanback.animation.LogDecelerateInterpolator;
 import android.support.v17.leanback.media.PlaybackGlueHost;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter.DataObserver;
 import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.RowPresenter;
@@ -108,7 +110,7 @@
     private static final int IN = 1;
     static final int OUT = 2;
 
-    private int mPaddingTop;
+    private int mOtherRowsCenterToBottom;
     private int mPaddingBottom;
     private View mRootView;
     private int mBackgroundType = BG_DARK;
@@ -613,6 +615,8 @@
                 mDescriptionFadeInAnimator.reverse();
             }
         }
+        getView().announceForAccessibility(getString(fadeIn ? R.string.lb_playback_controls_shown
+                : R.string.lb_playback_controls_hidden));
 
         // If fading in while control row is focused, set initial translationY so
         // views slide in from below.
@@ -641,35 +645,52 @@
     }
 
     @Override
+    protected void setupPresenter(Presenter rowPresenter) {
+        if (rowPresenter instanceof PlaybackRowPresenter) {
+            if (rowPresenter.getFacet(ItemAlignmentFacet.class) == null) {
+                ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
+                ItemAlignmentFacet.ItemAlignmentDef def =
+                        new ItemAlignmentFacet.ItemAlignmentDef();
+                def.setItemAlignmentOffset(0);
+                def.setItemAlignmentOffsetPercent(100);
+                itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
+                        {def});
+                rowPresenter.setFacet(ItemAlignmentFacet.class, itemAlignment);
+            }
+        } else {
+            super.setupPresenter(rowPresenter);
+        }
+    }
+
+    @Override
     void setVerticalGridViewLayout(VerticalGridView listview) {
         if (listview == null) {
             return;
         }
-        // Padding affects alignment when last row is focused
-        // (last is first when there's only one row).
-        setPadding(listview, mPaddingTop, mPaddingBottom);
 
-        // Item alignment affects focused row that isn't the last.
-        listview.setItemAlignmentOffset(0);
+        // we set the base line of alignment to -paddingBottom
+        listview.setWindowAlignmentOffset(-mPaddingBottom);
+        listview.setWindowAlignmentOffsetPercent(
+                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+
+        // align other rows that arent the last to center of screen, since our baseline is
+        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
+        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
         listview.setItemAlignmentOffsetPercent(50);
 
-        // Push rows to the bottom.
-        listview.setWindowAlignmentOffset(0);
-        listview.setWindowAlignmentOffsetPercent(50);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
-    }
-
-    private static void setPadding(View view, int paddingTop, int paddingBottom) {
-        view.setPadding(view.getPaddingLeft(), paddingTop,
-                view.getPaddingRight(), paddingBottom);
+        // Push last row to the bottom padding
+        // Padding affects alignment when last row is focused
+        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
+                listview.getPaddingRight(), mPaddingBottom);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mPaddingTop =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_top);
+        mOtherRowsCenterToBottom = getResources()
+                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
         mPaddingBottom =
                 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
         mBgDarkColor =
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
index 3133264..2e39904 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
@@ -36,6 +36,7 @@
 import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
 import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter;
 import android.support.v17.leanback.widget.PlaybackRowPresenter;
@@ -43,6 +44,7 @@
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.support.v17.leanback.widget.VerticalGridView;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
@@ -65,8 +67,12 @@
  * of {@link RowPresenter}.
  * </p>
  * <p>
- * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
- * at position 0 in the adapter.
+ * A playback row is a row rendered by {@link PlaybackRowPresenter}.
+ * App can call {@link #setPlaybackRow(Row)} to set playback row for the first element of adapter.
+ * App can call {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} to set presenter for it.
+ * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} are
+ * optional, app can pass playback row and PlaybackRowPresenter in the adapter using
+ * {@link #setAdapter(ObjectAdapter)}.
  * </p>
  */
 public class PlaybackSupportFragment extends Fragment {
@@ -182,8 +188,8 @@
     private static final int IN = 1;
     private static final int OUT = 2;
 
-    private int mPaddingTop;
     private int mPaddingBottom;
+    private int mOtherRowsCenterToBottom;
     private View mRootView;
     private int mBackgroundType = BG_DARK;
     private int mBgDarkColor;
@@ -597,6 +603,8 @@
                 mOtherRowFadeInAnimator.reverse();
             }
         }
+        getView().announceForAccessibility(getString(fadeIn ? R.string.lb_playback_controls_shown
+                : R.string.lb_playback_controls_hidden));
 
         // If fading in while control row is focused, set initial translationY so
         // views slide in from below.
@@ -636,31 +644,30 @@
         if (listview == null) {
             return;
         }
-        // Padding affects alignment when last row is focused
-        // (last is first when there's only one row).
-        setPadding(listview, mPaddingTop, mPaddingBottom);
 
-        // Item alignment affects focused row that isn't the last.
-        listview.setItemAlignmentOffset(0);
+        // we set the base line of alignment to -paddingBottom
+        listview.setWindowAlignmentOffset(-mPaddingBottom);
+        listview.setWindowAlignmentOffsetPercent(
+                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+
+        // align other rows that arent the last to center of screen, since our baseline is
+        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
+        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
         listview.setItemAlignmentOffsetPercent(50);
 
-        // Push rows to the bottom.
-        listview.setWindowAlignmentOffset(0);
-        listview.setWindowAlignmentOffsetPercent(50);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
-    }
-
-    private static void setPadding(View view, int paddingTop, int paddingBottom) {
-        view.setPadding(view.getPaddingLeft(), paddingTop,
-                view.getPaddingRight(), paddingBottom);
+        // Push last row to the bottom padding
+        // Padding affects alignment when last row is focused
+        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
+                listview.getPaddingRight(), mPaddingBottom);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mPaddingTop =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_top);
+        mOtherRowsCenterToBottom = getResources()
+                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
         mPaddingBottom =
                 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
         mBgDarkColor =
@@ -847,7 +854,9 @@
     }
 
     /**
-     * Sets the playback row for the playback controls.
+     * Sets the playback row for the playback controls. The row will be set as first element
+     * of adapter if the adapter is {@link ArrayObjectAdapter} or {@link SparseArrayObjectAdapter}.
+     * @param row The row that represents the playback.
      */
     public void setPlaybackRow(Row row) {
         this.mRow = row;
@@ -856,11 +865,38 @@
     }
 
     /**
-     * Sets the presenter for rendering the playback controls.
+     * Sets the presenter for rendering the playback row set by {@link #setPlaybackRow(Row)}. If
+     * adapter does not set a {@link PresenterSelector}, {@link #setAdapter(ObjectAdapter)} will
+     * create a {@link ClassPresenterSelector} by default and map from the row object class to this
+     * {@link PlaybackRowPresenter}.
+     *
+     * @param  presenter Presenter used to render {@link #setPlaybackRow(Row)}.
      */
     public void setPlaybackRowPresenter(PlaybackRowPresenter presenter) {
         this.mPresenter = presenter;
         setupPresenter();
+        setPlaybackRowPresenterAlignment();
+    }
+
+    void setPlaybackRowPresenterAlignment() {
+        if (mAdapter != null && mAdapter.getPresenterSelector() != null) {
+            Presenter[] presenters = mAdapter.getPresenterSelector().getPresenters();
+            if (presenters != null) {
+                for (int i = 0; i < presenters.length; i++) {
+                    if (presenters[i] instanceof PlaybackRowPresenter
+                            && presenters[i].getFacet(ItemAlignmentFacet.class) == null) {
+                        ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
+                        ItemAlignmentFacet.ItemAlignmentDef def =
+                                new ItemAlignmentFacet.ItemAlignmentDef();
+                        def.setItemAlignmentOffset(0);
+                        def.setItemAlignmentOffsetPercent(100);
+                        itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
+                                {def});
+                        presenters[i].setFacet(ItemAlignmentFacet.class, itemAlignment);
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -874,12 +910,19 @@
     }
 
     /**
-     * Sets the list of rows for the fragment.
+     * Sets the list of rows for the fragment. A default {@link ClassPresenterSelector} will be
+     * created if {@link ObjectAdapter#getPresenterSelector()} is null. if user provides
+     * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)},
+     * the row and presenter will be set onto the adapter.
+     *
+     * @param adapter The adapter that contains related rows and optional playback row.
      */
     public void setAdapter(ObjectAdapter adapter) {
         mAdapter = adapter;
         setupRow();
         setupPresenter();
+        setPlaybackRowPresenterAlignment();
+
         if (mRowsSupportFragment != null) {
             mRowsSupportFragment.setAdapter(adapter);
         }
@@ -893,6 +936,9 @@
             } else {
                 adapter.replace(0, mRow);
             }
+        } else if (mAdapter instanceof SparseArrayObjectAdapter && mRow != null) {
+            SparseArrayObjectAdapter adapter = ((SparseArrayObjectAdapter) mAdapter);
+            adapter.set(0, mRow);
         }
     }
 
@@ -901,10 +947,9 @@
             PresenterSelector selector = mAdapter.getPresenterSelector();
             if (selector == null) {
                 selector = new ClassPresenterSelector();
+                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
                 mAdapter.setPresenterSelector(selector);
-            }
-
-            if (selector instanceof ClassPresenterSelector) {
+            } else if (selector instanceof ClassPresenterSelector) {
                 ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java b/v17/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java
index 75ab391..700f7f0 100644
--- a/v17/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java
+++ b/v17/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java
@@ -23,88 +23,87 @@
  * rectangular bound - left/top/right/bottom.
  */
 public class BoundsRule {
-    static final int INHERIT_PARENT = 0;
-    static final int ABSOLUTE_VALUE = 1;
-    static final int INHERIT_WITH_OFFSET = 2;
 
     /**
-     * This class represents individual rules for updating the bounds. Currently we support
-     * 3 different rule types -
-     *
-     * <ul>
-     *     <li>inheritFromParent: it applies a percentage to the parent property to compute
-     *     the final value </li>
-     *     <li>absoluteValue: it always used the supplied absolute value</li>
-     *     <li>inheritFromParentWithOffset: this uses a combination of INHERIT_PARENT
-     *     and ABSOLUTE_VALUE. First it applies the percentage on the parent and then adds the
-     *     offset to compute the final value</li>
-     * </ul>
+     * This class represents individual rules for updating the bounds.
      */
     public final static class ValueRule {
-        private final int type;
-        private float fraction;
-        private int absoluteValue;
+        float mFraction;
+        int mAbsoluteValue;
 
-        ValueRule(int type, int absoluteValue, float fraction) {
-            this.type = type;
-            this.absoluteValue = absoluteValue;
-            this.fraction = fraction;
+        /**
+         * Creates ValueRule using a fraction of parent size.
+         *
+         * @param fraction Percentage of parent.
+         * @return Newly created ValueRule.
+         */
+        public static ValueRule inheritFromParent(float fraction) {
+            return new ValueRule(0, fraction);
+        }
+
+        /**
+         * Creates ValueRule using an absolute value.
+         *
+         * @param absoluteValue Absolute value.
+         * @return Newly created ValueRule.
+         */
+        public static ValueRule absoluteValue(int absoluteValue) {
+            return new ValueRule(absoluteValue, 0);
+        }
+
+        /**
+         * Creates ValueRule of fraction and offset.
+         *
+         * @param fraction Percentage of parent.
+         * @param value    Offset
+         * @return Newly created ValueRule.
+         */
+        public static ValueRule inheritFromParentWithOffset(float fraction, int value) {
+            return new ValueRule(value, fraction);
+        }
+
+        ValueRule(int absoluteValue, float fraction) {
+            this.mAbsoluteValue = absoluteValue;
+            this.mFraction = fraction;
         }
 
         ValueRule(ValueRule rule) {
-            this.type = rule.type;
-            this.fraction = rule.fraction;
-            this.absoluteValue = rule.absoluteValue;
+            this.mFraction = rule.mFraction;
+            this.mAbsoluteValue = rule.mAbsoluteValue;
         }
 
         /**
          * Sets the fractional value (percentage of parent) for this rule.
+         *
+         * @param fraction Percentage of parent.
          */
         public void setFraction(float fraction) {
-            this.fraction = fraction;
+            this.mFraction = fraction;
         }
 
         /**
-         * Returns the current fractional value.
+         * @return The current fractional value.
          */
         public float getFraction() {
-            return fraction;
+            return mFraction;
         }
 
         /**
-         * Sets the absolute value for this rule.
+         * Sets the absolute/offset value for rule.
+         *
+         * @param absoluteValue Absolute value.
          */
         public void setAbsoluteValue(int absoluteValue) {
-            this.absoluteValue = absoluteValue;
+            this.mAbsoluteValue = absoluteValue;
         }
 
         /**
-         * Returns the current absolute value.
+         * @return The current absolute/offset value forrule.
          */
         public int getAbsoluteValue() {
-            return absoluteValue;
+            return mAbsoluteValue;
         }
-    }
 
-    /**
-     * Factory method for creating ValueRule of type INHERIT_FROM_PARENT.
-     */
-    public static ValueRule inheritFromParent(float fraction) {
-        return new ValueRule(INHERIT_PARENT, 0, fraction);
-    }
-
-    /**
-     * Factory method for creating ValueRule of type ABSOLUTE_VALUE.
-     */
-    public static ValueRule absoluteValue(int value) {
-        return new ValueRule(ABSOLUTE_VALUE, value, 0);
-    }
-
-    /**
-     * Factory method for creating ValueRule of type INHERIT_WITH_OFFSET.
-     */
-    public static ValueRule inheritFromParentWithOffset(float fraction, int value) {
-        return new ValueRule(INHERIT_WITH_OFFSET, value, fraction);
     }
 
     /**
@@ -150,17 +149,7 @@
     }
 
     private int doCalculate(int value, ValueRule rule, int size) {
-        int offset = 0;
-        switch(rule.type) {
-            case INHERIT_WITH_OFFSET:
-                offset = rule.absoluteValue;
-            case INHERIT_PARENT:
-                return value + offset + (int)(rule.fraction * size);
-            case ABSOLUTE_VALUE:
-                return rule.absoluteValue;
-        }
-
-        throw new IllegalArgumentException("Invalid type: "+rule.type);
+        return value + rule.mAbsoluteValue + (int) (rule.mFraction * size);
     }
 
     /** {@link ValueRule} for left attribute of {@link BoundsRule} */
diff --git a/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java b/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
index edbca3c..4b68e69 100644
--- a/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
+++ b/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
@@ -21,8 +21,8 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.support.annotation.NonNull;
+import android.support.v17.leanback.graphics.BoundsRule.ValueRule;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.util.Property;
 
@@ -318,7 +318,7 @@
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
                 if (obj.getBoundsRule().top == null) {
-                    obj.getBoundsRule().top = BoundsRule.absoluteValue(value);
+                    obj.getBoundsRule().top = ValueRule.absoluteValue(value);
                 } else {
                     obj.getBoundsRule().top.setAbsoluteValue(value);
                 }
@@ -344,7 +344,7 @@
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
                 if (obj.getBoundsRule().bottom == null) {
-                    obj.getBoundsRule().bottom = BoundsRule.absoluteValue(value);
+                    obj.getBoundsRule().bottom = ValueRule.absoluteValue(value);
                 } else {
                     obj.getBoundsRule().bottom.setAbsoluteValue(value);
                 }
@@ -371,7 +371,7 @@
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
                 if (obj.getBoundsRule().left == null) {
-                    obj.getBoundsRule().left = BoundsRule.absoluteValue(value);
+                    obj.getBoundsRule().left = ValueRule.absoluteValue(value);
                 } else {
                     obj.getBoundsRule().left.setAbsoluteValue(value);
                 }
@@ -397,7 +397,7 @@
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
                 if (obj.getBoundsRule().right == null) {
-                    obj.getBoundsRule().right = BoundsRule.absoluteValue(value);
+                    obj.getBoundsRule().right = ValueRule.absoluteValue(value);
                 } else {
                     obj.getBoundsRule().right.setAbsoluteValue(value);
                 }
@@ -426,7 +426,7 @@
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Float value) {
                 if (obj.getBoundsRule().top == null) {
-                    obj.getBoundsRule().top = BoundsRule.inheritFromParent(value);
+                    obj.getBoundsRule().top = ValueRule.inheritFromParent(value);
                 } else {
                     obj.getBoundsRule().top.setFraction(value);
                 }
@@ -456,7 +456,7 @@
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Float value) {
                 if (obj.getBoundsRule().bottom == null) {
-                    obj.getBoundsRule().bottom = BoundsRule.inheritFromParent(value);
+                    obj.getBoundsRule().bottom = ValueRule.inheritFromParent(value);
                 } else {
                     obj.getBoundsRule().bottom.setFraction(value);
                 }
@@ -485,7 +485,7 @@
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Float value) {
                 if (obj.getBoundsRule().left == null) {
-                    obj.getBoundsRule().left = BoundsRule.inheritFromParent(value);
+                    obj.getBoundsRule().left = ValueRule.inheritFromParent(value);
                 } else {
                     obj.getBoundsRule().left.setFraction(value);
                 }
@@ -510,11 +510,11 @@
          * isn't available at compile time.
          */
         public static final Property<CompositeDrawable.ChildDrawable, Float> RIGHT_FRACTION =
-                new Property<CompositeDrawable.ChildDrawable, Float>(Float.class, "fractoinRight") {
+                new Property<CompositeDrawable.ChildDrawable, Float>(Float.class, "fractionRight") {
             @Override
             public void set(CompositeDrawable.ChildDrawable obj, Float value) {
                 if (obj.getBoundsRule().right == null) {
-                    obj.getBoundsRule().right = BoundsRule.inheritFromParent(value);
+                    obj.getBoundsRule().right = ValueRule.inheritFromParent(value);
                 } else {
                     obj.getBoundsRule().right.setFraction(value);
                 }
diff --git a/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
index 215ba22..9af9302 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
@@ -535,6 +535,7 @@
 
     private void updateControlsRow() {
         updateRowMetadata();
+        updateControlButtons();
         sHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference);
         updatePlaybackState();
     }
@@ -591,6 +592,49 @@
         }
     }
 
+    void updateControlButtons() {
+        final SparseArrayObjectAdapter primaryActionsAdapter = (SparseArrayObjectAdapter)
+                getControlsRow().getPrimaryActionsAdapter();
+        final long actions = getSupportedActions();
+        if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0 && mSkipPreviousAction == null) {
+            mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(getContext());
+            primaryActionsAdapter.set(ACTION_SKIP_TO_PREVIOUS, mSkipPreviousAction);
+        } else if ((actions & ACTION_SKIP_TO_PREVIOUS) == 0 && mSkipPreviousAction != null) {
+            primaryActionsAdapter.clear(ACTION_SKIP_TO_PREVIOUS);
+            mSkipPreviousAction = null;
+        }
+        if ((actions & ACTION_REWIND) != 0 && mRewindAction == null) {
+            mRewindAction = new PlaybackControlsRow.RewindAction(getContext(),
+                    mRewindSpeeds.length);
+            primaryActionsAdapter.set(ACTION_REWIND, mRewindAction);
+        } else if ((actions & ACTION_REWIND) == 0 && mRewindAction != null) {
+            primaryActionsAdapter.clear(ACTION_REWIND);
+            mRewindAction = null;
+        }
+        if ((actions & ACTION_PLAY_PAUSE) != 0 && mPlayPauseAction == null) {
+            mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(getContext());
+            primaryActionsAdapter.set(ACTION_PLAY_PAUSE, mPlayPauseAction);
+        } else if ((actions & ACTION_PLAY_PAUSE) == 0 && mPlayPauseAction != null) {
+            primaryActionsAdapter.clear(ACTION_PLAY_PAUSE);
+            mPlayPauseAction = null;
+        }
+        if ((actions & ACTION_FAST_FORWARD) != 0 && mFastForwardAction == null) {
+            mFastForwardAction = new PlaybackControlsRow.FastForwardAction(getContext(),
+                    mFastForwardSpeeds.length);
+            primaryActionsAdapter.set(ACTION_FAST_FORWARD, mFastForwardAction);
+        } else if ((actions & ACTION_FAST_FORWARD) == 0 && mFastForwardAction != null) {
+            primaryActionsAdapter.clear(ACTION_FAST_FORWARD);
+            mFastForwardAction = null;
+        }
+        if ((actions & ACTION_SKIP_TO_NEXT) != 0 && mSkipNextAction == null) {
+            mSkipNextAction = new PlaybackControlsRow.SkipNextAction(getContext());
+            primaryActionsAdapter.set(ACTION_SKIP_TO_NEXT, mSkipNextAction);
+        } else if ((actions & ACTION_SKIP_TO_NEXT) == 0 && mSkipNextAction != null) {
+            primaryActionsAdapter.clear(ACTION_SKIP_TO_NEXT);
+            mSkipNextAction = null;
+        }
+    }
+
     private void updatePlaybackState(int playbackSpeed) {
         if (mControlsRow == null) {
             return;
@@ -598,56 +642,6 @@
 
         final SparseArrayObjectAdapter primaryActionsAdapter = (SparseArrayObjectAdapter)
                 getControlsRow().getPrimaryActionsAdapter();
-        final long actions = getSupportedActions();
-        if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0) {
-            if (mSkipPreviousAction == null) {
-                mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(getContext());
-            }
-            primaryActionsAdapter.set(ACTION_SKIP_TO_PREVIOUS, mSkipPreviousAction);
-        } else {
-            primaryActionsAdapter.clear(ACTION_SKIP_TO_PREVIOUS);
-            mSkipPreviousAction = null;
-        }
-        if ((actions & ACTION_REWIND) != 0) {
-            if (mRewindAction == null) {
-                mRewindAction = new PlaybackControlsRow.RewindAction(
-                        getContext(),
-                        mRewindSpeeds.length);
-            }
-            primaryActionsAdapter.set(ACTION_REWIND, mRewindAction);
-        } else {
-            primaryActionsAdapter.clear(ACTION_REWIND);
-            mRewindAction = null;
-        }
-        if ((actions & ACTION_PLAY_PAUSE) != 0) {
-            if (mPlayPauseAction == null) {
-                mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(getContext());
-            }
-            primaryActionsAdapter.set(ACTION_PLAY_PAUSE, mPlayPauseAction);
-        } else {
-            primaryActionsAdapter.clear(ACTION_PLAY_PAUSE);
-            mPlayPauseAction = null;
-        }
-        if ((actions & ACTION_FAST_FORWARD) != 0) {
-            if (mFastForwardAction == null) {
-                mFastForwardAction = new PlaybackControlsRow.FastForwardAction(
-                        getContext(),
-                        mFastForwardSpeeds.length);
-            }
-            primaryActionsAdapter.set(ACTION_FAST_FORWARD, mFastForwardAction);
-        } else {
-            primaryActionsAdapter.clear(ACTION_FAST_FORWARD);
-            mFastForwardAction = null;
-        }
-        if ((actions & ACTION_SKIP_TO_NEXT) != 0) {
-            if (mSkipNextAction == null) {
-                mSkipNextAction = new PlaybackControlsRow.SkipNextAction(getContext());
-            }
-            primaryActionsAdapter.set(ACTION_SKIP_TO_NEXT, mSkipNextAction);
-        } else {
-            primaryActionsAdapter.clear(ACTION_SKIP_TO_NEXT);
-            mSkipNextAction = null;
-        }
 
         if (mFastForwardAction != null) {
             int index = 0;
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java b/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java
index dfba1c0..d8ee734 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java
@@ -55,7 +55,7 @@
     }
 
     Animator createAnimator(View view) {
-        final Parallax<?> source = (Parallax) view.getTag(R.id.lb_parallax_source);
+        final Parallax source = (Parallax) view.getTag(R.id.lb_parallax_source);
         if (source == null) {
             return null;
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java b/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
index 523bd4c..487188d 100644
--- a/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
+++ b/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
@@ -13,8 +13,6 @@
  */
 package android.support.v17.leanback.util;
 
-import java.lang.Exception;
-
 /**
  * Math Utilities for leanback library.
  * @hide
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
index ddcf3c6..9f2e452 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
@@ -15,11 +15,10 @@
 
 import android.content.Context;
 import android.graphics.Color;
-import android.util.TypedValue;
+import android.support.v17.leanback.R;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.support.v17.leanback.R;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Action.java b/v17/leanback/src/android/support/v17/leanback/widget/Action.java
index 5e6e313..715fdd9 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/Action.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Action.java
@@ -15,7 +15,6 @@
 
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
-import android.view.KeyEvent;
 
 import java.util.ArrayList;
 
@@ -32,7 +31,7 @@
     private Drawable mIcon;
     private CharSequence mLabel1;
     private CharSequence mLabel2;
-    private ArrayList mKeyCodes = new ArrayList();
+    private ArrayList<Integer> mKeyCodes = new ArrayList<>();
 
     /**
      * Constructor for an Action.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
index 22dba9c..f23acbc 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
@@ -94,7 +94,7 @@
         ViewHolder vh = new ViewHolder(view);
         ViewGroup.LayoutParams lp = view.getLayoutParams();
         vh.setSizeFromDrawableIntrinsic(lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
-                && lp.width == ViewGroup.LayoutParams.WRAP_CONTENT);
+                && lp.height == ViewGroup.LayoutParams.WRAP_CONTENT);
         return vh;
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java
index c7aaf6c..9e8dbcd 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java
@@ -17,7 +17,6 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.view.KeyEvent;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallax.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallax.java
index 374485d..ad5f13a 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallax.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallax.java
@@ -34,19 +34,17 @@
  * @see android.support.v17.leanback.app.DetailsSupportFragmentBackgroundController
  */
 public class DetailsParallax extends RecyclerViewParallax {
-    final Parallax.IntProperty mFrameTop;
-    final Parallax.IntProperty mFrameBottom;
+    final IntProperty mFrameTop;
+    final IntProperty mFrameBottom;
 
     public DetailsParallax() {
         // track the top edge of details_frame of first item of adapter
-        mFrameTop = this
-                .addProperty("overviewRowTop")
+        mFrameTop = addProperty("overviewRowTop")
                 .adapterPosition(0)
                 .viewId(R.id.details_frame);
 
         // track the bottom edge of details_frame of first item of adapter
-        mFrameBottom = this
-                .addProperty("overviewRowBottom")
+        mFrameBottom = addProperty("overviewRowBottom")
                 .adapterPosition(0)
                 .viewId(R.id.details_frame)
                 .fraction(1.0f);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallaxDrawable.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallaxDrawable.java
index d77bc44..37e3480 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallaxDrawable.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsParallaxDrawable.java
@@ -23,7 +23,6 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.v17.leanback.R;
-import android.support.v17.leanback.graphics.BoundsRule;
 import android.support.v17.leanback.graphics.CompositeDrawable;
 import android.support.v17.leanback.graphics.FitWidthBitmapDrawable;
 import android.util.TypedValue;
@@ -124,8 +123,6 @@
         }
         addChildDrawable(coverDrawable);
         addChildDrawable(mBottomDrawable = bottomDrawable);
-        getChildAt(0).getBoundsRule().bottom = BoundsRule.inheritFromParent(1f);
-        getChildAt(1).getBoundsRule().top = BoundsRule.inheritFromParent(1f);
         connect(context, parallax, coverDrawableParallaxTarget);
     }
 
@@ -179,23 +176,18 @@
                 .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions);
         final int toValue = context.getResources()
                 .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description);
-        parallax
-                .addEffect(frameTop.atAbsolute(fromValue), frameTop.atAbsolute(toValue))
+        parallax.addEffect(frameTop.atAbsolute(fromValue), frameTop.atAbsolute(toValue))
                 .target(coverDrawableParallaxTarget);
 
         // Add solid color parallax effect:
         // When frameBottom moves from bottom of the screen to top of the screen,
         // change solid ColorDrawable's top from bottom of screen to top of the screen.
-        parallax.addEffect(frameBottom.atFraction(1f), frameBottom.atFraction(0f))
-                .target(getChildAt(1),
-                        PropertyValuesHolder.ofFloat(
-                                CompositeDrawable.ChildDrawable.TOP_FRACTION, 1f, 0f));
+        parallax.addEffect(frameBottom.atMax(), frameBottom.atMin())
+                .target(getChildAt(1), ChildDrawable.TOP_ABSOLUTE);
         // Also when frameTop moves from bottom of screen to top of the screen,
         // we are changing bottom of the bitmap from bottom of screen to top of screen.
-        parallax.addEffect(frameTop.atFraction(1f), frameTop.atFraction(0f))
-                .target(getChildAt(0),
-                        PropertyValuesHolder.ofFloat(
-                                CompositeDrawable.ChildDrawable.BOTTOM_FRACTION, 1f, 0f));
+        parallax.addEffect(frameTop.atMax(), frameTop.atMin())
+                .target(getChildAt(0), ChildDrawable.BOTTOM_ABSOLUTE);
     }
 
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
index 252a317..64cb769 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
@@ -3,7 +3,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.view.View;
-import android.view.ViewGroup;
 
 final class ForegroundHelper {
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
index 888cc8f..edcec42 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
@@ -14,13 +14,10 @@
 package android.support.v17.leanback.widget;
 
 import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
 import android.support.v17.leanback.R;
 import android.text.TextUtils;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java
index d655e85..5871247 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java
@@ -15,7 +15,6 @@
 
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v17.leanback.widget.picker.DatePicker;
 
 import java.util.Calendar;
 import java.util.TimeZone;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java
index 4790a12..e1b7d13 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java
@@ -16,12 +16,8 @@
 
 import static android.support.v7.widget.RecyclerView.HORIZONTAL;
 import static android.support.v7.widget.RecyclerView.VERTICAL;
-import static android.support.v17.leanback.widget.BaseGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED;
 
-import android.graphics.Rect;
-import android.support.v17.leanback.widget.GridLayoutManager.LayoutParams;
 import android.view.View;
-import android.view.ViewGroup;
 
 /**
  * Defines alignment position on two directions of an item view. Typically item
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
index 19e6e9a..ff152f7 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
@@ -15,7 +15,6 @@
 
 import android.content.Context;
 import android.view.View;
-import android.view.ViewGroup.LayoutParams;
 
 /**
  * A wrapper class working with {@link ItemBridgeAdapter} to wrap item view in a
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java b/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
index ae9d436..ae170c0 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
@@ -15,8 +15,6 @@
 
 import android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef;
 import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.view.ViewGroup;
 
 /**
  * Interface for receiving notification when a child of this ViewGroup has been selected.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Parallax.java b/v17/leanback/src/android/support/v17/leanback/widget/Parallax.java
index 573ca02..aebf9b4 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/Parallax.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Parallax.java
@@ -31,22 +31,40 @@
  * rules to mapping property values to {@link ParallaxTarget}.
  *
  * <p>
- * There are two types of Parallax, int or float. App should subclass either
- * {@link Parallax.IntParallax} or {@link Parallax.FloatParallax}. App may subclass
- * {@link Parallax.IntProperty} or {@link Parallax.FloatProperty} to supply additional information
- * about how to retrieve Property value.  {@link RecyclerViewParallax} is a great example of
- * Parallax implementation tracking child view positions on screen.
+ * Example:
+ * <code>
+ *     // when Property "var1" changes from 15 to max value, perform parallax effect to
+ *     // change myView's translationY from 0 to 100.
+ *     Parallax<IntProperty> parallax = new Parallax<IntProperty>() {...};
+ *     p1 = parallax.addProperty("var1");
+ *     parallax.addEffect(p1.at(15), p1.atMax())
+ *             .target(myView, PropertyValuesHolder.ofFloat("translationY", 0, 100));
+ * </code>
+ * </p>
+ *
+ * <p>
+ * To create a {@link ParallaxEffect}, user calls {@link #addEffect(PropertyMarkerValue[])} with a
+ * list of {@link PropertyMarkerValue} which defines the range of {@link Parallax.IntProperty} or
+ * {@link Parallax.FloatProperty}. Then user adds {@link ParallaxTarget} into
+ * {@link ParallaxEffect}.
+ * </p>
+ * <p>
+ * App may subclass {@link Parallax.IntProperty} or {@link Parallax.FloatProperty} to supply
+ * additional information about how to retrieve Property value.  {@link RecyclerViewParallax} is
+ * a great example of Parallax implementation tracking child view positions on screen.
  * </p>
  * <p>
  * <ul>Restrictions of properties
+ * <li>FloatProperty and IntProperty cannot be mixed in one Parallax</li>
  * <li>Values must be in ascending order.</li>
  * <li>If the UI element is unknown above screen, use UNKNOWN_BEFORE.</li>
  * <li>if the UI element is unknown below screen, use UNKNOWN_AFTER.</li>
  * <li>UNKNOWN_BEFORE and UNKNOWN_AFTER are not allowed to be next to each other.</li>
  * </ul>
- * These rules can be verified by {@link #verifyProperties()}.
+ * These rules will be verified at runtime.
  * </p>
- * Subclass should override {@link #updateValues()} to update property values and perform
+ * <p>
+ * Subclass must override {@link #updateValues()} to update property values and perform
  * {@link ParallaxEffect}s. Subclass may call {@link #updateValues()} automatically e.g.
  * {@link RecyclerViewParallax} calls {@link #updateValues()} in RecyclerView scrolling. App might
  * call {@link #updateValues()} manually when Parallax is unaware of the value change. For example,
@@ -54,15 +72,12 @@
  * changes; it's the app's responsibility to call {@link #updateValues()} in every frame of
  * animation.
  * </p>
- * @param <PropertyT> Class of the property, e.g. {@link IntProperty} or {@link FloatProperty}.
+ * @param <PropertyT> Subclass of {@link Parallax.IntProperty} or {@link Parallax.FloatProperty}
  */
-public abstract class Parallax<PropertyT extends Property> {
-
-    private final List<ParallaxEffect> mEffects = new ArrayList<ParallaxEffect>(4);
+public abstract class Parallax<PropertyT extends android.util.Property> {
 
     /**
      * Class holding a fixed value for a Property in {@link Parallax}.
-     * Base class for {@link IntPropertyMarkerValue} and {@link FloatPropertyMarkerValue}.
      * @param <PropertyT> Class of the property, e.g. {@link IntProperty} or {@link FloatProperty}.
      */
     public static class PropertyMarkerValue<PropertyT> {
@@ -82,10 +97,10 @@
 
     /**
      * IntProperty provide access to an index based integer type property inside
-     * {@link IntParallax}. The IntProperty typically represents UI element position inside
-     * {@link IntParallax}.
+     * {@link Parallax}. The IntProperty typically represents UI element position inside
+     * {@link Parallax}.
      */
-    public static class IntProperty extends Property<IntParallax, Integer> {
+    public static class IntProperty extends Property<Parallax, Integer> {
 
         /**
          * Property value is unknown and it's smaller than minimal value of Parallax. For
@@ -94,7 +109,7 @@
         public static final int UNKNOWN_BEFORE = Integer.MIN_VALUE;
 
         /**
-         * Property value is unknown and it's larger than {@link IntParallax#getMaxValue()}. For
+         * Property value is unknown and it's larger than {@link Parallax#getMaxValue()}. For
          * example if a child is not created and after the last visible child of RecyclerView.
          */
         public static final int UNKNOWN_AFTER = Integer.MAX_VALUE;
@@ -105,7 +120,7 @@
          * Constructor.
          *
          * @param name Name of this Property.
-         * @param index Index of this Property inside {@link IntParallax}.
+         * @param index Index of this Property inside {@link Parallax}.
          */
         public IntProperty(String name, int index) {
             super(Integer.class, name);
@@ -113,168 +128,112 @@
         }
 
         @Override
-        public final Integer get(IntParallax object) {
-            return getIntValue(object);
+        public final Integer get(Parallax object) {
+            return object.getIntPropertyValue(mIndex);
         }
 
         @Override
-        public final void set(IntParallax object, Integer value) {
-            setIntValue(object, value);
-        }
-
-        final int getIntValue(IntParallax source) {
-            return source.getPropertyValue(mIndex);
-        }
-
-        final void setIntValue(IntParallax source, int value) {
-            source.setPropertyValue(mIndex, value);
+        public final void set(Parallax object, Integer value) {
+            object.setIntPropertyValue(mIndex, value);
         }
 
         /**
-         * @return Index of this Property in {@link IntParallax}.
+         * @return Index of this Property in {@link Parallax}.
          */
         public final int getIndex() {
             return mIndex;
         }
 
         /**
-         * Creates an {@link IntPropertyMarkerValue} object for the absolute marker value.
+         * Fast version of get() method that returns a primitive int value of the Property.
+         * @param object The Parallax object that owns this Property.
+         * @return Int value of the Property.
+         */
+        public final int getValue(Parallax object) {
+            return object.getIntPropertyValue(mIndex);
+        }
+
+        /**
+         * Fast version of set() method that takes a primitive int value into the Property.
+         *
+         * @param object The Parallax object that owns this Property.
+         * @param value Int value of the Property.
+         */
+        public final void setValue(Parallax object, int value) {
+            object.setIntPropertyValue(mIndex, value);
+        }
+
+        /**
+         * Creates an {@link PropertyMarkerValue} object for the absolute marker value.
          *
          * @param absoluteValue The integer marker value.
-         * @return A new {@link IntPropertyMarkerValue} object.
+         * @return A new {@link PropertyMarkerValue} object.
          */
-        public final IntPropertyMarkerValue atAbsolute(int absoluteValue) {
+        public final PropertyMarkerValue atAbsolute(int absoluteValue) {
             return new IntPropertyMarkerValue(this, absoluteValue, 0f);
         }
 
         /**
-         * Creates an {@link IntPropertyMarkerValue} object for a fraction of
-         * {@link IntParallax#getMaxValue()}.
+         * Creates an {@link PropertyMarkerValue} object for the marker value representing
+         * {@link Parallax#getMaxValue()}.
+         *
+         * @return A new {@link PropertyMarkerValue} object.
+         */
+        public final PropertyMarkerValue atMax() {
+            return new IntPropertyMarkerValue(this, 0, 1f);
+        }
+
+        /**
+         * Creates an {@link PropertyMarkerValue} object for the marker value representing 0.
+         *
+         * @return A new {@link PropertyMarkerValue} object.
+         */
+        public final PropertyMarkerValue atMin() {
+            return new IntPropertyMarkerValue(this, 0);
+        }
+
+        /**
+         * Creates an {@link PropertyMarkerValue} object for a fraction of
+         * {@link Parallax#getMaxValue()}.
          *
          * @param fractionOfMaxValue 0 to 1 fraction to multiply with
-         *                                       {@link IntParallax#getMaxValue()} for
+         *                                       {@link Parallax#getMaxValue()} for
          *                                       the marker value.
-         * @return A new {@link IntPropertyMarkerValue} object.
+         * @return A new {@link PropertyMarkerValue} object.
          */
-        public final IntPropertyMarkerValue atFraction(float fractionOfMaxValue) {
+        public final PropertyMarkerValue atFraction(float fractionOfMaxValue) {
             return new IntPropertyMarkerValue(this, 0, fractionOfMaxValue);
         }
 
         /**
-         * Create an {@link IntPropertyMarkerValue} object by multiplying the fraction with
-         * {@link IntParallax#getMaxValue()} and adding offsetValue to it.
+         * Create an {@link PropertyMarkerValue} object by multiplying the fraction with
+         * {@link Parallax#getMaxValue()} and adding offsetValue to it.
          *
          * @param offsetValue                    An offset integer value to be added to marker
          *                                       value.
          * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
-         *                                       {@link IntParallax#getMaxValue()} for
+         *                                       {@link Parallax#getMaxValue()} for
          *                                       the marker value.
-         * @return A new {@link IntPropertyMarkerValue} object.
+         * @return A new {@link PropertyMarkerValue} object.
          */
-        public final IntPropertyMarkerValue at(int offsetValue,
-                                               float fractionOfMaxParentVisibleSize) {
+        public final PropertyMarkerValue at(int offsetValue,
+                float fractionOfMaxParentVisibleSize) {
             return new IntPropertyMarkerValue(this, offsetValue, fractionOfMaxParentVisibleSize);
         }
     }
 
     /**
-     * Parallax that manages a list of {@link IntProperty}. App may override this class with a
-     * specific {@link IntProperty} subclass.
-     *
-     * @param <IntPropertyT> Type of {@link IntProperty} or subclass.
-     */
-    public abstract static class IntParallax<IntPropertyT extends IntProperty>
-            extends Parallax<IntPropertyT> {
-
-        private int[] mValues = new int[4];
-
-        /**
-         * Get index based property value.
-         *
-         * @param index Index of the property.
-         * @return Value of the property.
-         */
-        public final int getPropertyValue(int index) {
-            return mValues[index];
-        }
-
-        /**
-         * Set index based property value.
-         *
-         * @param index Index of the property.
-         * @param value Value of the property.
-         */
-        public final void setPropertyValue(int index, int value) {
-            if (index >= mProperties.size()) {
-                throw new ArrayIndexOutOfBoundsException();
-            }
-            mValues[index] = value;
-        }
-
-        /**
-         * Return the max value, which is typically parent visible area, e.g. RecyclerView's height
-         * if we are tracking Y position of a child. The size can be used to calculate marker value
-         * using the provided fraction of IntPropertyMarkerValue.
-         *
-         * @return Max value of parallax.
-         * @see IntPropertyMarkerValue#IntPropertyMarkerValue(IntProperty, int, float)
-         */
-        public abstract int getMaxValue();
-
-        @Override
-        public final IntPropertyT addProperty(String name) {
-            int newPropertyIndex = mProperties.size();
-            IntPropertyT property = createProperty(name, newPropertyIndex);
-            mProperties.add(property);
-            int size = mValues.length;
-            if (size == newPropertyIndex) {
-                int[] newValues = new int[size * 2];
-                for (int i = 0; i < size; i++) {
-                    newValues[i] = mValues[i];
-                }
-                mValues = newValues;
-            }
-            mValues[newPropertyIndex] = IntProperty.UNKNOWN_AFTER;
-            return property;
-        }
-
-        @Override
-        public final void verifyProperties() throws IllegalStateException {
-            if (mProperties.size() < 2) {
-                return;
-            }
-            int last = mProperties.get(0).getIntValue(this);
-            for (int i = 1; i < mProperties.size(); i++) {
-                int v = mProperties.get(i).getIntValue(this);
-                if (v < last) {
-                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
-                                    + " smaller than Property[%d]\"%s\"",
-                            i, mProperties.get(i).getName(),
-                            i - 1, mProperties.get(i - 1).getName()));
-                } else if (last == IntProperty.UNKNOWN_BEFORE && v == IntProperty.UNKNOWN_AFTER) {
-                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
-                                    + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
-                            i - 1, mProperties.get(i - 1).getName(),
-                            i, mProperties.get(i).getName()));
-                }
-                last = v;
-            }
-        }
-
-    }
-
-    /**
      * Implementation of {@link PropertyMarkerValue} for {@link IntProperty}.
      */
-    public static class IntPropertyMarkerValue extends PropertyMarkerValue<IntProperty> {
+    static class IntPropertyMarkerValue extends PropertyMarkerValue<IntProperty> {
         private final int mValue;
         private final float mFactionOfMax;
 
-        public IntPropertyMarkerValue(IntProperty property, int value) {
+        IntPropertyMarkerValue(IntProperty property, int value) {
             this(property, value, 0f);
         }
 
-        public IntPropertyMarkerValue(IntProperty property, int value, float fractionOfMax) {
+        IntPropertyMarkerValue(IntProperty property, int value, float fractionOfMax) {
             super(property);
             mValue = value;
             mFactionOfMax = fractionOfMax;
@@ -283,7 +242,7 @@
         /**
          * @return The marker value of integer type.
          */
-        public final int getMarkerValue(IntParallax source) {
+        final int getMarkerValue(Parallax source) {
             return mFactionOfMax == 0 ? mValue : mValue + Math.round(source
                     .getMaxValue() * mFactionOfMax);
         }
@@ -291,10 +250,10 @@
 
     /**
      * FloatProperty provide access to an index based integer type property inside
-     * {@link FloatParallax}. The FloatProperty typically represents UI element position inside
-     * {@link FloatParallax}.
+     * {@link Parallax}. The FloatProperty typically represents UI element position inside
+     * {@link Parallax}.
      */
-    public static class FloatProperty extends Property<FloatParallax, Float> {
+    public static class FloatProperty extends Property<Parallax, Float> {
 
         /**
          * Property value is unknown and it's smaller than minimal value of Parallax. For
@@ -303,7 +262,7 @@
         public static final float UNKNOWN_BEFORE = -Float.MAX_VALUE;
 
         /**
-         * Property value is unknown and it's larger than {@link FloatParallax#getMaxValue()}. For
+         * Property value is unknown and it's larger than {@link Parallax#getMaxValue()}. For
          * example if a child is not created and after the last visible child of RecyclerView.
          */
         public static final float UNKNOWN_AFTER = Float.MAX_VALUE;
@@ -314,7 +273,7 @@
          * Constructor.
          *
          * @param name Name of this Property.
-         * @param index Index of this Property inside {@link FloatParallax}.
+         * @param index Index of this Property inside {@link Parallax}.
          */
         public FloatProperty(String name, int index) {
             super(Float.class, name);
@@ -322,168 +281,111 @@
         }
 
         @Override
-        public final Float get(FloatParallax object) {
-            return getFloatValue(object);
+        public final Float get(Parallax object) {
+            return object.getFloatPropertyValue(mIndex);
         }
 
         @Override
-        public final void set(FloatParallax object, Float value) {
-            setFloatValue(object, value);
-        }
-
-        final float getFloatValue(FloatParallax source) {
-            return source.getPropertyValue(mIndex);
-        }
-
-        final void setFloatValue(FloatParallax source, float value) {
-            source.setPropertyValue(mIndex, value);
+        public final void set(Parallax object, Float value) {
+            object.setFloatPropertyValue(mIndex, value);
         }
 
         /**
-         * @return Index of this Property in {@link FloatParallax}.
+         * @return Index of this Property in {@link Parallax}.
          */
         public final int getIndex() {
             return mIndex;
         }
 
         /**
-         * Creates an {@link FloatPropertyMarkerValue} object for the absolute marker value.
+         * Fast version of get() method that returns a primitive int value of the Property.
+         * @param object The Parallax object that owns this Property.
+         * @return Float value of the Property.
+         */
+        public final float getValue(Parallax object) {
+            return object.getFloatPropertyValue(mIndex);
+        }
+
+        /**
+         * Fast version of set() method that takes a primitive float value into the Property.
+         *
+         * @param object The Parallax object that owns this Property.
+         * @param value Float value of the Property.
+         */
+        public final void setValue(Parallax object, float value) {
+            object.setFloatPropertyValue(mIndex, value);
+        }
+
+        /**
+         * Creates an {@link PropertyMarkerValue} object for the absolute marker value.
          *
          * @param markerValue The float marker value.
-         * @return A new {@link FloatPropertyMarkerValue} object.
+         * @return A new {@link PropertyMarkerValue} object.
          */
-        public final FloatPropertyMarkerValue atAbsolute(float markerValue) {
+        public final PropertyMarkerValue atAbsolute(float markerValue) {
             return new FloatPropertyMarkerValue(this, markerValue, 0f);
         }
 
         /**
-         * Creates an {@link FloatPropertyMarkerValue} object for a fraction of
-         * {@link FloatParallax#getMaxValue()}.
+         * Creates an {@link PropertyMarkerValue} object for the marker value representing
+         * {@link Parallax#getMaxValue()}.
+         *
+         * @return A new {@link PropertyMarkerValue} object.
+         */
+        public final PropertyMarkerValue atMax() {
+            return new FloatPropertyMarkerValue(this, 0, 1f);
+        }
+
+        /**
+         * Creates an {@link PropertyMarkerValue} object for the marker value representing 0.
+         *
+         * @return A new {@link PropertyMarkerValue} object.
+         */
+        public final PropertyMarkerValue atMin() {
+            return new FloatPropertyMarkerValue(this, 0);
+        }
+
+        /**
+         * Creates an {@link PropertyMarkerValue} object for a fraction of
+         * {@link Parallax#getMaxValue()}.
          *
          * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
-         *                                       {@link FloatParallax#getMaxValue()} for
+         *                                       {@link Parallax#getMaxValue()} for
          *                                       the marker value.
-         * @return A new {@link FloatPropertyMarkerValue} object.
+         * @return A new {@link PropertyMarkerValue} object.
          */
-        public final FloatPropertyMarkerValue atFraction(float fractionOfMaxParentVisibleSize) {
+        public final PropertyMarkerValue atFraction(float fractionOfMaxParentVisibleSize) {
             return new FloatPropertyMarkerValue(this, 0, fractionOfMaxParentVisibleSize);
         }
 
         /**
-         * Create an {@link FloatPropertyMarkerValue} object by multiplying the fraction with
-         * {@link FloatParallax#getMaxValue()} and adding offsetValue to it.
+         * Create an {@link PropertyMarkerValue} object by multiplying the fraction with
+         * {@link Parallax#getMaxValue()} and adding offsetValue to it.
          *
          * @param offsetValue                    An offset float value to be added to marker value.
          * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
-         *                                       {@link FloatParallax#getMaxValue()} for
+         *                                       {@link Parallax#getMaxValue()} for
          *                                       the marker value.
-         * @return A new {@link FloatPropertyMarkerValue} object.
+         * @return A new {@link PropertyMarkerValue} object.
          */
-        public final FloatPropertyMarkerValue at(float offsetValue,
-                                                 float fractionOfMaxParentVisibleSize) {
+        public final PropertyMarkerValue at(float offsetValue,
+                float fractionOfMaxParentVisibleSize) {
             return new FloatPropertyMarkerValue(this, offsetValue, fractionOfMaxParentVisibleSize);
         }
     }
 
     /**
-     * Parallax that manages a list of {@link FloatProperty}. App may override this class with a
-     * specific {@link FloatProperty} subclass.
-     *
-     * @param <FloatPropertyT> Type of {@link FloatProperty} or subclass.
-     */
-    public abstract static class FloatParallax<FloatPropertyT extends FloatProperty> extends
-            Parallax<FloatPropertyT> {
-
-        private float[] mValues = new float[4];
-
-        /**
-         * Get index based property value.
-         *
-         * @param index Index of the property.
-         * @return Value of the property.
-         */
-        public final float getPropertyValue(int index) {
-            return mValues[index];
-        }
-
-        /**
-         * Set index based property value.
-         *
-         * @param index Index of the property.
-         * @param value Value of the property.
-         */
-        public final void setPropertyValue(int index, float value) {
-            if (index >= mProperties.size()) {
-                throw new ArrayIndexOutOfBoundsException();
-            }
-            mValues[index] = value;
-        }
-
-        /**
-         * Return the max value which is typically size of parent visible area, e.g. RecyclerView's
-         * height if we are tracking Y position of a child. The size can be used to calculate marker
-         * value using the provided fraction of FloatPropertyMarkerValue.
-         *
-         * @return Size of parent visible area.
-         * @see FloatPropertyMarkerValue#FloatPropertyMarkerValue(FloatProperty, float, float)
-         */
-        public abstract float getMaxValue();
-
-        @Override
-        public final FloatPropertyT addProperty(String name) {
-            int newPropertyIndex = mProperties.size();
-            FloatPropertyT property = createProperty(name, newPropertyIndex);
-            mProperties.add(property);
-            int size = mValues.length;
-            if (size == newPropertyIndex) {
-                float[] newValues = new float[size * 2];
-                for (int i = 0; i < size; i++) {
-                    newValues[i] = mValues[i];
-                }
-                mValues = newValues;
-            }
-            mValues[newPropertyIndex] = FloatProperty.UNKNOWN_AFTER;
-            return property;
-        }
-
-        @Override
-        public final void verifyProperties() throws IllegalStateException {
-            if (mProperties.size() < 2) {
-                return;
-            }
-            float last = mProperties.get(0).getFloatValue(this);
-            for (int i = 1; i < mProperties.size(); i++) {
-                float v = mProperties.get(i).getFloatValue(this);
-                if (v < last) {
-                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
-                                    + " smaller than Property[%d]\"%s\"",
-                            i, mProperties.get(i).getName(),
-                            i - 1, mProperties.get(i - 1).getName()));
-                } else if (last == FloatProperty.UNKNOWN_BEFORE && v
-                        == FloatProperty.UNKNOWN_AFTER) {
-                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
-                                    + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
-                            i - 1, mProperties.get(i - 1).getName(),
-                            i, mProperties.get(i).getName()));
-                }
-                last = v;
-            }
-        }
-
-    }
-
-    /**
      * Implementation of {@link PropertyMarkerValue} for {@link FloatProperty}.
      */
-    public static class FloatPropertyMarkerValue extends PropertyMarkerValue<FloatProperty> {
+    static class FloatPropertyMarkerValue extends PropertyMarkerValue<FloatProperty> {
         private final float mValue;
         private final float mFactionOfMax;
 
-        public FloatPropertyMarkerValue(FloatProperty property, float value) {
+        FloatPropertyMarkerValue(FloatProperty property, float value) {
             this(property, value, 0f);
         }
 
-        public FloatPropertyMarkerValue(FloatProperty property, float value, float fractionOfMax) {
+        FloatPropertyMarkerValue(FloatProperty property, float value, float fractionOfMax) {
             super(property);
             mValue = value;
             mFactionOfMax = fractionOfMax;
@@ -492,7 +394,7 @@
         /**
          * @return The marker value.
          */
-        public final float getMarkerValue(FloatParallax source) {
+        final float getMarkerValue(Parallax source) {
             return mFactionOfMax == 0 ? mValue : mValue + source.getMaxValue()
                     * mFactionOfMax;
         }
@@ -501,6 +403,156 @@
     final List<PropertyT> mProperties = new ArrayList<PropertyT>();
     final List<PropertyT> mPropertiesReadOnly = Collections.unmodifiableList(mProperties);
 
+    private int[] mValues = new int[4];
+    private float[] mFloatValues = new float[4];
+
+    private final List<ParallaxEffect> mEffects = new ArrayList<ParallaxEffect>(4);
+
+    /**
+     * Return the max value which is typically size of parent visible area, e.g. RecyclerView's
+     * height if we are tracking Y position of a child. The size can be used to calculate marker
+     * value using the provided fraction of FloatPropertyMarkerValue.
+     *
+     * @return Size of parent visible area.
+     * @see IntPropertyMarkerValue#IntPropertyMarkerValue(IntProperty, int, float)
+     * @see FloatPropertyMarkerValue#FloatPropertyMarkerValue(FloatProperty, float, float)
+     */
+    public abstract float getMaxValue();
+
+    /**
+     * Get index based property value.
+     *
+     * @param index Index of the property.
+     * @return Value of the property.
+     */
+    final int getIntPropertyValue(int index) {
+        return mValues[index];
+    }
+
+    /**
+     * Set index based property value.
+     *
+     * @param index Index of the property.
+     * @param value Value of the property.
+     */
+    final void setIntPropertyValue(int index, int value) {
+        if (index >= mProperties.size()) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        mValues[index] = value;
+    }
+
+    /**
+     * Add a new IntProperty in the Parallax object. App may override
+     * {@link #createProperty(String, int)}.
+     *
+     * @param name Name of the property.
+     * @return Newly created Property object.
+     * @see #createProperty(String, int)
+     */
+    public final PropertyT addProperty(String name) {
+        int newPropertyIndex = mProperties.size();
+        PropertyT property = createProperty(name, newPropertyIndex);
+        if (property instanceof IntProperty) {
+            int size = mValues.length;
+            if (size == newPropertyIndex) {
+                int[] newValues = new int[size * 2];
+                for (int i = 0; i < size; i++) {
+                    newValues[i] = mValues[i];
+                }
+                mValues = newValues;
+            }
+            mValues[newPropertyIndex] = IntProperty.UNKNOWN_AFTER;
+        } else if (property instanceof FloatProperty) {
+            int size = mFloatValues.length;
+            if (size == newPropertyIndex) {
+                float[] newValues = new float[size * 2];
+                for (int i = 0; i < size; i++) {
+                    newValues[i] = mFloatValues[i];
+                }
+                mFloatValues = newValues;
+            }
+            mFloatValues[newPropertyIndex] = FloatProperty.UNKNOWN_AFTER;
+        } else {
+            throw new IllegalArgumentException("Invalid Property type");
+        }
+        mProperties.add(property);
+        return property;
+    }
+
+    /**
+     * Verify sanity of property values, throws RuntimeException if fails. The property values
+     * must be in ascending order. UNKNOW_BEFORE and UNKNOWN_AFTER are not allowed to be next to
+     * each other.
+     */
+    void verifyIntProperties() throws IllegalStateException {
+        if (mProperties.size() < 2) {
+            return;
+        }
+        int last = getIntPropertyValue(0);
+        for (int i = 1; i < mProperties.size(); i++) {
+            int v = getIntPropertyValue(i);
+            if (v < last) {
+                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                + " smaller than Property[%d]\"%s\"",
+                        i, mProperties.get(i).getName(),
+                        i - 1, mProperties.get(i - 1).getName()));
+            } else if (last == IntProperty.UNKNOWN_BEFORE && v == IntProperty.UNKNOWN_AFTER) {
+                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
+                        i - 1, mProperties.get(i - 1).getName(),
+                        i, mProperties.get(i).getName()));
+            }
+            last = v;
+        }
+    }
+
+    final void verifyFloatProperties() throws IllegalStateException {
+        if (mProperties.size() < 2) {
+            return;
+        }
+        float last = getFloatPropertyValue(0);
+        for (int i = 1; i < mProperties.size(); i++) {
+            float v = getFloatPropertyValue(i);
+            if (v < last) {
+                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                + " smaller than Property[%d]\"%s\"",
+                        i, mProperties.get(i).getName(),
+                        i - 1, mProperties.get(i - 1).getName()));
+            } else if (last == FloatProperty.UNKNOWN_BEFORE && v
+                    == FloatProperty.UNKNOWN_AFTER) {
+                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
+                        i - 1, mProperties.get(i - 1).getName(),
+                        i, mProperties.get(i).getName()));
+            }
+            last = v;
+        }
+    }
+
+    /**
+     * Get index based property value.
+     *
+     * @param index Index of the property.
+     * @return Value of the property.
+     */
+    final float getFloatPropertyValue(int index) {
+        return mFloatValues[index];
+    }
+
+    /**
+     * Set index based property value.
+     *
+     * @param index Index of the property.
+     * @param value Value of the property.
+     */
+    final void setFloatPropertyValue(int index, float value) {
+        if (index >= mProperties.size()) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        mFloatValues[index] = value;
+    }
+
     /**
      * @return A unmodifiable list of properties.
      */
@@ -509,14 +561,6 @@
     }
 
     /**
-     * Add a new Property in the Parallax object.
-     *
-     * @param name Name of the property.
-     * @return Newly created Property.
-     */
-    public abstract PropertyT addProperty(String name);
-
-    /**
      * Create a new Property object. App does not directly call this method.  See
      * {@link #addProperty(String)}.
      *
@@ -526,13 +570,6 @@
     public abstract PropertyT createProperty(String name, int index);
 
     /**
-     * Verify sanity of property values, throws RuntimeException if fails. The property values
-     * must be in ascending order. UNKNOW_BEFORE and UNKNOWN_AFTER are not allowed to be next to
-     * each other.
-     */
-    public abstract void verifyProperties() throws IllegalStateException;
-
-    /**
      * Update property values and perform {@link ParallaxEffect}s. Subclass may override and call
      * super.updateValues() after updated properties values.
      */
@@ -544,16 +581,6 @@
     }
 
     /**
-     * Adds a {@link ParallaxEffect} object which defines rules to perform mapping to multiple
-     * {@link ParallaxTarget}s.
-     *
-     * @param effect A {@link ParallaxEffect} object.
-     */
-    public void addEffect(ParallaxEffect effect) {
-        mEffects.add(effect);
-    }
-
-    /**
      * Returns a list of {@link ParallaxEffect} object which defines rules to perform mapping to
      * multiple {@link ParallaxTarget}s.
      *
@@ -586,24 +613,16 @@
      * @param ranges A list of marker values that defines the ranges.
      * @return Newly created ParallaxEffect object.
      */
-    public ParallaxEffect addEffect(IntPropertyMarkerValue... ranges) {
-        IntEffect effect = new IntEffect();
+    public ParallaxEffect addEffect(PropertyMarkerValue... ranges) {
+        ParallaxEffect effect;
+        if (ranges[0].getProperty() instanceof IntProperty) {
+            effect = new IntEffect();
+        } else {
+            effect = new FloatEffect();
+        }
         effect.setPropertyRanges(ranges);
-        addEffect(effect);
+        mEffects.add(effect);
         return effect;
     }
 
-    /**
-     * Create a {@link ParallaxEffect} object that will track source variable changes within a
-     * provided set of ranges.
-     *
-     * @param ranges A list of marker values that defines the ranges.
-     * @return Newly created ParallaxEffect object.
-     */
-    public ParallaxEffect addEffect(FloatPropertyMarkerValue... ranges) {
-        FloatEffect effect = new FloatEffect();
-        effect.setPropertyRanges(ranges);
-        addEffect(effect);
-        return effect;
-    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java
index 5760bdb..5c06e29 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java
@@ -21,6 +21,7 @@
 import android.support.v17.leanback.widget.Parallax.FloatPropertyMarkerValue;
 import android.support.v17.leanback.widget.Parallax.IntProperty;
 import android.support.v17.leanback.widget.Parallax.PropertyMarkerValue;
+import android.util.Property;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -36,25 +37,30 @@
  * on, the fraction increases from 0 at beginning to 1 at the end. Then the fraction is passed on
  * to {@link ParallaxTarget#update(float)}.
  * <p>
- * ParallaxEffect has two concrete subclasses, {@link IntEffect} and {@link FloatEffect}.
+ * App use {@link Parallax#addEffect(PropertyMarkerValue...)} to create a ParallaxEffect.
  */
-public abstract class ParallaxEffect<ParallaxEffectT extends ParallaxEffect,
-        PropertyMarkerValueT extends Parallax.PropertyMarkerValue> {
+public abstract class ParallaxEffect {
 
-    final List<PropertyMarkerValueT> mMarkerValues = new ArrayList<PropertyMarkerValueT>(2);
+    final List<Parallax.PropertyMarkerValue> mMarkerValues = new ArrayList(2);
     final List<Float> mWeights = new ArrayList<Float>(2);
     final List<Float> mTotalWeights = new ArrayList<Float>(2);
     final List<ParallaxTarget> mTargets = new ArrayList<ParallaxTarget>(4);
 
     /**
+     * Only accessible from package
+     */
+    ParallaxEffect() {
+    }
+
+    /**
      * Returns the list of {@link PropertyMarkerValue}s, which represents the range of values that
      * source variables can take.
      *
      * @return A list of {@link Parallax.PropertyMarkerValue}s.
      * @see #performMapping(Parallax)
      */
-    public final List<PropertyMarkerValueT> getPropertyRanges() {
-        return  mMarkerValues;
+    public final List<Parallax.PropertyMarkerValue> getPropertyRanges() {
+        return mMarkerValues;
     }
 
     /**
@@ -75,9 +81,9 @@
      * @param markerValues A list of {@link PropertyMarkerValue}s.
      * @see #performMapping(Parallax)
      */
-    public final void setPropertyRanges(PropertyMarkerValueT... markerValues) {
+    public final void setPropertyRanges(Parallax.PropertyMarkerValue... markerValues) {
         mMarkerValues.clear();
-        for (PropertyMarkerValueT markerValue : markerValues) {
+        for (Parallax.PropertyMarkerValue markerValue : markerValues) {
             mMarkerValues.add(markerValue);
         }
     }
@@ -154,6 +160,23 @@
     }
 
     /**
+     * Creates a {@link ParallaxTarget} using direct mapping from source property into target
+     * property, the new {@link ParallaxTarget} will be added to its list of targets.
+     *
+     * @param targetObject Target object for property.
+     * @param targetProperty The target property that will receive values.
+     * @return This ParallaxEffect object, allowing calls to methods in this class to be chained.
+     * @param <T> Type of target object.
+     * @param <V> Type of target property value, either Integer or Float.
+     * @see ParallaxTarget#isDirectMapping()
+     */
+    public final <T, V extends Number> ParallaxEffect target(T targetObject,
+            Property<T, V> targetProperty) {
+        mTargets.add(new ParallaxTarget.DirectPropertyTarget(targetObject, targetProperty));
+        return this;
+    }
+
+    /**
      * Returns the list of {@link ParallaxTarget} objects.
      *
      * @return The list of {@link ParallaxTarget} objects.
@@ -177,10 +200,28 @@
         if (mMarkerValues.size() < 2) {
             return;
         }
-        source.verifyProperties();
-        float fraction = calculateFraction(source);
+        if (this instanceof IntEffect) {
+            source.verifyIntProperties();
+        } else {
+            source.verifyFloatProperties();
+        }
+        boolean fractionCalculated = false;
+        float fraction = 0;
+        Number directValue = null;
         for (int i = 0; i < mTargets.size(); i++) {
-            mTargets.get(i).update(fraction);
+            ParallaxTarget target = mTargets.get(i);
+            if (target.isDirectMapping()) {
+                if (directValue == null) {
+                    directValue = calculateDirectValue(source);
+                }
+                target.directUpdate(directValue);
+            } else {
+                if (!fractionCalculated) {
+                    fractionCalculated = true;
+                    fraction = calculateFraction(source);
+                }
+                target.update(fraction);
+            }
         }
     }
 
@@ -191,7 +232,15 @@
      *
      * @return Float value between 0 and 1.
      */
-    protected abstract float calculateFraction(Parallax source);
+    abstract float calculateFraction(Parallax source);
+
+    /**
+     * This method is expected to get the current value of the single {@link IntProperty} or
+     * {@link FloatProperty}.
+     *
+     * @return Current value of the single {@link IntProperty} or {@link FloatProperty}.
+     */
+    abstract Number calculateDirectValue(Parallax source);
 
     /**
      * When there are multiple ranges (aka three or more markerValues),  this method adjust the
@@ -226,21 +275,48 @@
     /**
      * Implementation of {@link ParallaxEffect} for integer type.
      */
-    public static final class IntEffect extends ParallaxEffect<IntEffect,
-            Parallax.IntPropertyMarkerValue> {
+    static final class IntEffect extends ParallaxEffect {
 
         @Override
-        protected float calculateFraction(Parallax s) {
-            Parallax.IntParallax source = (Parallax.IntParallax) s;
+        Number calculateDirectValue(Parallax source) {
+            if (mMarkerValues.size() != 2) {
+                throw new RuntimeException("Must use two marker values for direct mapping");
+            }
+            if (mMarkerValues.get(0).getProperty() != mMarkerValues.get(1).getProperty()) {
+                throw new RuntimeException(
+                        "Marker value must use same Property for direct mapping");
+            }
+            int value1 = ((Parallax.IntPropertyMarkerValue) mMarkerValues.get(0))
+                    .getMarkerValue(source);
+            int value2 = ((Parallax.IntPropertyMarkerValue) mMarkerValues.get(1))
+                    .getMarkerValue(source);
+            if (value1 > value2) {
+                int swapValue = value2;
+                value2 = value1;
+                value1 = swapValue;
+            }
+
+            Number currentValue = ((IntProperty) mMarkerValues.get(0).getProperty()).get(source);
+            if (currentValue.intValue() < value1) {
+                currentValue = value1;
+            } else if (currentValue.intValue() > value2) {
+                currentValue = value2;
+            }
+            return currentValue;
+        }
+
+        @Override
+        float calculateFraction(Parallax source) {
             int lastIndex = 0;
             int lastValue = 0;
             int lastMarkerValue = 0;
             // go through all markerValues, find first markerValue that current value is less than.
             for (int i = 0; i <  mMarkerValues.size(); i++) {
-                Parallax.IntPropertyMarkerValue k =  mMarkerValues.get(i);
+                Parallax.IntPropertyMarkerValue k =  (Parallax.IntPropertyMarkerValue)
+                        mMarkerValues.get(i);
                 int index = k.getProperty().getIndex();
                 int markerValue = k.getMarkerValue(source);
-                int currentValue = source.getPropertyValue(index);
+                int currentValue = source.getIntPropertyValue(index);
 
                 float fraction;
                 if (i == 0) {
@@ -294,21 +370,47 @@
     /**
      * Implementation of {@link ParallaxEffect} for float type.
      */
-    public static final class FloatEffect extends ParallaxEffect<FloatEffect,
-            Parallax.FloatPropertyMarkerValue> {
+    static final class FloatEffect extends ParallaxEffect {
 
         @Override
-        protected float calculateFraction(Parallax s) {
-            Parallax.FloatParallax source = (Parallax.FloatParallax) s;
+        Number calculateDirectValue(Parallax source) {
+            if (mMarkerValues.size() != 2) {
+                throw new RuntimeException("Must use two marker values for direct mapping");
+            }
+            if (mMarkerValues.get(0).getProperty() != mMarkerValues.get(1).getProperty()) {
+                throw new RuntimeException(
+                        "Marker value must use same Property for direct mapping");
+            }
+            float value1 = ((FloatPropertyMarkerValue) mMarkerValues.get(0))
+                    .getMarkerValue(source);
+            float value2 = ((FloatPropertyMarkerValue) mMarkerValues.get(1))
+                    .getMarkerValue(source);
+            if (value1 > value2) {
+                float swapValue = value2;
+                value2 = value1;
+                value1 = swapValue;
+            }
+
+            Number currentValue = ((FloatProperty) mMarkerValues.get(0).getProperty()).get(source);
+            if (currentValue.floatValue() < value1) {
+                currentValue = value1;
+            } else if (currentValue.floatValue() > value2) {
+                currentValue = value2;
+            }
+            return currentValue;
+        }
+
+        @Override
+        float calculateFraction(Parallax source) {
             int lastIndex = 0;
             float lastValue = 0;
             float lastMarkerValue = 0;
             // go through all markerValues, find first markerValue that current value is less than.
             for (int i = 0; i <  mMarkerValues.size(); i++) {
-                FloatPropertyMarkerValue k =  mMarkerValues.get(i);
+                FloatPropertyMarkerValue k = (FloatPropertyMarkerValue) mMarkerValues.get(i);
                 int index = k.getProperty().getIndex();
                 float markerValue = k.getMarkerValue(source);
-                float currentValue = source.getPropertyValue(index);
+                float currentValue = source.getFloatPropertyValue(index);
 
                 float fraction;
                 if (i == 0) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java
index 7020433..49783ab 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java
@@ -18,32 +18,51 @@
 
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.util.Property;
 import android.view.animation.LinearInterpolator;
 
 /**
- * ParallaxTarget is responsible for updating the target through the {@link #update(float)} method.
- * {@link ParallaxEffect} transforms the values of {@link Parallax}, which represents the
- * current state of UI, into a float value between 0 and 1. That float value is passed into
- * {@link #update(float)} method.
+ * ParallaxTarget is responsible for updating the target through the {@link #update(float)} method
+ * or the {@link #directUpdate(Number)} method when {@link #isDirectMapping()} is true.
+ * When {@link #isDirectMapping()} is false, {@link ParallaxEffect} transforms the values of
+ * {@link Parallax}, which represents the current state of UI, into a float value between 0 and 1.
+ * That float value is passed into {@link #update(float)} method.
  */
 public abstract class ParallaxTarget {
 
     /**
      * Implementation class is supposed to update target with the provided fraction
      * (between 0 and 1). The fraction represents percentage of completed change (e.g. scroll) on
-     * target.
+     * target. Called only when {@link #isDirectMapping()} is false.
      *
      * @param fraction Fraction between 0 to 1.
+     * @see #isDirectMapping()
      */
-    public abstract void update(float fraction);
+    public void update(float fraction) {
+    }
 
     /**
-     * Returns the current fraction (between 0 and 1). The fraction represents percentage of
-     * completed change (e.g. scroll) on target.
+     * Returns true if the ParallaxTarget is directly mapping from source value,
+     * {@link #directUpdate(Number)} will be used to update value, otherwise update(fraction) will
+     * be called to update value. Default implementation returns false.
      *
-     * @return Current fraction value.
+     * @return True if direct mapping, false otherwise.
+     * @see #directUpdate(Number)
+     * @see #update(float)
      */
-    public abstract float getFraction();
+    public boolean isDirectMapping() {
+        return false;
+    }
+
+    /**
+     * Directly update the target using a float or int value. Called when {@link #isDirectMapping()}
+     * is true.
+     *
+     * @param value Either int or float value.
+     * @see #isDirectMapping()
+     */
+    public void directUpdate(Number value) {
+    }
 
     /**
      * PropertyValuesHolderTarget is an implementation of {@link ParallaxTarget} that uses
@@ -72,9 +91,42 @@
             mAnimator.setCurrentPlayTime((long) (PSEUDO_DURATION * fraction));
         }
 
+    }
+
+    /**
+     * DirectPropertyTarget is to support direct mapping into either Integer Property or Float
+     * Property. App uses convenient method {@link ParallaxEffect#target(Object, Property)} to
+     * add a direct mapping.
+     * @param <T> Type of target object.
+     * @param <V> Type of value, either Integer or Float.
+     */
+    public static final class DirectPropertyTarget<T extends Object, V extends Number>
+            extends ParallaxTarget {
+
+        Object mObject;
+        Property<T, V> mProperty;
+
+        /**
+         * @param targetObject Target object for perform Parallax
+         * @param property     Target property, either an Integer Property or a Float Property.
+         */
+        public DirectPropertyTarget(Object targetObject, Property<T, V> property) {
+            mObject = targetObject;
+            mProperty = property;
+        }
+
+        /**
+         * Returns true as DirectPropertyTarget receives a number to update Property in
+         * {@link #directUpdate(Number)}.
+         */
         @Override
-        public float getFraction() {
-            return mFraction;
+        public boolean isDirectMapping() {
+            return true;
+        }
+
+        @Override
+        public void directUpdate(Number value) {
+            mProperty.set((T) mObject, (V) value);
         }
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
index 83aff47..f54a454 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
@@ -13,20 +13,18 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.util.MathUtil;
-import android.util.TypedValue;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.util.MathUtil;
+import android.util.TypedValue;
 import android.view.KeyEvent;
 
 /**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java b/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java
index 20c40f9..589eef5 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java
@@ -22,6 +22,7 @@
 
 import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
+import android.util.Property;
 import android.view.View;
 
 /**
@@ -29,8 +30,7 @@
  * allows users to track position of specific views inside {@link RecyclerView} relative to
  * itself. @see {@link ChildPositionProperty} for details.
  */
-public class RecyclerViewParallax extends
-        Parallax.IntParallax<RecyclerViewParallax.ChildPositionProperty> {
+public class RecyclerViewParallax extends Parallax<RecyclerViewParallax.ChildPositionProperty> {
     RecyclerView mRecylerView;
     boolean mIsVertical;
 
@@ -141,16 +141,16 @@
                     : recyclerView.findViewHolderForAdapterPosition(mAdapterPosition);
             if (viewHolder == null) {
                 if (recyclerView == null || recyclerView.getLayoutManager().getChildCount() == 0) {
-                    source.setPropertyValue(getIndex(), IntProperty.UNKNOWN_AFTER);
+                    source.setIntPropertyValue(getIndex(), IntProperty.UNKNOWN_AFTER);
                     return;
                 }
                 View firstChild = recyclerView.getLayoutManager().getChildAt(0);
                 ViewHolder vh = recyclerView.findContainingViewHolder(firstChild);
                 int firstPosition = vh.getAdapterPosition();
                 if (firstPosition < mAdapterPosition) {
-                    source.setPropertyValue(getIndex(), IntProperty.UNKNOWN_AFTER);
+                    source.setIntPropertyValue(getIndex(), IntProperty.UNKNOWN_AFTER);
                 } else {
-                    source.setPropertyValue(getIndex(), IntProperty.UNKNOWN_BEFORE);
+                    source.setIntPropertyValue(getIndex(), IntProperty.UNKNOWN_BEFORE);
                 }
             } else {
                 View trackingView = viewHolder.itemView.findViewById(mViewId);
@@ -171,10 +171,10 @@
                 }
                 rect.offset((int) tx, (int) ty);
                 if (source.mIsVertical) {
-                    source.setPropertyValue(getIndex(), rect.top + mOffset
+                    source.setIntPropertyValue(getIndex(), rect.top + mOffset
                             + (int) (mFraction * rect.height()));
                 } else {
-                    source.setPropertyValue(getIndex(), rect.left + mOffset
+                    source.setIntPropertyValue(getIndex(), rect.left + mOffset
                             + (int) (mFraction * rect.width()));
                 }
             }
@@ -188,7 +188,7 @@
     }
 
     @Override
-    public int getMaxValue() {
+    public float getMaxValue() {
         if (mRecylerView == null) {
             return 0;
         }
@@ -221,8 +221,8 @@
      */
     @Override
     public void updateValues() {
-        for (ChildPositionProperty prop: getProperties()) {
-            prop.updateValue(RecyclerViewParallax.this);
+        for (Property prop: getProperties()) {
+            ((ChildPositionProperty) prop).updateValue(RecyclerViewParallax.this);
         }
         super.updateValues();
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java b/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java
index 56c63cf..51047d3 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchEditText.java
@@ -18,7 +18,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.widget.EditText;
 
 /**
  * EditText widget that monitors keyboard changes.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
index 1d731db..88d0aad 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
@@ -17,8 +17,6 @@
 import android.support.v4.util.CircularIntArray;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * A dynamic data structure that caches staggered grid position information
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
index 6c6e664..4422d62 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
@@ -16,7 +16,6 @@
 package android.support.v17.leanback.widget;
 
 import android.os.Build;
-import android.view.View;
 import android.view.ViewGroup;
 
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java b/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java
index 5bc0a8c..0b8781c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java
@@ -13,13 +13,13 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.support.v17.leanback.R;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.support.v17.leanback.R;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.SpannedString;
@@ -31,7 +31,6 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.EditText;
-import android.widget.TextView;
 
 import java.util.List;
 import java.util.Random;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/TitleViewAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/TitleViewAdapter.java
index 7156be2..de9db4b 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/TitleViewAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/TitleViewAdapter.java
@@ -13,11 +13,7 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.content.Context;
 import android.graphics.drawable.Drawable;
-import android.support.v17.leanback.R;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
 import android.view.View;
 
 /**
@@ -96,6 +92,10 @@
      * @param listener The listener to call when the search element is clicked.
      */
     public void setOnSearchClickedListener(View.OnClickListener listener) {
+        View view = getSearchAffordanceView();
+        if (view != null) {
+            view.setOnClickListener(listener);
+        }
     }
 
     /**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
index edb3ab2..56b6ed1 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
@@ -17,11 +17,10 @@
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.system.Settings;
 import android.support.v17.leanback.transition.TransitionHelper;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.util.Log;
 
 /**
  * A presenter that renders objects in a {@link VerticalGridView}.
diff --git a/v17/leanback/tests/generatev4.py b/v17/leanback/tests/generatev4.py
index 34ace00..2e228eb 100755
--- a/v17/leanback/tests/generatev4.py
+++ b/v17/leanback/tests/generatev4.py
@@ -136,12 +136,12 @@
     line = line.replace('IntEffect', 'FloatEffect')
     line = line.replace('IntParallax', 'FloatParallax')
     line = line.replace('IntProperty', 'FloatProperty')
-    line = line.replace('IntValue', 'FloatValue')
     line = line.replace('intValue()', 'floatValue()')
-    line = line.replace('int getMaxValue', 'float getMaxValue')
     line = line.replace('int screenMax', 'float screenMax')
     line = line.replace('assertEquals((int)', 'assertFloatEquals((float)')
     line = line.replace('(int)', '(float)')
+    line = line.replace('int[', 'float[')
+    line = line.replace('Integer', 'Float');
     outfile.write(line)
 file.close()
 outfile.close()
@@ -156,9 +156,8 @@
     line = line.replace('ParallaxIntTest', 'ParallaxFloatTest')
     line = line.replace('IntParallax', 'FloatParallax')
     line = line.replace('IntProperty', 'FloatProperty')
-    line = line.replace('IntValue', 'FloatValue')
+    line = line.replace('verifyIntProperties', 'verifyFloatProperties')
     line = line.replace('intValue()', 'floatValue()')
-    line = line.replace('int getMaxValue', 'float getMaxValue')
     line = line.replace('int screenMax', 'float screenMax')
     line = line.replace('assertEquals((int)', 'assertFloatEquals((float)')
     line = line.replace('(int)', '(float)')
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
index 50168a7..b70cc28 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
@@ -30,7 +30,6 @@
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.graphics.FitWidthBitmapDrawable;
 import android.support.v17.leanback.media.MediaPlayerGlue;
@@ -125,7 +124,6 @@
         assertEquals(0f, frameBottom.getAdapterPosition(), delta);
     }
 
-    @Suppress // Disabled due to flakiness.
     @Test
     public void parallaxTest() throws Throwable {
         launchAndWaitActivity(DetailsFragmentParallax.class,
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
index cd6032e..3880a7c 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
@@ -33,7 +33,6 @@
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.graphics.FitWidthBitmapDrawable;
 import android.support.v17.leanback.media.MediaPlayerGlue;
@@ -128,7 +127,6 @@
         assertEquals(0f, frameBottom.getAdapterPosition(), delta);
     }
 
-    @Suppress // Disabled due to flakiness.
     @Test
     public void parallaxTest() throws Throwable {
         launchAndWaitActivity(DetailsSupportFragmentParallax.class,
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
index 326d2be..70c8795 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
@@ -597,9 +597,53 @@
         playbackGlue.createControlsRowAndPresenter();
         // after a controls row is created, onRowChanged() call back is called once
         assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
         playbackGlue.notifyMetaDataChanged();
         // onMetaDataChanged() calls updateRowMetadata which ends up calling
         // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
         assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
     }
+
+
+    @Test
+    public void testWithoutValidMedia() throws Exception {
+        final PlaybackOverlayFragment[] fragmentResult = new
+                PlaybackOverlayFragment[1];
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fragmentResult[0] = new PlaybackOverlayFragment();
+            }
+        });
+        final boolean[] hasValidMedia = new boolean[] {false};
+        PlaybackOverlayFragment fragment = fragmentResult[0];
+        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
+                new int[]{
+                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
+                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1,
+                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2
+                }) {
+            @Override
+            public boolean hasValidMedia() {
+                return hasValidMedia[0];
+            }
+        };
+
+        // before any controls row is created the count is zero
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
+        playbackGlue.createControlsRowAndPresenter();
+        // after a controls row is created, onRowChanged() call back is called once
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
+        // enven hasValidMedia() is false, we should still have three buttons.
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
+
+        hasValidMedia[0] = true;
+        playbackGlue.notifyMetaDataChanged();
+        // onMetaDataChanged() calls updateRowMetadata which ends up calling
+        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
+    }
+
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
index 944c1f7..37f5754 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
@@ -600,9 +600,53 @@
         playbackGlue.createControlsRowAndPresenter();
         // after a controls row is created, onRowChanged() call back is called once
         assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
         playbackGlue.notifyMetaDataChanged();
         // onMetaDataChanged() calls updateRowMetadata which ends up calling
         // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
         assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
     }
+
+
+    @Test
+    public void testWithoutValidMedia() throws Exception {
+        final PlaybackOverlaySupportFragment[] fragmentResult = new
+                PlaybackOverlaySupportFragment[1];
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fragmentResult[0] = new PlaybackOverlaySupportFragment();
+            }
+        });
+        final boolean[] hasValidMedia = new boolean[] {false};
+        PlaybackOverlaySupportFragment fragment = fragmentResult[0];
+        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
+                new int[]{
+                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0,
+                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L1,
+                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2
+                }) {
+            @Override
+            public boolean hasValidMedia() {
+                return hasValidMedia[0];
+            }
+        };
+
+        // before any controls row is created the count is zero
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
+        playbackGlue.createControlsRowAndPresenter();
+        // after a controls row is created, onRowChanged() call back is called once
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
+        // enven hasValidMedia() is false, we should still have three buttons.
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
+
+        hasValidMedia[0] = true;
+        playbackGlue.notifyMetaDataChanged();
+        // onMetaDataChanged() calls updateRowMetadata which ends up calling
+        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
+        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
+    }
+
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
index b1c6d14..6f6459a 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
@@ -15,6 +15,8 @@
  */
 package android.support.v17.leanback.app;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -22,20 +24,25 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.media.PlaybackControlGlue;
 import android.support.v17.leanback.media.PlaybackGlue;
 import android.support.v17.leanback.testutils.PollingCheck;
+import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.view.KeyEvent;
+import android.view.View;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -106,7 +113,6 @@
         verify(selectedListener, times(0)).onItemSelected(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(selectedListener, times(1)).onItemSelected(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -114,7 +120,6 @@
         assertSame("The selected action should be rewind", rewind, itemCaptor.getValue());
 
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(selectedListener, times(2)).onItemSelected(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -125,7 +130,7 @@
         ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);
 
         sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-        Thread.sleep(TRANSITION_LENGTH);
+        waitForScrollIdle(fragment.getVerticalGridView());
         verify(selectedListener, times(3)).onItemSelected(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same list row should be passed to the listener", listRow0,
@@ -174,7 +179,6 @@
         verify(clickedListener, times(0)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(1)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -182,11 +186,9 @@
         assertSame("The clicked action should be playPause", playPause, itemCaptor.getValue());
 
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(1)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(2)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -194,11 +196,9 @@
         assertSame("The clicked action should be rewind", rewind, itemCaptor.getValue());
 
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(2)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(3)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -209,11 +209,10 @@
         ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);
 
         sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-        Thread.sleep(TRANSITION_LENGTH);
+        waitForScrollIdle(fragment.getVerticalGridView());
         verify(clickedListener, times(3)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(4)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same list row should be passed to the listener", listRow0,
@@ -224,4 +223,139 @@
                 listRowItemPassed);
     }
 
+    @Test
+    public void alignmentRowToBottom() throws Throwable {
+        launchAndWaitActivity(PlaybackTestFragment.class, 1000);
+        final PlaybackTestFragment fragment = (PlaybackTestFragment) mActivity.getTestFragment();
+
+        assertTrue(fragment.getAdapter().size() > 2);
+
+        View playRow = fragment.getVerticalGridView().getChildAt(0);
+        assertTrue(playRow.hasFocus());
+        assertEquals(playRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
+
+        activityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                fragment.getVerticalGridView().setSelectedPositionSmooth(
+                        fragment.getAdapter().size() - 1);
+            }
+        });
+        waitForScrollIdle(fragment.getVerticalGridView());
+
+        View lastRow = fragment.getVerticalGridView().getChildAt(
+                fragment.getVerticalGridView().getChildCount() - 1);
+        assertEquals(fragment.getAdapter().size() - 1,
+                fragment.getVerticalGridView().getChildAdapterPosition(lastRow));
+        assertTrue(lastRow.hasFocus());
+        assertEquals(lastRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - lastRow.getBottom());
+    }
+
+    public static class PurePlaybackFragment extends PlaybackFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setFadingEnabled(false);
+            PlaybackControlsRow row = new PlaybackControlsRow();
+            SparseArrayObjectAdapter primaryAdapter = new SparseArrayObjectAdapter(
+                    new ControlButtonPresenterSelector());
+            primaryAdapter.set(0, new PlaybackControlsRow.SkipPreviousAction(getActivity()));
+            primaryAdapter.set(1, new PlaybackControlsRow.PlayPauseAction(getActivity()));
+            primaryAdapter.set(2, new PlaybackControlsRow.SkipNextAction(getActivity()));
+            row.setPrimaryActionsAdapter(primaryAdapter);
+            row.setSecondaryActionsAdapter(null);
+            setPlaybackRow(row);
+            setPlaybackRowPresenter(new PlaybackControlsRowPresenter());
+        }
+    }
+
+    @Test
+    public void setupRowAndPresenterWithoutGlue() {
+        launchAndWaitActivity(PurePlaybackFragment.class, 1000);
+        final PurePlaybackFragment fragment = (PurePlaybackFragment)
+                mActivity.getTestFragment();
+
+        assertTrue(fragment.getAdapter().size() == 1);
+        View playRow = fragment.getVerticalGridView().getChildAt(0);
+        assertTrue(playRow.hasFocus());
+        assertEquals(playRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
+    }
+
+    public static class ControlGlueFragment extends PlaybackFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            int[] ffspeeds = new int[] {PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
+                    PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1};
+            PlaybackGlue glue = new PlaybackControlGlue(
+                    getActivity(), ffspeeds) {
+                @Override
+                public boolean hasValidMedia() {
+                    return true;
+                }
+
+                @Override
+                public boolean isMediaPlaying() {
+                    return false;
+                }
+
+                @Override
+                public CharSequence getMediaTitle() {
+                    return "Title";
+                }
+
+                @Override
+                public CharSequence getMediaSubtitle() {
+                    return "SubTitle";
+                }
+
+                @Override
+                public int getMediaDuration() {
+                    return 100;
+                }
+
+                @Override
+                public Drawable getMediaArt() {
+                    return null;
+                }
+
+                @Override
+                public long getSupportedActions() {
+                    return PlaybackControlGlue.ACTION_PLAY_PAUSE;
+                }
+
+                @Override
+                public int getCurrentSpeedId() {
+                    return PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+                }
+
+                @Override
+                public int getCurrentPosition() {
+                    return 50;
+                }
+            };
+            glue.setHost(new PlaybackFragmentGlueHost(this));
+        }
+    }
+
+    @Test
+    public void setupWithControlGlue() throws Throwable {
+        launchAndWaitActivity(ControlGlueFragment.class, 1000);
+        final ControlGlueFragment fragment = (ControlGlueFragment)
+                mActivity.getTestFragment();
+
+        assertTrue(fragment.getAdapter().size() == 1);
+
+        View playRow = fragment.getVerticalGridView().getChildAt(0);
+        assertTrue(playRow.hasFocus());
+        assertEquals(playRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java
index dfc3458..be78f79 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java
@@ -15,12 +15,15 @@
  */
 package android.support.v17.leanback.app;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.test.R;
+import android.view.View;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -40,4 +43,38 @@
         assertTrue(fragment.getView().hasFocus());
     }
 
+    @Test
+    public void alignmentRowToBottom() throws Throwable {
+        launchAndWaitActivity(PlaybackOverlayTestFragment.class,
+                new Options().activityLayoutId(R.layout.playback_controls_with_video), 0);
+        final PlaybackOverlayTestFragment fragment = (PlaybackOverlayTestFragment)
+                mActivity.getTestFragment();
+
+        assertTrue(fragment.getAdapter().size() > 2);
+
+        View playRow = fragment.getVerticalGridView().getChildAt(0);
+        assertTrue(playRow.hasFocus());
+        assertEquals(playRow.getResources().getDimensionPixelSize(
+                R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
+
+        activityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                fragment.getVerticalGridView().setSelectedPositionSmooth(
+                        fragment.getAdapter().size() - 1);
+            }
+        });
+        waitForScrollIdle(fragment.getVerticalGridView());
+
+        View lastRow = fragment.getVerticalGridView().getChildAt(
+                fragment.getVerticalGridView().getChildCount() - 1);
+        assertEquals(fragment.getAdapter().size() - 1,
+                fragment.getVerticalGridView().getChildAdapterPosition(lastRow));
+        assertTrue(lastRow.hasFocus());
+        assertEquals(lastRow.getResources().getDimensionPixelSize(
+                R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - lastRow.getBottom());
+    }
+
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
index 388cfc8..de8ff88 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
@@ -22,6 +22,7 @@
 import android.support.v17.leanback.test.R;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
@@ -62,7 +63,6 @@
 
     private PlaybackControlHelper mGlue;
     private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
-    private ListRowPresenter mListRowPresenter;
 
     private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
         @Override
@@ -136,19 +136,11 @@
 
         mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
         mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
-        mListRowPresenter = new ListRowPresenter();
+        ClassPresenterSelector selector = new ClassPresenterSelector();
+        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
+        selector.addClassPresenter(PlaybackControlsRow.class, mPlaybackControlsRowPresenter);
 
-        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object object) {
-                if (object instanceof PlaybackControlsRow) {
-                    return mPlaybackControlsRowPresenter;
-                } else if (object instanceof ListRow) {
-                    return mListRowPresenter;
-                }
-                throw new IllegalArgumentException("Unhandled object: " + object);
-            }
-        }));
+        setAdapter(new SparseArrayObjectAdapter(selector));
 
         // Add the controls row
         getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
index b21ea01..fc9867e 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
@@ -18,6 +18,8 @@
  */
 package android.support.v17.leanback.app;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -25,20 +27,25 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.media.PlaybackControlGlue;
 import android.support.v17.leanback.media.PlaybackGlue;
 import android.support.v17.leanback.testutils.PollingCheck;
+import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.view.KeyEvent;
+import android.view.View;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -109,7 +116,6 @@
         verify(selectedListener, times(0)).onItemSelected(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(selectedListener, times(1)).onItemSelected(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -117,7 +123,6 @@
         assertSame("The selected action should be rewind", rewind, itemCaptor.getValue());
 
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(selectedListener, times(2)).onItemSelected(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -128,7 +133,7 @@
         ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);
 
         sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-        Thread.sleep(TRANSITION_LENGTH);
+        waitForScrollIdle(fragment.getVerticalGridView());
         verify(selectedListener, times(3)).onItemSelected(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same list row should be passed to the listener", listRow0,
@@ -177,7 +182,6 @@
         verify(clickedListener, times(0)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(1)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -185,11 +189,9 @@
         assertSame("The clicked action should be playPause", playPause, itemCaptor.getValue());
 
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(1)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(2)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -197,11 +199,9 @@
         assertSame("The clicked action should be rewind", rewind, itemCaptor.getValue());
 
         sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(2)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(3)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same controls row should be passed to the listener", controlsRow,
@@ -212,11 +212,10 @@
         ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);
 
         sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-        Thread.sleep(TRANSITION_LENGTH);
+        waitForScrollIdle(fragment.getVerticalGridView());
         verify(clickedListener, times(3)).onItemClicked(any(Presenter.ViewHolder.class),
                 any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        Thread.sleep(TRANSITION_LENGTH);
         verify(clickedListener, times(4)).onItemClicked(itemVHCaptor.capture(),
                 itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
         assertSame("Same list row should be passed to the listener", listRow0,
@@ -227,4 +226,139 @@
                 listRowItemPassed);
     }
 
+    @Test
+    public void alignmentRowToBottom() throws Throwable {
+        launchAndWaitActivity(PlaybackTestSupportFragment.class, 1000);
+        final PlaybackTestSupportFragment fragment = (PlaybackTestSupportFragment) mActivity.getTestFragment();
+
+        assertTrue(fragment.getAdapter().size() > 2);
+
+        View playRow = fragment.getVerticalGridView().getChildAt(0);
+        assertTrue(playRow.hasFocus());
+        assertEquals(playRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
+
+        activityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                fragment.getVerticalGridView().setSelectedPositionSmooth(
+                        fragment.getAdapter().size() - 1);
+            }
+        });
+        waitForScrollIdle(fragment.getVerticalGridView());
+
+        View lastRow = fragment.getVerticalGridView().getChildAt(
+                fragment.getVerticalGridView().getChildCount() - 1);
+        assertEquals(fragment.getAdapter().size() - 1,
+                fragment.getVerticalGridView().getChildAdapterPosition(lastRow));
+        assertTrue(lastRow.hasFocus());
+        assertEquals(lastRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - lastRow.getBottom());
+    }
+
+    public static class PurePlaybackSupportFragment extends PlaybackSupportFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setFadingEnabled(false);
+            PlaybackControlsRow row = new PlaybackControlsRow();
+            SparseArrayObjectAdapter primaryAdapter = new SparseArrayObjectAdapter(
+                    new ControlButtonPresenterSelector());
+            primaryAdapter.set(0, new PlaybackControlsRow.SkipPreviousAction(getActivity()));
+            primaryAdapter.set(1, new PlaybackControlsRow.PlayPauseAction(getActivity()));
+            primaryAdapter.set(2, new PlaybackControlsRow.SkipNextAction(getActivity()));
+            row.setPrimaryActionsAdapter(primaryAdapter);
+            row.setSecondaryActionsAdapter(null);
+            setPlaybackRow(row);
+            setPlaybackRowPresenter(new PlaybackControlsRowPresenter());
+        }
+    }
+
+    @Test
+    public void setupRowAndPresenterWithoutGlue() {
+        launchAndWaitActivity(PurePlaybackSupportFragment.class, 1000);
+        final PurePlaybackSupportFragment fragment = (PurePlaybackSupportFragment)
+                mActivity.getTestFragment();
+
+        assertTrue(fragment.getAdapter().size() == 1);
+        View playRow = fragment.getVerticalGridView().getChildAt(0);
+        assertTrue(playRow.hasFocus());
+        assertEquals(playRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
+    }
+
+    public static class ControlGlueFragment extends PlaybackSupportFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            int[] ffspeeds = new int[] {PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
+                    PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1};
+            PlaybackGlue glue = new PlaybackControlGlue(
+                    getActivity(), ffspeeds) {
+                @Override
+                public boolean hasValidMedia() {
+                    return true;
+                }
+
+                @Override
+                public boolean isMediaPlaying() {
+                    return false;
+                }
+
+                @Override
+                public CharSequence getMediaTitle() {
+                    return "Title";
+                }
+
+                @Override
+                public CharSequence getMediaSubtitle() {
+                    return "SubTitle";
+                }
+
+                @Override
+                public int getMediaDuration() {
+                    return 100;
+                }
+
+                @Override
+                public Drawable getMediaArt() {
+                    return null;
+                }
+
+                @Override
+                public long getSupportedActions() {
+                    return PlaybackControlGlue.ACTION_PLAY_PAUSE;
+                }
+
+                @Override
+                public int getCurrentSpeedId() {
+                    return PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+                }
+
+                @Override
+                public int getCurrentPosition() {
+                    return 50;
+                }
+            };
+            glue.setHost(new PlaybackSupportFragmentGlueHost(this));
+        }
+    }
+
+    @Test
+    public void setupWithControlGlue() throws Throwable {
+        launchAndWaitActivity(ControlGlueFragment.class, 1000);
+        final ControlGlueFragment fragment = (ControlGlueFragment)
+                mActivity.getTestFragment();
+
+        assertTrue(fragment.getAdapter().size() == 1);
+
+        View playRow = fragment.getVerticalGridView().getChildAt(0);
+        assertTrue(playRow.hasFocus());
+        assertEquals(playRow.getResources().getDimensionPixelSize(
+                android.support.v17.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
+                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java
index 99a7fc6..c9cc5b2 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java
@@ -23,6 +23,7 @@
 import android.support.v17.leanback.test.R;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
@@ -46,8 +47,6 @@
      */
     private static final int BACKGROUND_TYPE = PlaybackFragment.BG_LIGHT;
 
-    private static final int ROW_CONTROLS = 0;
-
     /**
      * Change this to select hidden
      */
@@ -59,7 +58,6 @@
     private static final int RELATED_CONTENT_ROWS = 3;
 
     private android.support.v17.leanback.media.PlaybackControlGlue mGlue;
-    private ListRowPresenter mListRowPresenter;
     boolean mDestroyCalled;
 
     @Override
@@ -120,23 +118,10 @@
         };
 
         mGlue.setHost(new PlaybackFragmentGlueHost(this));
-       //  mGlue.setOnI
-        mListRowPresenter = new ListRowPresenter();
+        ClassPresenterSelector selector = new ClassPresenterSelector();
+        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
 
-        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object object) {
-                if (object instanceof PlaybackControlsRow) {
-                    return mGlue.getControlsRowPresenter();
-                } else if (object instanceof ListRow) {
-                    return mListRowPresenter;
-                }
-                throw new IllegalArgumentException("Unhandled object: " + object);
-            }
-        }));
-
-        // Add the controls row
-        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
+        setAdapter(new SparseArrayObjectAdapter(selector));
 
         // Add related content rows
         for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
@@ -144,7 +129,7 @@
             listRowAdapter.add("Some related content");
             listRowAdapter.add("Other related content");
             HeaderItem header = new HeaderItem(i, "Row " + i);
-            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
+            getAdapter().set(1 + i, new ListRow(header, listRowAdapter));
         }
     }
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
index ef99eb6..4e63522 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
@@ -26,6 +26,7 @@
 import android.support.v17.leanback.test.R;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
@@ -49,8 +50,6 @@
      */
     private static final int BACKGROUND_TYPE = PlaybackSupportFragment.BG_LIGHT;
 
-    private static final int ROW_CONTROLS = 0;
-
     /**
      * Change this to select hidden
      */
@@ -62,7 +61,6 @@
     private static final int RELATED_CONTENT_ROWS = 3;
 
     private android.support.v17.leanback.media.PlaybackControlGlue mGlue;
-    private ListRowPresenter mListRowPresenter;
     boolean mDestroyCalled;
 
     @Override
@@ -123,23 +121,10 @@
         };
 
         mGlue.setHost(new PlaybackSupportFragmentGlueHost(this));
-       //  mGlue.setOnI
-        mListRowPresenter = new ListRowPresenter();
+        ClassPresenterSelector selector = new ClassPresenterSelector();
+        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
 
-        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object object) {
-                if (object instanceof PlaybackControlsRow) {
-                    return mGlue.getControlsRowPresenter();
-                } else if (object instanceof ListRow) {
-                    return mListRowPresenter;
-                }
-                throw new IllegalArgumentException("Unhandled object: " + object);
-            }
-        }));
-
-        // Add the controls row
-        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
+        setAdapter(new SparseArrayObjectAdapter(selector));
 
         // Add related content rows
         for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
@@ -147,7 +132,7 @@
             listRowAdapter.add("Some related content");
             listRowAdapter.add("Other related content");
             HeaderItem header = new HeaderItem(i, "Row " + i);
-            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
+            getAdapter().set(1 + i, new ListRow(header, listRowAdapter));
         }
     }
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
index 561facb..aec79a3 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
@@ -20,6 +20,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.support.v17.leanback.testutils.PollingCheck;
+import android.support.v7.widget.RecyclerView;
 
 import org.junit.After;
 import org.junit.Rule;
@@ -27,6 +28,8 @@
 
 public class SingleFragmentTestBase {
 
+    private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000;
+
     @Rule
     public TestName mUnitTestName = new TestName();
 
@@ -105,4 +108,28 @@
         mActivity = activityTestRule.launchActivity(intent);
         SystemClock.sleep(waitTimeMs);
     }
+
+    protected void waitForScrollIdle(RecyclerView recyclerView) throws Throwable {
+        waitForScrollIdle(recyclerView, null);
+    }
+
+    protected void waitForScrollIdle(RecyclerView recyclerView, Runnable verify) throws Throwable {
+        Thread.sleep(100);
+        int total = 0;
+        while (recyclerView.getLayoutManager().isSmoothScrolling()
+                || recyclerView.getScrollState() != recyclerView.SCROLL_STATE_IDLE) {
+            if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) {
+                throw new RuntimeException("waitForScrollIdle Timeout");
+            }
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                break;
+            }
+            if (verify != null) {
+                activityTestRule.runOnUiThread(verify);
+            }
+        }
+    }
+
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
index 3083ecf..bb2009f 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
@@ -23,6 +23,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.support.v17.leanback.testutils.PollingCheck;
+import android.support.v7.widget.RecyclerView;
 
 import org.junit.After;
 import org.junit.Rule;
@@ -30,6 +31,8 @@
 
 public class SingleSupportFragmentTestBase {
 
+    private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000;
+
     @Rule
     public TestName mUnitTestName = new TestName();
 
@@ -108,4 +111,28 @@
         mActivity = activityTestRule.launchActivity(intent);
         SystemClock.sleep(waitTimeMs);
     }
+
+    protected void waitForScrollIdle(RecyclerView recyclerView) throws Throwable {
+        waitForScrollIdle(recyclerView, null);
+    }
+
+    protected void waitForScrollIdle(RecyclerView recyclerView, Runnable verify) throws Throwable {
+        Thread.sleep(100);
+        int total = 0;
+        while (recyclerView.getLayoutManager().isSmoothScrolling()
+                || recyclerView.getScrollState() != recyclerView.SCROLL_STATE_IDLE) {
+            if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) {
+                throw new RuntimeException("waitForScrollIdle Timeout");
+            }
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                break;
+            }
+            if (verify != null) {
+                activityTestRule.runOnUiThread(verify);
+            }
+        }
+    }
+
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java
index 7f9b408..9aa872c 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java
@@ -83,7 +83,7 @@
 
     public static final String EXTRA_PROVIDER = "testActivityProvider";
 
-    static HashMap<String, Provider> sProviders = new HashMap();
+    static HashMap<String, Provider> sProviders = new HashMap<>();
 
     String mProviderName;
     Provider mProvider;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
index 3819dac..691a9df 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
@@ -18,7 +18,6 @@
 import android.support.v17.leanback.app.GuidedStepFragment;
 import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidedAction;
-import android.util.Log;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java b/v17/leanback/tests/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java
index 132013a..df2c94c 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java
@@ -28,6 +28,7 @@
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.graphics.BoundsRule.ValueRule;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -68,7 +69,7 @@
 
         // inherit from parent
         parentDrawable.addChildDrawable(drawable);
-        parentDrawable.getChildAt(0).getBoundsRule().bottom = BoundsRule.inheritFromParent(
+        parentDrawable.getChildAt(0).getBoundsRule().bottom = ValueRule.inheritFromParent(
                 fraction);
         parentDrawable.updateBounds(bounds);
 
@@ -79,7 +80,7 @@
 
         // absolute value
         drawable.setBounds(bounds);
-        parentDrawable.getChildAt(0).getBoundsRule().bottom = BoundsRule.absoluteValue(200);
+        parentDrawable.getChildAt(0).getBoundsRule().bottom = ValueRule.absoluteValue(200);
         parentDrawable.updateBounds(bounds);
 
         adjustedBounds = drawable.getBounds();
@@ -89,7 +90,7 @@
 
         // inherit with offset
         parentDrawable.getChildAt(0).getBoundsRule().bottom =
-                BoundsRule.inheritFromParentWithOffset(fraction, 100);
+                ValueRule.inheritFromParentWithOffset(fraction, 100);
         parentDrawable.updateBounds(bounds);
 
         adjustedBounds = drawable.getBounds();
@@ -100,7 +101,7 @@
         // inherit from parent 2
         bounds = new Rect(100, 200, WIDTH, HEIGHT);
         parentDrawable.getChildAt(0).getBoundsRule().bottom =
-                BoundsRule.inheritFromParent(fraction);
+                ValueRule.inheritFromParent(fraction);
         parentDrawable.updateBounds(bounds);
 
         adjustedBounds = drawable.getBounds();
@@ -124,8 +125,8 @@
 
         // inherit from parent
         BoundsRule boundsRule = parentDrawable.getChildAt(0).getBoundsRule();
-        boundsRule.top = BoundsRule.absoluteValue(-200);
-        boundsRule.bottom = BoundsRule.inheritFromParent(fraction);
+        boundsRule.top = ValueRule.absoluteValue(-200);
+        boundsRule.bottom = ValueRule.inheritFromParent(fraction);
         parentDrawable.getChildAt(0).getBoundsRule().top.setAbsoluteValue(-100);
 
         parentDrawable.updateBounds(bounds);
@@ -133,21 +134,32 @@
         Rect adjustedBounds = drawable.getBounds();
         Rect expectedBounds = new Rect(bounds);
         expectedBounds.top = -100;
-        expectedBounds.bottom = bounds.top + (int) (HEIGHT * fraction);
+        expectedBounds.bottom = (int) (HEIGHT * fraction);
         assertEquals(expectedBounds, adjustedBounds);
 
         // inherit from parent with offset
-        boundsRule.bottom = BoundsRule.absoluteValue(HEIGHT);
+        boundsRule.bottom = ValueRule.inheritFromParentWithOffset(1f, -100);
 
         parentDrawable.updateBounds(bounds);
 
         adjustedBounds = drawable.getBounds();
         expectedBounds = new Rect(bounds);
         expectedBounds.top = -100;
-        expectedBounds.bottom = HEIGHT;
+        expectedBounds.bottom = HEIGHT - 100;
+        assertEquals(expectedBounds, adjustedBounds);
+
+        // using property would change type:
+        CompositeDrawable.ChildDrawable.BOTTOM_ABSOLUTE.set(parentDrawable.getChildAt(0), 0);
+        CompositeDrawable.ChildDrawable.BOTTOM_FRACTION.set(parentDrawable.getChildAt(0), 0.5f);
+        parentDrawable.updateBounds(bounds);
+        adjustedBounds = drawable.getBounds();
+        expectedBounds = new Rect(bounds);
+        expectedBounds.top = -100;
+        expectedBounds.bottom = (int) (0.5f * HEIGHT);
         assertEquals(expectedBounds, adjustedBounds);
     }
 
+
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     @Test
     public void constantState() {
@@ -184,7 +196,7 @@
         FitWidthBitmapDrawable child = new FitWidthBitmapDrawable();
         parent.addChildDrawable(child);
         parent.getChildAt(0).getBoundsRule().bottom =
-                BoundsRule.inheritFromParentWithOffset(.5f, 100);
+                ValueRule.inheritFromParentWithOffset(.5f, 100);
 
         CompositeDrawable.ChildDrawable newChild = new CompositeDrawable.ChildDrawable(
                 parent.getChildAt(0),
@@ -201,7 +213,7 @@
         FitWidthBitmapDrawable child = new FitWidthBitmapDrawable();
         parent.addChildDrawable(child);
         parent.getChildAt(0).getBoundsRule().bottom =
-                BoundsRule.inheritFromParentWithOffset(.5f, 100);
+                ValueRule.inheritFromParentWithOffset(.5f, 100);
 
         CompositeDrawable newDrawable = (CompositeDrawable) parent.getConstantState().newDrawable();
 
@@ -215,4 +227,5 @@
         assertEquals(parent.getChildAt(0).getBoundsRule().bottom.getFraction(),
                 newChild.getBoundsRule().bottom.getFraction(), delta);
     }
+
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java b/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
index 2f2fc5d..77a903e 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
@@ -18,8 +18,6 @@
 import android.app.Activity;
 import android.view.View;
 
-import java.util.concurrent.Callable;
-
 import junit.framework.Assert;
 
 public abstract class PollingCheck {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
index 1e314e4..ff87b93 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -224,7 +224,7 @@
      */
     protected View[][] sortByRows() {
         final HashMap<Integer, ArrayList<View>> rows = new HashMap<Integer, ArrayList<View>>();
-        ArrayList<Integer> rowLocations = new ArrayList();
+        ArrayList<Integer> rowLocations = new ArrayList<>();
         for (int i = 0; i < mGridView.getChildCount(); i++) {
             View v = mGridView.getChildAt(i);
             int rowLocation;
@@ -2890,7 +2890,7 @@
         mNumRows = 1;
 
         assertEquals(mGridView.getSelectedPosition(), 0);
-        final SparseArray states = new SparseArray();
+        final SparseArray<Parcelable> states = new SparseArray<>();
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
index eca3b9a..046b4c0 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
@@ -19,11 +19,14 @@
 
 package android.support.v17.leanback.widget;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.Property;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -36,15 +39,19 @@
 @SmallTest
 public class ParallaxFloatEffectTest {
 
-    Parallax.FloatParallax mSource;
+    Parallax<Parallax.FloatProperty> mSource;
     int mScreenMax;
     ParallaxEffect.FloatEffect mEffect;
     @Mock ParallaxTarget mTarget;
 
+    static void assertFloatEquals(float expected, float actual) {
+        org.junit.Assert.assertEquals((double) expected, (double) actual, 0.0001d);
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mSource = new Parallax.FloatParallax<Parallax.FloatProperty>() {
+        mSource = new Parallax<Parallax.FloatProperty>() {
 
             @Override
             public float getMaxValue() {
@@ -68,55 +75,55 @@
         mEffect.target(mTarget);
 
         // start
-        var1.setFloatValue(mSource, 540);
+        var1.setValue(mSource, 540);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // 25% complete
-        var1.setFloatValue(mSource, 405);
+        var1.setValue(mSource, 405);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.25f);
         Mockito.reset(mTarget);
 
         // middle
-        var1.setFloatValue(mSource, 270);
+        var1.setValue(mSource, 270);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(.5f);
         Mockito.reset(mTarget);
 
         // 75% complete
-        var1.setFloatValue(mSource, 135);
+        var1.setValue(mSource, 135);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.75f);
         Mockito.reset(mTarget);
 
         // end
-        var1.setFloatValue(mSource, 0);
+        var1.setValue(mSource, 0);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // after end
-        var1.setFloatValue(mSource, -1000);
+        var1.setValue(mSource, -1000);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // before start
-        var1.setFloatValue(mSource, 1000);
+        var1.setValue(mSource, 1000);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_before
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_after
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
@@ -129,7 +136,7 @@
 
         mEffect.setPropertyRanges(var1.atAbsolute(540), var1.atAbsolute(550));
         mEffect.target(mTarget);
-        var1.setFloatValue(mSource, 0);
+        var1.setValue(mSource, 0);
         mEffect.performMapping(mSource);
     }
 
@@ -143,95 +150,137 @@
         mEffect.target(mTarget);
 
         // start
-        var1.setFloatValue(mSource, 540);
-        var2.setFloatValue(mSource, 840);
+        var1.setValue(mSource, 540);
+        var2.setValue(mSource, 840);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // middle
-        var1.setFloatValue(mSource, 390);
-        var2.setFloatValue(mSource, 690);
+        var1.setValue(mSource, 390);
+        var2.setValue(mSource, 690);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(.5f);
         Mockito.reset(mTarget);
 
         // end
-        var1.setFloatValue(mSource, 240);
-        var2.setFloatValue(mSource, 540);
+        var1.setValue(mSource, 240);
+        var2.setValue(mSource, 540);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // after end
-        var1.setFloatValue(mSource, 200);
-        var2.setFloatValue(mSource, 500);
+        var1.setValue(mSource, 200);
+        var2.setValue(mSource, 500);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // before start
-        var1.setFloatValue(mSource, 1000);
-        var2.setFloatValue(mSource, 1300);
+        var1.setValue(mSource, 1000);
+        var2.setValue(mSource, 1300);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_before
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
-        var2.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_before
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
-        var2.setFloatValue(mSource, -1000);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, -1000);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_after
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
-        var2.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
+        var2.setValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_after
-        var1.setFloatValue(mSource, 1000);
-        var2.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, 1000);
+        var2.setValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_before and less
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
-        var2.setFloatValue(mSource, 500);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, 500);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_before and hit second
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
-        var2.setFloatValue(mSource, 540);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, 540);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_before with estimation
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
-        var2.setFloatValue(mSource, 1080);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, 1080);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.5f);
         Mockito.reset(mTarget);
 
         // unknown_after with estimation
-        var1.setFloatValue(mSource, 0);
-        var2.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, 0);
+        var2.setValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.5f);
         Mockito.reset(mTarget);
     }
 
+    @Test
+    public void testDirectMapping() {
+        mScreenMax = 1080;
+        Parallax.FloatProperty var1 = mSource.addProperty("var1");
+
+        mEffect.setPropertyRanges(var1.atAbsolute((float) 540.45), var1.atAbsolute((float) 0.22));
+        Object object = new Object();
+        final float[] properValue = new float[1];
+        Property<Object, Float> property = new Property<Object, Float>(Float.class, "attr") {
+            @Override
+            public void set(Object object, Float value) {
+                properValue[0] = value;
+            }
+
+            @Override
+            public Float get(Object o) {
+                return properValue[0];
+            }
+        };
+        mTarget = new ParallaxTarget.DirectPropertyTarget<>(object, property);
+        mEffect.target(mTarget);
+
+        var1.setValue(mSource, (float) 540.45);
+        mEffect.performMapping(mSource);
+        assertFloatEquals((float) 540.45, properValue[0]);
+
+        var1.setValue(mSource, (float) 405.85);
+        mEffect.performMapping(mSource);
+        assertFloatEquals((float) 405.85, properValue[0]);
+
+        var1.setValue(mSource, 2000);
+        mEffect.performMapping(mSource);
+        assertFloatEquals((float) 540.45, properValue[0]);
+
+        var1.setValue(mSource, (float) 0.22);
+        mEffect.performMapping(mSource);
+        assertFloatEquals((float) 0.22, properValue[0]);
+
+        var1.setValue(mSource, (float) 0.12);
+        mEffect.performMapping(mSource);
+        assertFloatEquals((float) 0.22, properValue[0]);
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
index 23b8b5c..4b45cc2 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
@@ -32,7 +32,7 @@
 @SmallTest
 public class ParallaxFloatTest {
 
-    Parallax.FloatParallax mSource;
+    Parallax<Parallax.FloatProperty> mSource;
     int mScreenMax;
 
     static void assertFloatEquals(float expected, float actual) {
@@ -41,7 +41,7 @@
 
     @Before
     public void setUp() throws Exception {
-        mSource = new Parallax.FloatParallax<Parallax.FloatProperty>() {
+        mSource = new Parallax<Parallax.FloatProperty>() {
 
             @Override
             public float getMaxValue() {
@@ -59,8 +59,8 @@
     public void testVariable() {
         mScreenMax = 1080;
         Parallax.FloatProperty var1 = mSource.addProperty("var1");
-        var1.setFloatValue(mSource, 54);
-        assertFloatEquals((float) 54, var1.getFloatValue(mSource));
+        var1.setValue(mSource, 54);
+        assertFloatEquals((float) 54, var1.getValue(mSource));
         assertEquals(var1.getName(), "var1");
         var1.set(mSource, (float) 2000);
         assertFloatEquals((float) 2000, var1.get(mSource).floatValue());
@@ -71,7 +71,8 @@
         mScreenMax = 1080;
         Parallax.FloatProperty var1 = mSource.addProperty("var1");
 
-        Parallax.FloatPropertyMarkerValue keyValue = var1.atAbsolute(1000);
+        Parallax.FloatPropertyMarkerValue keyValue = (Parallax.FloatPropertyMarkerValue)
+                var1.atAbsolute(1000);
         assertSame(keyValue.getProperty(), var1);
         assertFloatEquals((float) 1000, keyValue.getMarkerValue(mSource));
     }
@@ -81,7 +82,8 @@
         mScreenMax = 1080;
         Parallax.FloatProperty var1 = mSource.addProperty("var1");
 
-        Parallax.FloatPropertyMarkerValue keyValue = var1.at(0, 0.5f);
+        Parallax.FloatPropertyMarkerValue keyValue = (Parallax.FloatPropertyMarkerValue)
+                var1.at(0, 0.5f);
         assertSame(keyValue.getProperty(), var1);
         assertFloatEquals((float) 540, keyValue.getMarkerValue(mSource));
     }
@@ -91,11 +93,13 @@
         mScreenMax = 1080;
         Parallax.FloatProperty var1 = mSource.addProperty("var1");
 
-        Parallax.FloatPropertyMarkerValue keyValue = var1.at(-100, 0.5f);
+        Parallax.FloatPropertyMarkerValue keyValue = (Parallax.FloatPropertyMarkerValue)
+                var1.at(-100, 0.5f);
         assertSame(keyValue.getProperty(), var1);
         assertFloatEquals((float) 440, keyValue.getMarkerValue(mSource));
 
-        Parallax.FloatPropertyMarkerValue keyValue2 = var1.at(100, 0.5f);
+        Parallax.FloatPropertyMarkerValue keyValue2 = (Parallax.FloatPropertyMarkerValue)
+                var1.at(100, 0.5f);
         assertSame(keyValue2.getProperty(), var1);
         assertFloatEquals((float) 640, keyValue2.getMarkerValue(mSource));
     }
@@ -105,10 +109,10 @@
         Parallax.FloatProperty var1 = mSource.addProperty("var1");
         Parallax.FloatProperty var2 = mSource.addProperty("var2");
 
-        var1.setFloatValue(mSource, (float) 500);
-        var2.setFloatValue(mSource, (float) 499);
+        var1.setValue(mSource, (float) 500);
+        var2.setValue(mSource, (float) 499);
 
-        mSource.verifyProperties();
+        mSource.verifyFloatProperties();
     }
 
     @Test(expected = IllegalStateException.class)
@@ -116,10 +120,10 @@
         Parallax.FloatProperty var1 = mSource.addProperty("var1");
         Parallax.FloatProperty var2 = mSource.addProperty("var2");
 
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
-        var2.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
 
-        mSource.verifyProperties();
+        mSource.verifyFloatProperties();
     }
 
     @Test
@@ -127,19 +131,19 @@
         Parallax.FloatProperty var1 = mSource.addProperty("var1");
         Parallax.FloatProperty var2 = mSource.addProperty("var2");
 
-        var1.setFloatValue(mSource, (float) 499);
-        var2.setFloatValue(mSource, (float) 500);
+        var1.setValue(mSource, (float) 499);
+        var2.setValue(mSource, (float) 500);
 
-        mSource.verifyProperties();
+        mSource.verifyFloatProperties();
 
-        var1.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
-        var2.setFloatValue(mSource, (float) 500);
+        var1.setValue(mSource, Parallax.FloatProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, (float) 500);
 
-        mSource.verifyProperties();
+        mSource.verifyFloatProperties();
 
-        var1.setFloatValue(mSource, (float) 499);
-        var2.setFloatValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, (float) 499);
+        var2.setValue(mSource, Parallax.FloatProperty.UNKNOWN_AFTER);
 
-        mSource.verifyProperties();
+        mSource.verifyFloatProperties();
     }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
index 398a0a8..4311fa6 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
@@ -16,11 +16,14 @@
 
 package android.support.v17.leanback.widget;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.Property;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -33,18 +36,22 @@
 @SmallTest
 public class ParallaxIntEffectTest {
 
-    Parallax.IntParallax mSource;
+    Parallax<Parallax.IntProperty> mSource;
     int mScreenMax;
     ParallaxEffect.IntEffect mEffect;
     @Mock ParallaxTarget mTarget;
 
+    static void assertFloatEquals(float expected, float actual) {
+        org.junit.Assert.assertEquals((double) expected, (double) actual, 0.0001d);
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mSource = new Parallax.IntParallax<Parallax.IntProperty>() {
+        mSource = new Parallax<Parallax.IntProperty>() {
 
             @Override
-            public int getMaxValue() {
+            public float getMaxValue() {
                 return mScreenMax;
             }
 
@@ -65,55 +72,55 @@
         mEffect.target(mTarget);
 
         // start
-        var1.setIntValue(mSource, 540);
+        var1.setValue(mSource, 540);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // 25% complete
-        var1.setIntValue(mSource, 405);
+        var1.setValue(mSource, 405);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.25f);
         Mockito.reset(mTarget);
 
         // middle
-        var1.setIntValue(mSource, 270);
+        var1.setValue(mSource, 270);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(.5f);
         Mockito.reset(mTarget);
 
         // 75% complete
-        var1.setIntValue(mSource, 135);
+        var1.setValue(mSource, 135);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.75f);
         Mockito.reset(mTarget);
 
         // end
-        var1.setIntValue(mSource, 0);
+        var1.setValue(mSource, 0);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // after end
-        var1.setIntValue(mSource, -1000);
+        var1.setValue(mSource, -1000);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // before start
-        var1.setIntValue(mSource, 1000);
+        var1.setValue(mSource, 1000);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_before
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_after
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
@@ -126,7 +133,7 @@
 
         mEffect.setPropertyRanges(var1.atAbsolute(540), var1.atAbsolute(550));
         mEffect.target(mTarget);
-        var1.setIntValue(mSource, 0);
+        var1.setValue(mSource, 0);
         mEffect.performMapping(mSource);
     }
 
@@ -140,95 +147,137 @@
         mEffect.target(mTarget);
 
         // start
-        var1.setIntValue(mSource, 540);
-        var2.setIntValue(mSource, 840);
+        var1.setValue(mSource, 540);
+        var2.setValue(mSource, 840);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // middle
-        var1.setIntValue(mSource, 390);
-        var2.setIntValue(mSource, 690);
+        var1.setValue(mSource, 390);
+        var2.setValue(mSource, 690);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(.5f);
         Mockito.reset(mTarget);
 
         // end
-        var1.setIntValue(mSource, 240);
-        var2.setIntValue(mSource, 540);
+        var1.setValue(mSource, 240);
+        var2.setValue(mSource, 540);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // after end
-        var1.setIntValue(mSource, 200);
-        var2.setIntValue(mSource, 500);
+        var1.setValue(mSource, 200);
+        var2.setValue(mSource, 500);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // before start
-        var1.setIntValue(mSource, 1000);
-        var2.setIntValue(mSource, 1300);
+        var1.setValue(mSource, 1000);
+        var2.setValue(mSource, 1300);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_before
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
-        var2.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_before
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
-        var2.setIntValue(mSource, -1000);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, -1000);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_after
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
-        var2.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
+        var2.setValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_after
-        var1.setIntValue(mSource, 1000);
-        var2.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, 1000);
+        var2.setValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0f);
         Mockito.reset(mTarget);
 
         // unknown_before and less
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
-        var2.setIntValue(mSource, 500);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, 500);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_before and hit second
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
-        var2.setIntValue(mSource, 540);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, 540);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(1f);
         Mockito.reset(mTarget);
 
         // unknown_before with estimation
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
-        var2.setIntValue(mSource, 1080);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, 1080);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.5f);
         Mockito.reset(mTarget);
 
         // unknown_after with estimation
-        var1.setIntValue(mSource, 0);
-        var2.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, 0);
+        var2.setValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
         mEffect.performMapping(mSource);
         verify(mTarget, times(1)).update(0.5f);
         Mockito.reset(mTarget);
     }
 
+    @Test
+    public void testDirectMapping() {
+        mScreenMax = 1080;
+        Parallax.IntProperty var1 = mSource.addProperty("var1");
+
+        mEffect.setPropertyRanges(var1.atAbsolute((int) 540.45), var1.atAbsolute((int) 0.22));
+        Object object = new Object();
+        final int[] properValue = new int[1];
+        Property<Object, Integer> property = new Property<Object, Integer>(Integer.class, "attr") {
+            @Override
+            public void set(Object object, Integer value) {
+                properValue[0] = value;
+            }
+
+            @Override
+            public Integer get(Object o) {
+                return properValue[0];
+            }
+        };
+        mTarget = new ParallaxTarget.DirectPropertyTarget<>(object, property);
+        mEffect.target(mTarget);
+
+        var1.setValue(mSource, (int) 540.45);
+        mEffect.performMapping(mSource);
+        assertEquals((int) 540.45, properValue[0]);
+
+        var1.setValue(mSource, (int) 405.85);
+        mEffect.performMapping(mSource);
+        assertEquals((int) 405.85, properValue[0]);
+
+        var1.setValue(mSource, 2000);
+        mEffect.performMapping(mSource);
+        assertEquals((int) 540.45, properValue[0]);
+
+        var1.setValue(mSource, (int) 0.22);
+        mEffect.performMapping(mSource);
+        assertEquals((int) 0.22, properValue[0]);
+
+        var1.setValue(mSource, (int) 0.12);
+        mEffect.performMapping(mSource);
+        assertEquals((int) 0.22, properValue[0]);
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java
index e8269ad..a49acbd 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java
@@ -29,7 +29,7 @@
 @SmallTest
 public class ParallaxIntTest {
 
-    Parallax.IntParallax mSource;
+    Parallax<Parallax.IntProperty> mSource;
     int mScreenMax;
 
     static void assertFloatEquals(float expected, float actual) {
@@ -38,10 +38,10 @@
 
     @Before
     public void setUp() throws Exception {
-        mSource = new Parallax.IntParallax<Parallax.IntProperty>() {
+        mSource = new Parallax<Parallax.IntProperty>() {
 
             @Override
-            public int getMaxValue() {
+            public float getMaxValue() {
                 return mScreenMax;
             }
 
@@ -56,8 +56,8 @@
     public void testVariable() {
         mScreenMax = 1080;
         Parallax.IntProperty var1 = mSource.addProperty("var1");
-        var1.setIntValue(mSource, 54);
-        assertEquals((int) 54, var1.getIntValue(mSource));
+        var1.setValue(mSource, 54);
+        assertEquals((int) 54, var1.getValue(mSource));
         assertEquals(var1.getName(), "var1");
         var1.set(mSource, (int) 2000);
         assertEquals((int) 2000, var1.get(mSource).intValue());
@@ -68,7 +68,8 @@
         mScreenMax = 1080;
         Parallax.IntProperty var1 = mSource.addProperty("var1");
 
-        Parallax.IntPropertyMarkerValue keyValue = var1.atAbsolute(1000);
+        Parallax.IntPropertyMarkerValue keyValue = (Parallax.IntPropertyMarkerValue)
+                var1.atAbsolute(1000);
         assertSame(keyValue.getProperty(), var1);
         assertEquals((int) 1000, keyValue.getMarkerValue(mSource));
     }
@@ -78,7 +79,8 @@
         mScreenMax = 1080;
         Parallax.IntProperty var1 = mSource.addProperty("var1");
 
-        Parallax.IntPropertyMarkerValue keyValue = var1.at(0, 0.5f);
+        Parallax.IntPropertyMarkerValue keyValue = (Parallax.IntPropertyMarkerValue)
+                var1.at(0, 0.5f);
         assertSame(keyValue.getProperty(), var1);
         assertEquals((int) 540, keyValue.getMarkerValue(mSource));
     }
@@ -88,11 +90,13 @@
         mScreenMax = 1080;
         Parallax.IntProperty var1 = mSource.addProperty("var1");
 
-        Parallax.IntPropertyMarkerValue keyValue = var1.at(-100, 0.5f);
+        Parallax.IntPropertyMarkerValue keyValue = (Parallax.IntPropertyMarkerValue)
+                var1.at(-100, 0.5f);
         assertSame(keyValue.getProperty(), var1);
         assertEquals((int) 440, keyValue.getMarkerValue(mSource));
 
-        Parallax.IntPropertyMarkerValue keyValue2 = var1.at(100, 0.5f);
+        Parallax.IntPropertyMarkerValue keyValue2 = (Parallax.IntPropertyMarkerValue)
+                var1.at(100, 0.5f);
         assertSame(keyValue2.getProperty(), var1);
         assertEquals((int) 640, keyValue2.getMarkerValue(mSource));
     }
@@ -102,10 +106,10 @@
         Parallax.IntProperty var1 = mSource.addProperty("var1");
         Parallax.IntProperty var2 = mSource.addProperty("var2");
 
-        var1.setIntValue(mSource, (int) 500);
-        var2.setIntValue(mSource, (int) 499);
+        var1.setValue(mSource, (int) 500);
+        var2.setValue(mSource, (int) 499);
 
-        mSource.verifyProperties();
+        mSource.verifyIntProperties();
     }
 
     @Test(expected = IllegalStateException.class)
@@ -113,10 +117,10 @@
         Parallax.IntProperty var1 = mSource.addProperty("var1");
         Parallax.IntProperty var2 = mSource.addProperty("var2");
 
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
-        var2.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
 
-        mSource.verifyProperties();
+        mSource.verifyIntProperties();
     }
 
     @Test
@@ -124,19 +128,19 @@
         Parallax.IntProperty var1 = mSource.addProperty("var1");
         Parallax.IntProperty var2 = mSource.addProperty("var2");
 
-        var1.setIntValue(mSource, (int) 499);
-        var2.setIntValue(mSource, (int) 500);
+        var1.setValue(mSource, (int) 499);
+        var2.setValue(mSource, (int) 500);
 
-        mSource.verifyProperties();
+        mSource.verifyIntProperties();
 
-        var1.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
-        var2.setIntValue(mSource, (int) 500);
+        var1.setValue(mSource, Parallax.IntProperty.UNKNOWN_BEFORE);
+        var2.setValue(mSource, (int) 500);
 
-        mSource.verifyProperties();
+        mSource.verifyIntProperties();
 
-        var1.setIntValue(mSource, (int) 499);
-        var2.setIntValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
+        var1.setValue(mSource, (int) 499);
+        var2.setValue(mSource, Parallax.IntProperty.UNKNOWN_AFTER);
 
-        mSource.verifyProperties();
+        mSource.verifyIntProperties();
     }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/TitleViewAdapterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/TitleViewAdapterTest.java
new file mode 100644
index 0000000..d038be7
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/TitleViewAdapterTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 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.v17.leanback.widget;
+
+import android.content.Context;
+import android.graphics.drawable.GradientDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TitleViewAdapterTest {
+
+
+    public static class CustomTitle extends LinearLayout implements TitleViewAdapter.Provider {
+
+        final View mSearchOrbView;
+
+        public CustomTitle(Context context, AttributeSet set) {
+            this(context, set, 0);
+        }
+
+        public CustomTitle(Context context, AttributeSet set, int s) {
+            super(context, set, s);
+            mSearchOrbView = new View(context);
+            addView(mSearchOrbView, 10, 10);
+        }
+
+        TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter() {
+            @Override
+            public View getSearchAffordanceView() {
+                return mSearchOrbView;
+            }
+        };
+
+        @Override
+        public TitleViewAdapter getTitleViewAdapter() {
+            return mTitleViewAdapter;
+        }
+    }
+
+    @Test
+    public void customTitle() {
+        CustomTitle t = new CustomTitle(InstrumentationRegistry.getTargetContext(), null);
+        TitleViewAdapter adapter = t.getTitleViewAdapter();
+        adapter.setTitle("title");
+        adapter.setBadgeDrawable(new GradientDrawable());
+        View.OnClickListener listener = Mockito.mock(View.OnClickListener.class);
+        adapter.setOnSearchClickedListener(listener);
+        adapter.getSearchAffordanceView().performClick();
+        Mockito.verify(listener).onClick(Mockito.any(View.class));
+    }
+}
diff --git a/v7/appcompat/res/anim/tooltip_enter.xml b/v7/appcompat/res/anim/tooltip_enter.xml
new file mode 100644
index 0000000..134d9d7
--- /dev/null
+++ b/v7/appcompat/res/anim/tooltip_enter.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+       android:interpolator="@android:interpolator/decelerate_quad"
+       android:fromAlpha="0.0" android:toAlpha="1.0"
+       android:duration="@integer/config_tooltipAnimTime" />
diff --git a/v7/appcompat/res/anim/tooltip_exit.xml b/v7/appcompat/res/anim/tooltip_exit.xml
new file mode 100644
index 0000000..67f6af8
--- /dev/null
+++ b/v7/appcompat/res/anim/tooltip_exit.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+       android:interpolator="@android:interpolator/accelerate_quad"
+       android:fromAlpha="1.0" android:toAlpha="0.0"
+       android:duration="@integer/config_tooltipAnimTime" />
diff --git a/v7/appcompat/res/color-v23/abc_tint_switch_thumb.xml b/v7/appcompat/res/color-v23/abc_tint_switch_thumb.xml
deleted file mode 100644
index f589fdf..0000000
--- a/v7/appcompat/res/color-v23/abc_tint_switch_thumb.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?attr/colorSwitchThumbNormal" android:alpha="?android:attr/disabledAlpha"/>
-    <item android:state_checked="true" android:color="?attr/colorControlActivated"/>
-    <item android:color="?attr/colorSwitchThumbNormal"/>
-</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/color/abc_tint_switch_thumb.xml b/v7/appcompat/res/color/abc_tint_switch_thumb.xml
deleted file mode 100644
index fc8bd24..0000000
--- a/v7/appcompat/res/color/abc_tint_switch_thumb.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item android:state_enabled="false" android:color="?attr/colorSwitchThumbNormal" app:alpha="?android:attr/disabledAlpha"/>
-    <item android:state_checked="true" android:color="?attr/colorControlActivated"/>
-    <item android:color="?attr/colorSwitchThumbNormal"/>
-</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/tooltip_frame_dark.xml b/v7/appcompat/res/drawable/tooltip_frame_dark.xml
new file mode 100644
index 0000000..43c2f99
--- /dev/null
+++ b/v7/appcompat/res/drawable/tooltip_frame_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@color/tooltip_background_dark" />
+    <corners android:radius="@dimen/tooltip_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/tooltip_frame_light.xml b/v7/appcompat/res/drawable/tooltip_frame_light.xml
new file mode 100644
index 0000000..20966d5
--- /dev/null
+++ b/v7/appcompat/res/drawable/tooltip_frame_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@color/tooltip_background_light" />
+    <corners android:radius="@dimen/tooltip_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/tooltip.xml b/v7/appcompat/res/layout/tooltip.xml
new file mode 100644
index 0000000..1421cd4
--- /dev/null
+++ b/v7/appcompat/res/layout/tooltip.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/tooltip_margin"
+        android:paddingLeft="@dimen/tooltip_horizontal_padding"
+        android:paddingStart="@dimen/tooltip_horizontal_padding"
+        android:paddingRight="@dimen/tooltip_horizontal_padding"
+        android:paddingEnd="@dimen/tooltip_horizontal_padding"
+        android:paddingTop="@dimen/tooltip_vertical_padding"
+        android:paddingBottom="@dimen/tooltip_vertical_padding"
+        android:maxWidth="256dp"
+        android:background="?attr/tooltipFrameBackground"
+        android:textAppearance="@style/TextAppearance.AppCompat.Tooltip"
+        android:textColor="?attr/tooltipForegroundColor"
+        android:maxLines="3"
+        android:ellipsize="end"
+    />
+
+</LinearLayout>
diff --git a/v7/appcompat/res/values-v16/styles.xml b/v7/appcompat/res/values-v16/styles.xml
new file mode 100644
index 0000000..1b865d4
--- /dev/null
+++ b/v7/appcompat/res/values-v16/styles.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+
+<resources>
+
+    <style name="TextAppearance.AppCompat.Tooltip">
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index c140a67..dfefd6e 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -392,6 +392,16 @@
 
         <!-- Default menu-style ListView style. -->
         <attr name="listMenuViewStyle" format="reference" />
+
+        <!-- ===================== -->
+        <!-- Tooltip styles -->
+        <!-- ===================== -->
+        <eat-comment />
+
+        <!-- Background to use for tooltips -->
+        <attr name="tooltipFrameBackground" format="reference" />
+        <!-- Foreground color to use for tooltips -->
+        <attr name="tooltipForegroundColor" format="reference|color" />
     </declare-styleable>
 
 
@@ -634,10 +644,32 @@
              with alphabetic keys. -->
         <attr name="android:alphabeticShortcut" />
 
+        <!-- The alphabetic modifier key. This is the modifier when using a keyboard
+            with alphabetic keys. The values should be kept in sync with KeyEvent -->
+        <attr name="alphabeticModifiers">
+            <flag name="META" value="0x10000" />
+            <flag name="CTRL" value="0x1000" />
+            <flag name="ALT" value="0x02" />
+            <flag name="SHIFT" value="0x1" />
+            <flag name="SYM" value="0x4" />
+            <flag name="FUNCTION" value="0x8" />
+        </attr>
+
         <!-- The numeric shortcut key.  This is the shortcut when using a numeric (e.g., 12-key)
              keyboard. -->
         <attr name="android:numericShortcut" />
 
+        <!-- The numeric modifier key. This is the modifier when using a numeric (e.g., 12-key)
+            keyboard. The values should be kept in sync with KeyEvent -->
+        <attr name="numericModifiers">
+            <flag name="META" value="0x10000" />
+            <flag name="CTRL" value="0x1000" />
+            <flag name="ALT" value="0x02" />
+            <flag name="SHIFT" value="0x1" />
+            <flag name="SYM" value="0x4" />
+            <flag name="FUNCTION" value="0x8" />
+        </attr>
+
         <!-- Whether the item is capable of displaying a check mark. -->
         <attr name="android:checkable" />
 
diff --git a/v7/appcompat/res/values/colors.xml b/v7/appcompat/res/values/colors.xml
index 92c91fd..e6bab86 100644
--- a/v7/appcompat/res/values/colors.xml
+++ b/v7/appcompat/res/values/colors.xml
@@ -28,4 +28,8 @@
     <!-- The color of the material notification background for media notifications when no custom
      color is specified -->
     <color name="notification_material_background_media_default_color">#ff424242</color>
+
+    <!-- Tooltip specific colors -->
+    <color name="tooltip_background_dark">#e6616161</color>
+    <color name="tooltip_background_light">#e6FFFFFF</color>
 </resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/config.xml b/v7/appcompat/res/values/config.xml
index 6d986ea..96916a8 100644
--- a/v7/appcompat/res/values/config.xml
+++ b/v7/appcompat/res/values/config.xml
@@ -40,4 +40,7 @@
     <integer name="status_bar_notification_info_maxnum">999</integer>
 
     <integer name="cancel_button_image_alpha">127</integer>
+
+    <!-- The duration (in milliseconds) of the tooltip show/hide animations. -->
+    <integer name="config_tooltipAnimTime">150</integer>
 </resources>
diff --git a/v7/appcompat/res/values/dimens.xml b/v7/appcompat/res/values/dimens.xml
index e055eed..284bdf1 100644
--- a/v7/appcompat/res/values/dimens.xml
+++ b/v7/appcompat/res/values/dimens.xml
@@ -140,4 +140,23 @@
 
     <!-- the paddingtop on the right side of the notification (for time etc.) -->
     <dimen name="notification_right_side_padding_top">2dp</dimen>
+
+    <!-- Tooltip dimensions. -->
+    <!-- Vertical offset from the edge of the anchor view for a touch-triggered tooltip. -->
+    <dimen name="tooltip_y_offset_touch">16dp</dimen>
+    <!-- Vertical offset from the edge of the anchor view for a non-touch-triggered tooltip. -->
+    <dimen name="tooltip_y_offset_non_touch">0dp</dimen>
+    <!-- The tooltip does not get closer than this to the window edge -->
+    <dimen name="tooltip_margin">8dp</dimen>
+    <!-- Left/right padding of the tooltip text. -->
+    <dimen name="tooltip_horizontal_padding">16dp</dimen>
+    <!-- Top/bottom padding of the tooltip text. -->
+    <dimen name="tooltip_vertical_padding">6.5dp</dimen>
+    <!-- Border corner radius of the tooltip window. -->
+    <dimen name="tooltip_corner_radius">2dp</dimen>
+    <!-- View with the height equal or above this threshold will have a tooltip anchored
+    to the mouse/touch position -->
+    <dimen name="tooltip_precise_anchor_threshold">96dp</dimen>
+    <!-- Extra tooltip offset used when anchoring to the mouse/touch position -->
+    <dimen name="tooltip_precise_anchor_extra_offset">8dp</dimen>
 </resources>
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index 7595d74..394b1ec 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -241,6 +241,7 @@
     <eat-comment />
     <style name="Animation.AppCompat.Dialog" parent="Base.Animation.AppCompat.Dialog" />
     <style name="Animation.AppCompat.DropDownUp" parent="Base.Animation.AppCompat.DropDownUp" />
+    <style name="Animation.AppCompat.Tooltip" parent="Base.Animation.AppCompat.Tooltip" />
 
 
     <!-- Text styles -->
@@ -302,6 +303,8 @@
 
     <style name="TextAppearance.AppCompat.Widget.Button.Borderless.Colored" parent="Base.TextAppearance.AppCompat.Widget.Button.Borderless.Colored" />
 
+    <style name="TextAppearance.AppCompat.Tooltip" parent="Base.TextAppearance.AppCompat.Tooltip"/>
+
     <!--
          The following themes are deprecated.
     -->
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index a760b78..ca250d5 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -522,4 +522,9 @@
 
     <style name="Base.AlertDialog.AppCompat.Light" parent="Base.AlertDialog.AppCompat" />
 
+    <style name="Base.Animation.AppCompat.Tooltip" parent="android:Animation">
+        <item name="android:windowEnterAnimation">@anim/tooltip_enter</item>
+        <item name="android:windowExitAnimation">@anim/tooltip_exit</item>
+    </style>
+
 </resources>
diff --git a/v7/appcompat/res/values/styles_base_text.xml b/v7/appcompat/res/values/styles_base_text.xml
index 6a43144..11de1e6 100644
--- a/v7/appcompat/res/values/styles_base_text.xml
+++ b/v7/appcompat/res/values/styles_base_text.xml
@@ -102,6 +102,10 @@
         <item name="android:textColor">?android:textColorPrimaryInverse</item>
     </style>
 
+    <style name="Base.TextAppearance.AppCompat.Tooltip">
+        <item name="android:textSize">14sp</item>
+    </style>
+
     <!-- Deprecated text styles -->
 
     <style name="Base.TextAppearance.AppCompat.Inverse">
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index 92e7bce..2844d2b 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -276,6 +276,10 @@
         <item name="windowFixedWidthMinor">@null</item>
         <item name="windowFixedHeightMajor">@null</item>
         <item name="windowFixedHeightMinor">@null</item>
+
+        <!-- Tooltip attributes -->
+        <item name="tooltipFrameBackground">@drawable/tooltip_frame_light</item>
+        <item name="tooltipForegroundColor">@color/foreground_material_light</item>
     </style>
 
     <!-- Base platform-dependent theme providing an action bar in a light-themed activity. -->
@@ -437,6 +441,10 @@
         <item name="windowFixedWidthMinor">@null</item>
         <item name="windowFixedHeightMajor">@null</item>
         <item name="windowFixedHeightMinor">@null</item>
+
+        <!-- Tooltip attributes -->
+        <item name="tooltipFrameBackground">@drawable/tooltip_frame_dark</item>
+        <item name="tooltipForegroundColor">@color/foreground_material_dark</item>
     </style>
 
     <style name="Base.Theme.AppCompat" parent="Base.V7.Theme.AppCompat">
diff --git a/v7/appcompat/src/android/support/v7/app/AlertController.java b/v7/appcompat/src/android/support/v7/app/AlertController.java
index ee7ea8e..d0f8fd6 100644
--- a/v7/appcompat/src/android/support/v7/app/AlertController.java
+++ b/v7/appcompat/src/android/support/v7/app/AlertController.java
@@ -16,6 +16,8 @@
 
 package android.support.v7.app;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
@@ -28,6 +30,7 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.NestedScrollView;
 import android.support.v7.appcompat.R;
+import android.support.v7.widget.LinearLayoutCompat;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -58,8 +61,6 @@
 
 import java.lang.ref.WeakReference;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
 class AlertController {
     private final Context mContext;
     final AppCompatDialog mDialog;
@@ -652,7 +653,7 @@
             }
 
             if (mListView != null) {
-                ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
+                ((LinearLayoutCompat.LayoutParams) customPanel.getLayoutParams()).weight = 0;
             }
         } else {
             customPanel.setVisibility(View.GONE);
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
index e4d951c..6c0f125 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
@@ -40,6 +40,7 @@
 import android.view.MenuInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.Window;
 
 /**
  * Base class for activities that use the
@@ -547,4 +548,32 @@
         }
         return mResources == null ? super.getResources() : mResources;
     }
+
+    /**
+     * KeyEvents with non-default modifiers are not dispatched to menu's performShortcut in API 24
+     * or lower. Here, we check if the keypress corresponds to a menuitem's shortcut combination
+     * and perform the corresponding action.
+     */
+    private boolean performMenuItemShortcut(int keycode, KeyEvent event) {
+        if (!KeyEvent.metaStateHasNoModifiers(event.getMetaState())
+                && event.getRepeatCount() == 0
+                && !KeyEvent.isModifierKey(event.getKeyCode())) {
+            final Window currentWindow = getWindow();
+            if (currentWindow != null && currentWindow.getDecorView() != null) {
+                final View decorView = currentWindow.getDecorView();
+                if (decorView.dispatchKeyShortcutEvent(event)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (performMenuItemShortcut(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
index 39ff508..c412d59 100644
--- a/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
@@ -51,6 +51,8 @@
 import android.support.v7.widget.Toolbar;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -1401,4 +1403,19 @@
             setDisplayHomeAsUpEnabled(enable);
         }
     }
+
+    @Override
+    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+        if (mActionMode == null) {
+            return false;
+        }
+        Menu menu = mActionMode.getMenu();
+        if (menu != null) {
+            final KeyCharacterMap kmap = KeyCharacterMap.load(
+                    event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
+            menu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC);
+            return menu.performShortcut(keyCode, event, 0);
+        }
+        return false;
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
index 3ab5f81..fa7fe1b 100644
--- a/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
@@ -19,7 +19,6 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.content.Context;
-import android.os.Build;
 import android.support.annotation.RestrictTo;
 import android.support.v4.internal.view.SupportMenu;
 import android.support.v4.internal.view.SupportMenuItem;
diff --git a/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
index 60f0f9e..003c986 100644
--- a/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
@@ -34,6 +34,7 @@
 import android.util.Log;
 import android.util.Xml;
 import android.view.InflateException;
+import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -293,7 +294,9 @@
         private CharSequence itemTitleCondensed;
         private int itemIconResId;
         private char itemAlphabeticShortcut;
+        private int itemAlphabeticModifiers;
         private char itemNumericShortcut;
+        private int itemNumericModifiers;
         /**
          * Sync to attrs.xml enum:
          * - 0: none
@@ -384,8 +387,12 @@
             itemIconResId = a.getResourceId(R.styleable.MenuItem_android_icon, 0);
             itemAlphabeticShortcut =
                     getShortcut(a.getString(R.styleable.MenuItem_android_alphabeticShortcut));
+            itemAlphabeticModifiers =
+                    a.getInt(R.styleable.MenuItem_alphabeticModifiers, KeyEvent.META_CTRL_ON);
             itemNumericShortcut =
                     getShortcut(a.getString(R.styleable.MenuItem_android_numericShortcut));
+            itemNumericModifiers =
+                    a.getInt(R.styleable.MenuItem_numericModifiers, KeyEvent.META_CTRL_ON);
             if (a.hasValue(R.styleable.MenuItem_android_checkable)) {
                 // Item has attribute checkable, use it
                 itemCheckable = a.getBoolean(R.styleable.MenuItem_android_checkable, false) ? 1 : 0;
@@ -438,9 +445,7 @@
                     .setEnabled(itemEnabled)
                     .setCheckable(itemCheckable >= 1)
                     .setTitleCondensed(itemTitleCondensed)
-                    .setIcon(itemIconResId)
-                    .setAlphabeticShortcut(itemAlphabeticShortcut)
-                    .setNumericShortcut(itemNumericShortcut);
+                    .setIcon(itemIconResId);
 
             if (itemShowAsAction >= 0) {
                 item.setShowAsAction(itemShowAsAction);
@@ -486,6 +491,9 @@
 
             MenuItemCompat.setContentDescription(item, itemContentDescription);
             MenuItemCompat.setTooltipText(item, itemTooltipText);
+            MenuItemCompat.setAlphabeticShortcut(item, itemAlphabeticShortcut,
+                    itemAlphabeticModifiers);
+            MenuItemCompat.setNumericShortcut(item, itemNumericShortcut, itemNumericModifiers);
         }
 
         public void addItem() {
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
index b3278a4..d190df3 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
@@ -26,6 +26,7 @@
 import android.support.v4.internal.view.SupportMenuItem;
 import android.support.v4.view.ActionProvider;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
@@ -45,7 +46,9 @@
     private CharSequence mTitleCondensed;
     private Intent mIntent;
     private char mShortcutNumericChar;
+    private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON;
     private char mShortcutAlphabeticChar;
+    private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON;
 
     private Drawable mIconDrawable;
     private int mIconResId = NO_ICON;
@@ -82,6 +85,11 @@
     }
 
     @Override
+    public int getAlphabeticModifiers() {
+        return mShortcutAlphabeticModifiers;
+    }
+
+    @Override
     public int getGroupId() {
         return mGroup;
     }
@@ -112,6 +120,11 @@
     }
 
     @Override
+    public int getNumericModifiers() {
+        return mShortcutNumericModifiers;
+    }
+
+    @Override
     public int getOrder() {
         return mOrdering;
     }
@@ -158,7 +171,14 @@
 
     @Override
     public MenuItem setAlphabeticShortcut(char alphaChar) {
-        mShortcutAlphabeticChar = alphaChar;
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        return this;
+    }
+
+    @Override
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
         return this;
     }
 
@@ -212,6 +232,13 @@
     }
 
     @Override
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        return this;
+    }
+
+    @Override
     public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
         mClickListener = menuItemClickListener;
         return this;
@@ -220,7 +247,17 @@
     @Override
     public MenuItem setShortcut(char numericChar, char alphaChar) {
         mShortcutNumericChar = numericChar;
-        mShortcutAlphabeticChar = alphaChar;
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        return this;
+    }
+
+    @Override
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
         return this;
     }
 
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
index 989e609..259ae07 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
@@ -25,11 +25,11 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
 import android.support.annotation.RestrictTo;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.widget.ActionMenuView;
 import android.support.v7.widget.AppCompatTextView;
 import android.support.v7.widget.ForwardingListener;
+import android.support.v7.widget.TooltipCompat;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -202,9 +202,9 @@
         final CharSequence tooltipText = mItemData.getTooltipText();
         if (TextUtils.isEmpty(tooltipText)) {
             // Use the uncondensed title for tooltip, but only if the title is not shown already.
-            ViewCompat.setTooltipText(this, visible ? null : mItemData.getTitle());
+            TooltipCompat.setTooltipText(this, visible ? null : mItemData.getTitle());
         } else {
-            ViewCompat.setTooltipText(this, tooltipText);
+            TooltipCompat.setTooltipText(this, tooltipText);
         }
     }
 
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
index 3adfd87..e6dee8d 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
@@ -868,7 +868,7 @@
     @SuppressWarnings("deprecation")
     void findItemsWithShortcutForKey(List<MenuItemImpl> items, int keyCode, KeyEvent event) {
         final boolean qwerty = isQwertyMode();
-        final int metaState = event.getMetaState();
+        final int modifierState = event.getModifiers();
         final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
         // Get the chars associated with the keyCode (i.e using any chording combo)
         final boolean isKeyCodeMapped = event.getKeyData(possibleChars);
@@ -884,14 +884,18 @@
             if (item.hasSubMenu()) {
                 ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event);
             }
-            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
-            if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) &&
-                  (shortcutChar != 0) &&
-                  (shortcutChar == possibleChars.meta[0]
-                      || shortcutChar == possibleChars.meta[2]
-                      || (qwerty && shortcutChar == '\b' &&
-                          keyCode == KeyEvent.KEYCODE_DEL)) &&
-                  item.isEnabled()) {
+            final char shortcutChar =
+                    qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
+            final int shortcutModifiers =
+                    qwerty ? item.getAlphabeticModifiers() : item.getNumericModifiers();
+            final boolean isModifiersExactMatch = (modifierState & SUPPORTED_MODIFIERS_MASK)
+                    == (shortcutModifiers & SUPPORTED_MODIFIERS_MASK);
+            if (isModifiersExactMatch && (shortcutChar != 0)
+                    && (shortcutChar == possibleChars.meta[0]
+                            || shortcutChar == possibleChars.meta[2]
+                            || (qwerty && shortcutChar == '\b'
+                                && keyCode == KeyEvent.KEYCODE_DEL))
+                    && item.isEnabled()) {
                 items.add(item);
             }
         }
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
index 510034a..a476d05 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
@@ -29,6 +29,7 @@
 import android.support.v7.content.res.AppCompatResources;
 import android.util.Log;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
@@ -56,7 +57,9 @@
     private CharSequence mTitleCondensed;
     private Intent mIntent;
     private char mShortcutNumericChar;
+    private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON;
     private char mShortcutAlphabeticChar;
+    private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON;
 
     /** The icon's drawable which is only created as needed */
     private Drawable mIconDrawable;
@@ -257,11 +260,35 @@
     }
 
     @Override
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+        if (mShortcutAlphabeticChar == alphaChar
+                && mShortcutAlphabeticModifiers == alphaModifiers) {
+            return this;
+        }
+
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+
+        mMenu.onItemsChanged(false);
+        return this;
+    }
+
+    @Override
+    public int getAlphabeticModifiers() {
+        return mShortcutAlphabeticModifiers;
+    }
+
+    @Override
     public char getNumericShortcut() {
         return mShortcutNumericChar;
     }
 
     @Override
+    public int getNumericModifiers() {
+        return mShortcutNumericModifiers;
+    }
+
+    @Override
     public MenuItem setNumericShortcut(char numericChar) {
         if (mShortcutNumericChar == numericChar) {
             return this;
@@ -275,6 +302,20 @@
     }
 
     @Override
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        if (mShortcutNumericChar == numericChar && mShortcutNumericModifiers == numericModifiers) {
+            return this;
+        }
+
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    @Override
     public MenuItem setShortcut(char numericChar, char alphaChar) {
         mShortcutNumericChar = numericChar;
         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
@@ -284,6 +325,19 @@
         return this;
     }
 
+    @Override
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
     /**
      * @return The active shortcut (based on QWERTY-mode of the menu).
      */
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
index 386c43a..7f1266e 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
@@ -129,28 +129,57 @@
     }
 
     @Override
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        mWrappedObject.setShortcut(numericChar, alphaChar, numericModifiers, alphaModifiers);
+        return this;
+    }
+
+    @Override
     public MenuItem setNumericShortcut(char numericChar) {
         mWrappedObject.setNumericShortcut(numericChar);
         return this;
     }
 
     @Override
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        mWrappedObject.setNumericShortcut(numericChar, numericModifiers);
+        return this;
+    }
+
+    @Override
     public char getNumericShortcut() {
         return mWrappedObject.getNumericShortcut();
     }
 
     @Override
+    public int getNumericModifiers() {
+        return mWrappedObject.getNumericModifiers();
+    }
+
+    @Override
     public MenuItem setAlphabeticShortcut(char alphaChar) {
         mWrappedObject.setAlphabeticShortcut(alphaChar);
         return this;
     }
 
     @Override
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+        mWrappedObject.setAlphabeticShortcut(alphaChar, alphaModifiers);
+        return this;
+    }
+
+    @Override
     public char getAlphabeticShortcut() {
         return mWrappedObject.getAlphabeticShortcut();
     }
 
     @Override
+    public int getAlphabeticModifiers() {
+        return mWrappedObject.getAlphabeticModifiers();
+    }
+
+    @Override
     public MenuItem setCheckable(boolean checkable) {
         mWrappedObject.setCheckable(checkable);
         return this;
diff --git a/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java b/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java
index 2ab1a0c..bcb589b 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java
@@ -25,7 +25,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnKeyListener;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
index 888d33b..030c3db 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
@@ -27,7 +27,6 @@
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.view.ActionProvider;
 import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.transition.ActionBarTransition;
 import android.support.v7.view.ActionBarPolicy;
@@ -652,7 +651,7 @@
             setVisibility(VISIBLE);
             setEnabled(true);
 
-            ViewCompat.setTooltipText(this, getContentDescription());
+            TooltipCompat.setTooltipText(this, getContentDescription());
 
             setOnTouchListener(new ForwardingListener(this) {
                 @Override
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index 70e241d..34e2f4e 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -532,7 +532,7 @@
             } else if (resId == R.drawable.abc_switch_track_mtrl_alpha) {
                 tint = getColorStateList(context, R.color.abc_tint_switch_track);
             } else if (resId == R.drawable.abc_switch_thumb_material) {
-                tint = getColorStateList(context, R.color.abc_tint_switch_thumb);
+                tint = createSwitchThumbColorStateList(context);
             } else if (resId == R.drawable.abc_btn_default_mtrl_shape) {
                 tint = createDefaultButtonColorStateList(context);
             } else if (resId == R.drawable.abc_btn_borderless_material) {
@@ -625,6 +625,52 @@
         return new ColorStateList(states, colors);
     }
 
+    private ColorStateList createSwitchThumbColorStateList(Context context) {
+        final int[][] states = new int[3][];
+        final int[] colors = new int[3];
+        int i = 0;
+
+        final ColorStateList thumbColor = getThemeAttrColorStateList(context,
+                R.attr.colorSwitchThumbNormal);
+
+        if (thumbColor != null && thumbColor.isStateful()) {
+            // If colorSwitchThumbNormal is a valid ColorStateList, extract the default and
+            // disabled colors from it
+
+            // Disabled state
+            states[i] = ThemeUtils.DISABLED_STATE_SET;
+            colors[i] = thumbColor.getColorForState(states[i], 0);
+            i++;
+
+            states[i] = ThemeUtils.CHECKED_STATE_SET;
+            colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated);
+            i++;
+
+            // Default enabled state
+            states[i] = ThemeUtils.EMPTY_STATE_SET;
+            colors[i] = thumbColor.getDefaultColor();
+            i++;
+        } else {
+            // Else we'll use an approximation using the default disabled alpha
+
+            // Disabled state
+            states[i] = ThemeUtils.DISABLED_STATE_SET;
+            colors[i] = getDisabledThemeAttrColor(context, R.attr.colorSwitchThumbNormal);
+            i++;
+
+            states[i] = ThemeUtils.CHECKED_STATE_SET;
+            colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated);
+            i++;
+
+            // Default enabled state
+            states[i] = ThemeUtils.EMPTY_STATE_SET;
+            colors[i] = getThemeAttrColor(context, R.attr.colorSwitchThumbNormal);
+            i++;
+        }
+
+        return new ColorStateList(states, colors);
+    }
+
     private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> {
 
         public ColorFilterLruCache(int maxSize) {
diff --git a/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
index a8b4257..7512631 100644
--- a/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
@@ -25,7 +25,6 @@
 import android.os.Build;
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.app.ActionBar;
 import android.support.v7.appcompat.R;
 import android.support.v7.view.ActionBarPolicy;
@@ -511,7 +510,7 @@
                 if (mIconView != null) {
                     mIconView.setContentDescription(tab.getContentDescription());
                 }
-                ViewCompat.setTooltipText(this, hasText ? null : tab.getContentDescription());
+                TooltipCompat.setTooltipText(this, hasText ? null : tab.getContentDescription());
             }
         }
 
diff --git a/v7/appcompat/src/android/support/v7/widget/SearchView.java b/v7/appcompat/src/android/support/v7/widget/SearchView.java
index 2dac3d9..0af462f 100644
--- a/v7/appcompat/src/android/support/v7/widget/SearchView.java
+++ b/v7/appcompat/src/android/support/v7/widget/SearchView.java
@@ -323,7 +323,7 @@
 
         mSearchHintIcon = a.getDrawable(R.styleable.SearchView_searchHintIcon);
 
-        ViewCompat.setTooltipText(mSearchButton,
+        TooltipCompat.setTooltipText(mSearchButton,
                 getResources().getString(R.string.abc_searchview_description_search));
 
         // Extract dropdown layout resource IDs for later use.
diff --git a/v7/appcompat/src/android/support/v7/widget/TooltipCompat.java b/v7/appcompat/src/android/support/v7/widget/TooltipCompat.java
new file mode 100644
index 0000000..f7466bc
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/TooltipCompat.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.v7.widget;
+
+import android.annotation.TargetApi;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+import android.view.View;
+
+/**
+ * Helper class used to emulate the behavior of {@link View#setTooltipText(CharSequence)} prior
+ * to API level 26.
+ *
+ */
+public class TooltipCompat  {
+    private interface ViewCompatImpl {
+        void setTooltipText(@NonNull View view, @Nullable CharSequence tooltipText);
+    }
+
+    private static class BaseViewCompatImpl implements ViewCompatImpl {
+        @Override
+        public void setTooltipText(@NonNull View view, @Nullable CharSequence tooltipText) {
+            TooltipCompatHandler.setTooltipText(view, tooltipText);
+        }
+    }
+
+    @TargetApi(26)
+    private static class Api26ViewCompatImpl implements ViewCompatImpl {
+        @Override
+        public void setTooltipText(@NonNull View view, @Nullable CharSequence tooltipText) {
+            view.setTooltipText(tooltipText);
+        }
+    }
+
+    private static final ViewCompatImpl IMPL;
+    static {
+        if (BuildCompat.isAtLeastO()) {
+            IMPL = new Api26ViewCompatImpl();
+        } else {
+            IMPL = new BaseViewCompatImpl();
+        }
+    }
+
+    /**
+     * Sets the tooltip text for the view.
+     * <p> Prior to API 26 this method sets or clears (when tooltip is null) the view's
+     * OnLongClickListener and OnHoverListener. A toast-like subpanel will be created on long click
+     * or mouse hover.
+     *
+     * @param view the view to set the tooltip text on
+     * @param tooltipText the tooltip text
+     */
+    public static void setTooltipText(@NonNull View view, @Nullable CharSequence tooltipText) {
+        IMPL.setTooltipText(view, tooltipText);
+    }
+
+    private TooltipCompat() {}
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/TooltipCompatHandler.java b/v7/appcompat/src/android/support/v7/widget/TooltipCompatHandler.java
new file mode 100644
index 0000000..4670534
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/TooltipCompatHandler.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2017 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.v7.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
+
+import android.content.Context;
+import android.support.annotation.RestrictTo;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityManagerCompat;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityManager;
+
+/**
+ * Event handler used used to emulate the behavior of {@link View#setTooltipText(CharSequence)}
+ * prior to API level 26.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+class TooltipCompatHandler implements View.OnLongClickListener, View.OnHoverListener,
+        View.OnAttachStateChangeListener {
+    private static final String TAG = "TooltipCompatHandler";
+
+    private static final long LONG_CLICK_HIDE_TIMEOUT_MS = 2500;
+    private static final long HOVER_HIDE_TIMEOUT_MS = 15000;
+    private static final long HOVER_HIDE_TIMEOUT_SHORT_MS = 3000;
+
+    private final View mAnchor;
+    private final CharSequence mTooltipText;
+
+    private final Runnable mShowRunnable = new Runnable() {
+        @Override
+        public void run() {
+            show(false /* not from touch*/);
+        }
+    };
+    private final Runnable mHideRunnable = new Runnable() {
+        @Override
+        public void run() {
+            hide();
+        }
+    };
+
+    private int mAnchorX;
+    private int mAnchorY;
+
+    private TooltipPopup mPopup;
+    private boolean mFromTouch;
+
+    // The handler currently showing a tooltip (there can be only one).
+    private static TooltipCompatHandler sActiveHandler;
+
+    /**
+     * Set the tooltip text for the view.
+     *
+     * @param view        view to set the tooltip on
+     * @param tooltipText the tooltip text
+     */
+    public static void setTooltipText(View view, CharSequence tooltipText) {
+        if (TextUtils.isEmpty(tooltipText)) {
+            if (sActiveHandler != null && sActiveHandler.mAnchor == view) {
+                sActiveHandler.hide();
+            }
+            view.setOnLongClickListener(null);
+            view.setLongClickable(false);
+            view.setOnHoverListener(null);
+        } else {
+            if (sActiveHandler != null && sActiveHandler.mAnchor == view) {
+                sActiveHandler.update(tooltipText);
+            } else {
+                new TooltipCompatHandler(view, tooltipText);
+            }
+        }
+    }
+
+    private TooltipCompatHandler(View anchor, CharSequence tooltipText) {
+        mAnchor = anchor;
+        mTooltipText = tooltipText;
+
+        mAnchor.setOnLongClickListener(this);
+        mAnchor.setOnHoverListener(this);
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        mAnchorX = v.getWidth() / 2;
+        mAnchorY = v.getHeight() / 2;
+        show(true /* from touch */);
+        return true;
+    }
+
+    @Override
+    public boolean onHover(View v, MotionEvent event) {
+        if (mPopup != null && mFromTouch) {
+            return false;
+        }
+        AccessibilityManager manager = (AccessibilityManager)
+                mAnchor.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (manager.isEnabled()
+                && AccessibilityManagerCompat.isTouchExplorationEnabled(manager)) {
+            return false;
+        }
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_HOVER_MOVE:
+                if (mAnchor.isEnabled() && mPopup == null) {
+                    mAnchorX = (int) event.getX();
+                    mAnchorY = (int) event.getY();
+                    mAnchor.removeCallbacks(mShowRunnable);
+                    mAnchor.postDelayed(mShowRunnable, ViewConfiguration.getLongPressTimeout());
+                }
+                break;
+            case MotionEvent.ACTION_HOVER_EXIT:
+                hide();
+                break;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View v) {
+        // no-op.
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        hide();
+    }
+
+    private void show(boolean fromTouch) {
+        if (!ViewCompat.isAttachedToWindow(mAnchor)) {
+            return;
+        }
+        if (sActiveHandler != null) {
+            sActiveHandler.hide();
+        }
+        sActiveHandler = this;
+
+        mFromTouch = fromTouch;
+        mPopup = new TooltipPopup(mAnchor.getContext());
+        mPopup.show(mAnchor, mAnchorX, mAnchorY, mFromTouch, mTooltipText);
+        // Only listen for attach state change while the popup is being shown.
+        mAnchor.addOnAttachStateChangeListener(this);
+
+        final long timeout;
+        if (mFromTouch) {
+            timeout = LONG_CLICK_HIDE_TIMEOUT_MS;
+        } else if ((ViewCompat.getWindowSystemUiVisibility(mAnchor)
+                & SYSTEM_UI_FLAG_LOW_PROFILE) == SYSTEM_UI_FLAG_LOW_PROFILE) {
+            timeout = HOVER_HIDE_TIMEOUT_SHORT_MS - ViewConfiguration.getLongPressTimeout();
+        } else {
+            timeout = HOVER_HIDE_TIMEOUT_MS - ViewConfiguration.getLongPressTimeout();
+        }
+        mAnchor.removeCallbacks(mHideRunnable);
+        mAnchor.postDelayed(mHideRunnable, timeout);
+    }
+
+    private void hide() {
+        if (sActiveHandler == this) {
+            sActiveHandler = null;
+            if (mPopup != null) {
+                mPopup.hide();
+                mPopup = null;
+                mAnchor.removeOnAttachStateChangeListener(this);
+            } else {
+                Log.e(TAG, "sActiveHandler.mPopup == null");
+            }
+        }
+        mAnchor.removeCallbacks(mShowRunnable);
+        mAnchor.removeCallbacks(mHideRunnable);
+    }
+
+    private void update(CharSequence tooltipText) {
+        mPopup.updateContent(tooltipText);
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/TooltipPopup.java b/v7/appcompat/src/android/support/v7/widget/TooltipPopup.java
new file mode 100644
index 0000000..26bd9df
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/TooltipPopup.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2017 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.v7.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.support.annotation.RestrictTo;
+import android.support.v7.appcompat.R;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+/**
+ * A popup window displaying a text message aligned to a specified view.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+class TooltipPopup {
+    private static final String TAG = "TooltipPopup";
+
+    private final Context mContext;
+
+    private final View mContentView;
+    private final TextView mMessageView;
+
+    private final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
+    private final Rect mTmpDisplayFrame = new Rect();
+    private final int[] mTmpAnchorPos = new int[2];
+    private final int[] mTmpAppPos = new int[2];
+
+    TooltipPopup(Context context) {
+        mContext = context;
+
+        mContentView = LayoutInflater.from(mContext).inflate(R.layout.tooltip, null);
+        mMessageView = (TextView) mContentView.findViewById(R.id.message);
+
+        mLayoutParams.setTitle(getClass().getSimpleName());
+        mLayoutParams.packageName = mContext.getPackageName();
+        mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
+        mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        mLayoutParams.format = PixelFormat.TRANSLUCENT;
+        mLayoutParams.windowAnimations = R.style.Animation_AppCompat_Tooltip;
+        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+    }
+
+    void show(View anchorView, int anchorX, int anchorY, boolean fromTouch,
+            CharSequence tooltipText) {
+        if (isShowing()) {
+            hide();
+        }
+
+        mMessageView.setText(tooltipText);
+
+        computePosition(anchorView, anchorX, anchorY, fromTouch, mLayoutParams);
+
+        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        wm.addView(mContentView, mLayoutParams);
+    }
+
+    void hide() {
+        if (!isShowing()) {
+            return;
+        }
+
+        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        wm.removeView(mContentView);
+    }
+
+    boolean isShowing() {
+        return mContentView.getParent() != null;
+    }
+
+    void updateContent(CharSequence tooltipText) {
+        mMessageView.setText(tooltipText);
+    }
+
+    private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch,
+            WindowManager.LayoutParams outParams) {
+        final int tooltipPreciseAnchorThreshold = mContext.getResources().getDimensionPixelOffset(
+                R.dimen.tooltip_precise_anchor_threshold);
+
+        final int offsetX;
+        if (anchorView.getWidth() >= tooltipPreciseAnchorThreshold) {
+            // Wide view. Align the tooltip horizontally to the precise X position.
+            offsetX = anchorX;
+        } else {
+            // Otherwise anchor the tooltip to the view center.
+            offsetX = anchorView.getWidth() / 2;  // Center on the view horizontally.
+        }
+
+        final int offsetBelow;
+        final int offsetAbove;
+        if (anchorView.getHeight() >= tooltipPreciseAnchorThreshold) {
+            // Tall view. Align the tooltip vertically to the precise Y position.
+            final int offsetExtra = mContext.getResources().getDimensionPixelOffset(
+                    R.dimen.tooltip_precise_anchor_extra_offset);
+            offsetBelow = anchorY + offsetExtra;
+            offsetAbove = anchorY - offsetExtra;
+        } else {
+            // Otherwise anchor the tooltip to the view center.
+            offsetBelow = anchorView.getHeight();  // Place below the view in most cases.
+            offsetAbove = 0;  // Place above the view if the tooltip does not fit below.
+        }
+
+        outParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+
+        final int tooltipOffset = mContext.getResources().getDimensionPixelOffset(
+                fromTouch ? R.dimen.tooltip_y_offset_touch : R.dimen.tooltip_y_offset_non_touch);
+
+        final View appView = getAppRootView(anchorView);
+        if (appView == null) {
+            Log.e(TAG, "Cannot find app view");
+            return;
+        }
+        appView.getWindowVisibleDisplayFrame(mTmpDisplayFrame);
+        if (mTmpDisplayFrame.left < 0 && mTmpDisplayFrame.top < 0) {
+            // No meaningful display frame, the anchor view is probably in a subpanel
+            // (such as a popup window). Use the screen frame as a reasonable approximation.
+            final Resources res = mContext.getResources();
+            final int statusBarHeight;
+            int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
+            if (resourceId > 0) {
+                statusBarHeight = res.getDimensionPixelSize(resourceId);
+            } else {
+                statusBarHeight = 0;
+            }
+            final DisplayMetrics metrics = res.getDisplayMetrics();
+            mTmpDisplayFrame.set(0, statusBarHeight, metrics.widthPixels, metrics.heightPixels);
+        }
+        appView.getLocationOnScreen(mTmpAppPos);
+
+        anchorView.getLocationOnScreen(mTmpAnchorPos);
+        mTmpAnchorPos[0] -= mTmpAppPos[0];
+        mTmpAnchorPos[1] -= mTmpAppPos[1];
+        // mTmpAnchorPos is now relative to the main app window.
+
+        outParams.x = mTmpAnchorPos[0] + offsetX - mTmpDisplayFrame.width() / 2;
+
+        final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+        mContentView.measure(spec, spec);
+        final int tooltipHeight = mContentView.getMeasuredHeight();
+
+        final int yAbove = mTmpAnchorPos[1] + offsetAbove - tooltipOffset - tooltipHeight;
+        final int yBelow = mTmpAnchorPos[1] + offsetBelow + tooltipOffset;
+        if (fromTouch) {
+            if (yAbove >= 0) {
+                outParams.y = yAbove;
+            } else {
+                outParams.y = yBelow;
+            }
+        } else {
+            if (yBelow + tooltipHeight <= mTmpDisplayFrame.height()) {
+                outParams.y = yBelow;
+            } else {
+                outParams.y = yAbove;
+            }
+        }
+    }
+
+    private static View getAppRootView(View anchorView) {
+        Context context = anchorView.getContext();
+        while (context instanceof ContextWrapper) {
+            if (context instanceof Activity) {
+                return ((Activity) context).getWindow().getDecorView();
+            } else {
+                context = ((ContextWrapper) context).getBaseContext();
+            }
+        }
+        return anchorView.getRootView();
+    }
+}
diff --git a/v7/appcompat/tests/AndroidManifest.xml b/v7/appcompat/tests/AndroidManifest.xml
index 00febff..0401a19 100644
--- a/v7/appcompat/tests/AndroidManifest.xml
+++ b/v7/appcompat/tests/AndroidManifest.xml
@@ -30,6 +30,8 @@
         <activity
                 android:name="android.support.v7.app.AppCompatActivity"/>
 
+        <activity android:name="android.support.v7.app.AppCompatMenuItemShortcutsTestActivity"/>
+
         <activity
                 android:name="android.support.v7.app.WindowDecorAppCompatActivity"/>
         <activity
@@ -56,6 +58,8 @@
                 android:label="@string/alert_dialog_activity"
                 android:theme="@style/Theme.AppCompat.Light" />
 
+        <activity android:name="android.support.v7.view.SupportMenuInflaterTestActivity" />
+
         <activity
                 android:name="android.support.v7.widget.PopupTestActivity"
                 android:label="@string/popup_activity"
diff --git a/v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml b/v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml
new file mode 100644
index 0000000..95cdece
--- /dev/null
+++ b/v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item android:id="@+id/no_modifiers"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="a" />
+
+    <item android:id="@+id/default_modifiers"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="b"
+          app:alphabeticModifiers="CTRL" />
+
+    <item android:id="@+id/single_modifier"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="c"
+          app:alphabeticModifiers="SHIFT" />
+
+    <item android:id="@+id/multiple_modifiers"
+          android:onClick="handleMenuItem"
+          android:alphabeticShortcut="d"
+          app:alphabeticModifiers="CTRL|SHIFT" />
+
+</menu>
diff --git a/v7/appcompat/tests/res/menu/shortcut.xml b/v7/appcompat/tests/res/menu/shortcut.xml
new file mode 100644
index 0000000..b22c06c
--- /dev/null
+++ b/v7/appcompat/tests/res/menu/shortcut.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item android:id="@+id/no_modifiers"
+          android:alphabeticShortcut="a"
+          android:numericShortcut="1" />
+
+    <item android:id="@+id/default_modifiers"
+          android:alphabeticShortcut="b"
+          android:numericShortcut="2"
+          app:alphabeticModifiers="CTRL"
+          app:numericModifiers="CTRL" />
+
+    <item android:id="@+id/single_modifier"
+          android:alphabeticShortcut="c"
+          android:numericShortcut="3"
+          app:alphabeticModifiers="SHIFT"
+          app:numericModifiers="SHIFT" />
+
+    <item android:id="@+id/multiple_modifiers"
+          android:alphabeticShortcut="d"
+          android:numericShortcut="4"
+          app:alphabeticModifiers="CTRL|SHIFT"
+          app:numericModifiers="CTRL|SHIFT" />
+
+</menu>
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java
new file mode 100644
index 0000000..6d4830a
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 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.v7.app;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.appcompat.test.R;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test shortcut trigger in case of MenuItems with non-default modifiers.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppCompatMenuItemShortcutsTest {
+
+    private AppCompatMenuItemShortcutsTestActivity mActivity;
+    private MenuInflater mMenuInflater;
+    private Menu mMenu;
+
+    @Rule
+    public ActivityTestRule<AppCompatMenuItemShortcutsTestActivity> mActivityTestRule =
+            new ActivityTestRule<>(AppCompatMenuItemShortcutsTestActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityTestRule.getActivity();
+    }
+
+    @Test
+    public void testPerformShortcut() {
+        final long downTime = SystemClock.uptimeMillis();
+        int keyCodeToSend, metaState;
+        KeyEvent keyEventToSend;
+
+        // Test shortcut trigger in case of non-default single modifier
+        keyCodeToSend = KeyEvent.KEYCODE_C;
+        metaState = KeyEvent.META_SHIFT_ON;
+        keyEventToSend = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                keyCodeToSend, 0, metaState);
+        assertTrue(mActivity.onKeyDown(keyCodeToSend, keyEventToSend));
+        assertEquals(mActivity.getMenuItemIdTracker(), R.id.single_modifier);
+
+        // Test shortcut trigger in case of multiple modifiers
+        keyCodeToSend = KeyEvent.KEYCODE_D;
+        metaState = KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON;
+        keyEventToSend = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                keyCodeToSend, 0, metaState);
+        assertTrue(mActivity.onKeyDown(keyCodeToSend, keyEventToSend));
+        assertEquals(mActivity.getMenuItemIdTracker(), R.id.multiple_modifiers);
+
+        // Test no shortcut trigger in case of incorrect modifier
+        keyCodeToSend = KeyEvent.KEYCODE_E;
+        metaState = KeyEvent.META_CTRL_ON;
+        keyEventToSend = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                keyCodeToSend, 0, metaState);
+        assertFalse(mActivity.onKeyDown(keyCodeToSend, keyEventToSend));
+    }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java
new file mode 100644
index 0000000..26638f2
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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.v7.app;
+
+import android.support.v7.appcompat.test.R;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+public class AppCompatMenuItemShortcutsTestActivity extends AppCompatActivity {
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.appcompat_menu_shortcut, menu);
+        return true;
+    }
+
+    private int mMenuItemIdTracker;
+
+    public int getMenuItemIdTracker() {
+        return mMenuItemIdTracker;
+    }
+
+    public boolean handleMenuItem(MenuItem item) {
+        mMenuItemIdTracker = item.getItemId();
+        return true;
+    }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java b/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java
index 90a9b59..92d97f4 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java
@@ -18,7 +18,6 @@
 
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.BaseTestActivity;
-import android.util.Log;
 
 /**
  * Test activity for testing presence of single and multiple drawers in <code>DrawerLayout</code>.
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java b/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java
index b2e0abc..a1c1558 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java
@@ -16,15 +16,12 @@
 
 package android.support.v7.app;
 
-import android.content.res.Configuration;
-import android.os.Bundle;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.BaseTestActivity;
 import android.support.v7.testutils.Shakespeare;
 import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
diff --git a/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java b/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java
index dc202cd..6305301 100644
--- a/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java
+++ b/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java
@@ -16,12 +16,9 @@
 package android.support.v7.custom;
 
 import android.content.Context;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowInsets;
-
 import android.support.v4.widget.DrawerLayout;
+import android.util.AttributeSet;
+import android.view.WindowInsets;
 
 public class CustomDrawerLayout extends DrawerLayout {
     private int mSystemWindowInsetTop;
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java b/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
index de36207..bce67aa 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
@@ -16,22 +16,20 @@
 
 package android.support.v7.testutils;
 
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+
+import static org.hamcrest.core.AllOf.allOf;
+
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.DrawableRes;
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
-import android.support.v4.view.TintableBackgroundView;
 import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.AppCompatTextView;
 import android.view.View;
-import org.hamcrest.Matcher;
 
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
-import static org.hamcrest.core.AllOf.allOf;
+import org.hamcrest.Matcher;
 
 public class AppCompatTintableViewActions {
     /**
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
index 3e092c4..e3f25a9 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
@@ -25,10 +25,9 @@
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.widget.CheckedTextView;
 import android.widget.ImageView;
-import junit.framework.Assert;
+
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
diff --git a/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java
new file mode 100644
index 0000000..bfcb80b
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.v7.view;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v7.appcompat.test.R;
+import android.support.v7.widget.PopupMenu;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test SupportMenuInflater
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SupportMenuInflaterTest {
+
+    private SupportMenuInflaterTestActivity mActivity;
+    private MenuInflater mMenuInflater;
+    private Menu mMenu;
+
+    @Rule
+    public ActivityTestRule<SupportMenuInflaterTestActivity> mActivityTestRule =
+            new ActivityTestRule<>(SupportMenuInflaterTestActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityTestRule.getActivity();
+        mMenuInflater = mActivity.getMenuInflater();
+        mMenu = new PopupMenu(mActivity, null).getMenu();
+    }
+
+    @Test
+    public void testInflateFromXml() {
+        mMenuInflater.inflate(R.menu.shortcut, mMenu);
+        SupportMenuItem mMenuItem;
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.no_modifiers);
+        assertEquals('a', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getAlphabeticModifiers());
+        assertEquals('1', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getNumericModifiers());
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.default_modifiers);
+        assertEquals('b', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getAlphabeticModifiers());
+        assertEquals('2', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON, mMenuItem.getNumericModifiers());
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.single_modifier);
+        assertEquals('c', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_SHIFT_ON, mMenuItem.getAlphabeticModifiers());
+        assertEquals('3', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_SHIFT_ON, mMenuItem.getNumericModifiers());
+
+        mMenuItem = (SupportMenuItem) mMenu.findItem(R.id.multiple_modifiers);
+        assertEquals('d', mMenuItem.getAlphabeticShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON,
+                mMenuItem.getAlphabeticModifiers());
+        assertEquals('4', mMenuItem.getNumericShortcut());
+        assertEquals(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON,
+                mMenuItem.getNumericModifiers());
+    }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java
new file mode 100644
index 0000000..45ad0d9
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 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.v7.view;
+
+import android.support.v7.appcompat.test.R;
+import android.support.v7.testutils.BaseTestActivity;
+
+public class SupportMenuInflaterTestActivity extends BaseTestActivity {
+
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.appcompat_textview_activity;
+    }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
index bfc2bc1..e663ef2 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
@@ -21,7 +21,6 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.v7.appcompat.test.R;
 
diff --git a/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java b/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java
index 298505b..b779326 100644
--- a/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java
+++ b/v7/cardview/gingerbread/android/support/v7/widget/CardViewGingerbread.java
@@ -21,7 +21,6 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.support.annotation.ColorInt;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 
diff --git a/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java b/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
index 0a090a5..51bd498 100644
--- a/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
+++ b/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
@@ -23,7 +23,6 @@
 import android.support.annotation.RequiresApi;
 import android.util.Log;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
index 6cc8c5d..95b5f5d 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
@@ -28,10 +28,10 @@
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.ViewCompat;
 import android.support.v7.media.MediaRouteSelector;
 import android.support.v7.media.MediaRouter;
 import android.support.v7.mediarouter.R;
+import android.support.v7.widget.TooltipCompat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.SoundEffectConstants;
@@ -274,7 +274,7 @@
      * button when the button is long pressed.
      */
     void setCheatSheetEnabled(boolean enable) {
-        ViewCompat.setTooltipText(this,
+        TooltipCompat.setTooltipText(this,
                 enable ? getContext().getString(R.string.mr_button_content_description) : null);
     }
 
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
index a7a0dd3..4278028 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
@@ -20,7 +20,6 @@
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.support.v7.mediarouter.R;
 import android.support.v7.widget.AppCompatSeekBar;
 import android.util.AttributeSet;
 import android.util.Log;
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java b/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java
index ec2f7ba..f6daeff 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java
@@ -15,7 +15,6 @@
  */
 package android.support.v7.media;
 
-import android.content.IntentFilter;
 import android.os.Bundle;
 
 import java.util.ArrayList;
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index fe16de8..1a17ef5 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -2289,7 +2289,7 @@
                                 mRoutes.add(route);
                                 // 2. Create the route's contents.
                                 if (isGroup) {
-                                    addedGroups.add(new Pair(route, routeDescriptor));
+                                    addedGroups.add(new Pair<>(route, routeDescriptor));
                                 } else {
                                     route.maybeUpdateDescriptor(routeDescriptor);
                                     // 3. Notify clients about addition.
@@ -2309,7 +2309,7 @@
                                         sourceIndex, targetIndex++);
                                 // 2. Update the route's contents.
                                 if (route instanceof RouteGroup) {
-                                    updatedGroups.add(new Pair(route, routeDescriptor));
+                                    updatedGroups.add(new Pair<>(route, routeDescriptor));
                                 } else {
                                     // 3. Notify clients about changes.
                                     if (updateRouteDescriptorAndNotify(route, routeDescriptor)
@@ -2413,7 +2413,7 @@
             String componentName = provider.getComponentName().flattenToShortString();
             String uniqueId = componentName + ":" + routeDescriptorId;
             if (findRouteByUniqueId(uniqueId) < 0) {
-                mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), uniqueId);
+                mUniqueIdMap.put(new Pair<>(componentName, routeDescriptorId), uniqueId);
                 return uniqueId;
             }
             Log.w(TAG, "Either " + routeDescriptorId + " isn't unique in " + componentName
@@ -2421,7 +2421,7 @@
             for (int i = 2; ; i++) {
                 String newUniqueId = String.format(Locale.US, "%s_%d", uniqueId, i);
                 if (findRouteByUniqueId(newUniqueId) < 0) {
-                    mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), newUniqueId);
+                    mUniqueIdMap.put(new Pair<>(componentName, routeDescriptorId), newUniqueId);
                     return newUniqueId;
                 }
             }
@@ -2439,7 +2439,7 @@
 
         private String getUniqueId(ProviderInfo provider, String routeDescriptorId) {
             String componentName = provider.getComponentName().flattenToShortString();
-            return mUniqueIdMap.get(new Pair(componentName, routeDescriptorId));
+            return mUniqueIdMap.get(new Pair<>(componentName, routeDescriptorId));
         }
 
         private void updateSelectedRouteIfNeeded(boolean selectedRouteDescriptorChanged) {
@@ -2494,7 +2494,7 @@
                 if (mSelectedRoute instanceof RouteGroup) {
                     List<RouteInfo> routes = ((RouteGroup) mSelectedRoute).getRoutes();
                     // Build a set of descriptor IDs for the new route group.
-                    Set idSet = new HashSet<String>();
+                    Set<String> idSet = new HashSet<>();
                     for (RouteInfo route : routes) {
                         idSet.add(route.mDescriptorId);
                     }
diff --git a/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java b/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java
index 1dc556b..8e09889 100644
--- a/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java
+++ b/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java
@@ -24,8 +24,6 @@
 import android.os.Bundle;
 import android.util.Log;
 
-import java.util.Iterator;
-
 /**
  * A helper class for playing media on remote routes using the remote playback protocol
  * defined by {@link MediaControlIntent}.
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
index 0c35828..b7fb054 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
@@ -540,7 +540,7 @@
                 final int darkTitleAlpha = ColorUtils.calculateMinimumAlpha(
                         Color.BLACK, mRgb, MIN_CONTRAST_TITLE_TEXT);
 
-                if (darkBodyAlpha != -1 && darkBodyAlpha != -1) {
+                if (darkBodyAlpha != -1 && darkTitleAlpha != -1) {
                     // If we found valid dark values, use them and return
                     mBodyTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
                     mTitleTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index 2e4cfcf..b94876f 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -15,6 +15,7 @@
     androidTestCompile libs.mockito_core
     androidTestCompile libs.dexmaker
     androidTestCompile libs.dexmaker_mockito
+    androidTestCompile project(':support-testutils')
 
     testCompile libs.junit
     testCompile libs.mockito_core
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index b8caca5..6e9ea69 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -486,7 +486,7 @@
      * the View's state is undefined.
      */
     @VisibleForTesting
-    final List<ViewHolder> mPendingAccessibilityImportanceChange = new ArrayList();
+    final List<ViewHolder> mPendingAccessibilityImportanceChange = new ArrayList<>();
 
     private Runnable mItemAnimatorRunner = new Runnable() {
         @Override
@@ -5104,7 +5104,7 @@
 
         public void putRecycledView(ViewHolder scrap) {
             final int viewType = scrap.getItemViewType();
-            final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap;
+            final ArrayList<ViewHolder> scrapHeap = getScrapDataForType(viewType).mScrapHeap;
             if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {
                 return;
             }
@@ -6209,7 +6209,7 @@
                     continue;
                 }
 
-                final int pos = holder.getLayoutPosition();
+                final int pos = holder.mPosition;
                 if (pos >= positionStart && pos < positionEnd) {
                     holder.addFlags(ViewHolder.FLAG_UPDATE);
                     recycleCachedViewAt(i);
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/PollingCheck.java b/v7/recyclerview/tests/src/android/support/v7/util/PollingCheck.java
deleted file mode 100644
index 796a4ae..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/util/PollingCheck.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.v7.util;
-
-import junit.framework.Assert;
-
-import java.util.concurrent.Callable;
-
-public abstract class PollingCheck {
-    private static final long TIME_SLICE = 50;
-    private long mTimeout = 3000;
-
-    public interface PollingCheckCondition {
-        boolean canProceed();
-    }
-
-    public PollingCheck() {
-    }
-
-    public PollingCheck(long timeout) {
-        mTimeout = timeout;
-    }
-
-    protected abstract boolean check();
-
-    public void run() {
-        if (check()) {
-            return;
-        }
-
-        long timeout = mTimeout;
-        while (timeout > 0) {
-            try {
-                Thread.sleep(TIME_SLICE);
-            } catch (InterruptedException e) {
-                Assert.fail("unexpected InterruptedException");
-            }
-
-            if (check()) {
-                return;
-            }
-
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail("unexpected timeout");
-    }
-
-    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
-            throws Exception {
-        while (timeout > 0) {
-            if (condition.call()) {
-                return;
-            }
-
-            Thread.sleep(TIME_SLICE);
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail(message.toString());
-    }
-
-    public static void waitFor(final PollingCheckCondition condition) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return condition.canProceed();
-            }
-        }.run();
-    }
-
-    public static void waitFor(long timeout, final PollingCheckCondition condition) {
-        new PollingCheck(timeout) {
-            @Override
-            protected boolean check() {
-                return condition.canProceed();
-            }
-        }.run();
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 5f7bf48..8ca5f4e 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -765,7 +765,7 @@
 
         int mAdapterIndex;
 
-        final String mText;
+        String mText;
         int mType = 0;
         boolean mFocusable;
 
@@ -882,7 +882,12 @@
             assertEquals(log, shouldHavePosition, adapterPosition != RecyclerView.NO_POSITION);
             if (shouldHavePosition) {
                 assertTrue(log, mItems.size() > adapterPosition);
-                assertSame(log, holder.mBoundItem, mItems.get(adapterPosition));
+                // TODO: fix b/36042615 getAdapterPosition() is wrong in
+                // consumePendingUpdatesInOnePass where it applies pending change to already
+                // modified position.
+                if (holder.mPreLayoutPosition == RecyclerView.NO_POSITION) {
+                    assertSame(log, holder.mBoundItem, mItems.get(adapterPosition));
+                }
             }
         }
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
index 6a2a175..bd14d2c 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
@@ -43,7 +43,7 @@
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class RecyclerViewAccessibilityLifecycleTest extends BaseRecyclerViewInstrumentationTest {
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
     @Test
     public void dontDispatchChangeDuringLayout() throws Throwable {
         LayoutAllLayoutManager lm = new LayoutAllLayoutManager();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index 786df47..2142832 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -906,6 +906,61 @@
     }
 
     @Test
+    public void moveAndUpdateCachedViews() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setItemViewCacheSize(3);
+        recyclerView.setItemAnimator(null);
+        final TestAdapter adapter = new TestAdapter(1000);
+        final CountDownLatch layoutLatch = new CountDownLatch(1);
+        LinearLayoutManager tlm = new LinearLayoutManager(recyclerView.getContext()) {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutLatch.countDown();
+            }
+        };
+        tlm.setItemPrefetchEnabled(false);
+        recyclerView.setLayoutManager(tlm);
+        recyclerView.setAdapter(adapter);
+        setRecyclerView(recyclerView);
+        // wait first layout pass
+        layoutLatch.await();
+        // scroll and hide 0 and 1
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.smoothScrollBy(0, recyclerView.getChildAt(2).getTop() + 5);
+            }
+        });
+        waitForIdleScroll(recyclerView);
+        assertNull(recyclerView.findViewHolderForAdapterPosition(0));
+        assertNull(recyclerView.findViewHolderForAdapterPosition(1));
+        // swap 1 and 0 and update 0
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    // swap 1 and 0
+                    adapter.moveInUIThread(1, 0);
+                    adapter.notifyItemMoved(1, 0);
+                    // update 0
+                    adapter.mItems.get(0).mText = "updated";
+                    adapter.notifyItemChanged(0);
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+        // scroll back to 0
+        smoothScrollToPosition(0);
+        waitForIdleScroll(recyclerView);
+        TestViewHolder vh = (TestViewHolder) recyclerView.findViewHolderForAdapterPosition(0);
+        // assert updated right item
+        assertTrue((((TextView) (vh.itemView)).getText()).toString().contains("updated"));
+        checkForMainThreadException();
+    }
+
+    @Test
     public void noLayoutIf0ItemsAreChanged() throws Throwable {
         unnecessaryNotifyEvents(new AdapterRunnable() {
             @Override
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
index c95f9ab..aa66b8f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
@@ -16,12 +16,10 @@
 
 package android.support.v7.widget;
 
-import android.app.Instrumentation;
 import android.content.Context;
 import android.support.test.InstrumentationRegistry;
 import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
-import android.view.View;
 
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.MatcherAssert;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
index 604bf71..18af47b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -31,7 +31,7 @@
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.Suppress;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.util.PollingCheck;
+import android.support.testutils.PollingCheck;
 import android.support.v7.util.TouchUtils;
 import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
 import android.support.v7.widget.RecyclerView;
diff --git a/wearable/Android.mk b/wearable/Android.mk
index 98ea45a..7339f55 100644
--- a/wearable/Android.mk
+++ b/wearable/Android.mk
@@ -19,7 +19,8 @@
 #
 #   LOCAL_STATIC_ANDROID_LIBRARIES := \
 #       android-support-wearable \
-#       android-support-core-ui
+#       android-support-core-ui \
+#       android-support-v7-recyclerview
 #
 # in their makefiles to include the resources and their dependencies in their package.
 include $(CLEAR_VARS)
@@ -29,9 +30,10 @@
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-core-ui \
-    android-support-annotations \
-    android-support-v7-recyclerview
+        android-support-core-ui \
+        android-support-annotations \
+        android-support-v7-recyclerview \
+        android-support-v4
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/wearable/build.gradle b/wearable/build.gradle
index 74b4c89..81ec665 100644
--- a/wearable/build.gradle
+++ b/wearable/build.gradle
@@ -5,13 +5,15 @@
     compile project(':support-annotations')
     compile project(':support-core-ui')
     compile project(':support-recyclerview-v7')
-
     androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
     androidTestCompile (libs.espresso_core) {
         exclude module: 'support-annotations'
     }
+    androidTestCompile libs.mockito_core
+    androidTestCompile libs.dexmaker
+    androidTestCompile libs.dexmaker_mockito
 }
 
 android {
diff --git a/wearable/res-public/values/public_attrs.xml b/wearable/res-public/values/public_attrs.xml
index afb7bfe..a8a2909 100644
--- a/wearable/res-public/values/public_attrs.xml
+++ b/wearable/res-public/values/public_attrs.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2017 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.
@@ -16,5 +16,11 @@
 
 <!-- Definitions of attributes to be exposed as public -->
 <resources>
+    <!-- BoxInsetLayout -->
     <public type="attr" name="boxedEdges" />
+
+    <!-- WearableRecyclerView -->
+    <public type="attr" name="bezelWidth" />
+    <public type="attr" name="circularScrollingGestureEnabled" />
+    <public type="attr" name="scrollDegreesPerScreen" />
 </resources>
\ No newline at end of file
diff --git a/wearable/res/values/attrs.xml b/wearable/res/values/attrs.xml
index e52dee9..bdf3675 100644
--- a/wearable/res/values/attrs.xml
+++ b/wearable/res/values/attrs.xml
@@ -47,4 +47,21 @@
             <flag name="all" value="0x0F" />
         </attr>
     </declare-styleable>
+
+    <!-- Attributes that can be used with any
+        {@link android.support.wearable.view.WearableRecyclerView}.
+        These attributes relate to the circular scrolling gesture of the view. -->
+    <declare-styleable name="WearableRecyclerView">
+        <!-- Taps within this radius and the radius of the screen are considered close enough to the
+            bezel to be candidates for circular scrolling. Expressed as a fraction of the screen's
+            radius. The default is the whole screen i.e 1.0f -->
+        <attr name="bezelWidth" format="fraction" />
+        <!-- Enables/disables circular touch scrolling for this view. When enabled, circular touch
+            gestures around the edge of the screen will cause the view to scroll up or down. -->
+        <attr name="circularScrollingGestureEnabled" format="boolean" />
+        <!-- Sets how many degrees the user has to rotate by to scroll through one screen height
+            when they are using the circular scrolling gesture. The default value equates 180
+            degrees scroll to one screen.-->
+        <attr name="scrollDegreesPerScreen" format="float" />
+    </declare-styleable>
 </resources>
diff --git a/dynamic-animation/AndroidManifest-make.xml b/wearable/res/values/dimens.xml
similarity index 78%
copy from dynamic-animation/AndroidManifest-make.xml
copy to wearable/res/values/dimens.xml
index bfe97cc..4b95511 100644
--- a/dynamic-animation/AndroidManifest-make.xml
+++ b/wearable/res/values/dimens.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
+<resources>
+    <!-- Values for the WearableRecyclerView. -->
+    <dimen name="wrv_curve_default_x_offset">24dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/wearable/src/android/support/wearable/view/CurvedOffsettingHelper.java b/wearable/src/android/support/wearable/view/CurvedOffsettingHelper.java
new file mode 100644
index 0000000..a1f4e3b
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/CurvedOffsettingHelper.java
@@ -0,0 +1,141 @@
+/*
+ * 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.wearable.view;
+
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.support.wearable.R;
+import android.view.View;
+
+/**
+ * This implementation of the {@link WearableRecyclerView.OffsettingHelper} provides basic
+ * offsetting logic for updating child layout. For round devices it offsets the children
+ * horizontally to make them appear to travel around a circle. For square devices it aligns them
+ * in a straight list.
+ */
+public class CurvedOffsettingHelper extends WearableRecyclerView.OffsettingHelper {
+    private static final float EPSILON = 0.001f;
+
+    private final Path mCurvePath;
+    private final PathMeasure mPathMeasure;
+    private int mCurvePathHeight;
+    private int mXCurveOffset;
+    private float mPathLength;
+    private float mCurveBottom;
+    private float mCurveTop;
+    private float mLineGradient;
+    private final float[] mPathPoints = new float[2];
+    private final float[] mPathTangent = new float[2];
+    private final float[] mAnchorOffsetXY = new float[2];
+
+    private WearableRecyclerView mParentView;
+    private boolean mIsScreenRound;
+    private int mLayoutWidth;
+    private int mLayoutHeight;
+
+    public CurvedOffsettingHelper() {
+        mCurvePath = new Path();
+        mPathMeasure = new PathMeasure();
+    }
+
+    @Override
+    public void updateChild(View child, WearableRecyclerView parent) {
+        if (mParentView != parent || (mParentView != null
+                && (mParentView.getWidth() != parent.getWidth()
+                        || mParentView.getHeight() != parent.getHeight()))) {
+            mParentView = parent;
+            mIsScreenRound =
+                    mParentView.getContext().getResources().getConfiguration().isScreenRound();
+            mXCurveOffset =
+                    mParentView.getResources().getDimensionPixelSize(
+                            R.dimen.wrv_curve_default_x_offset);
+            mLayoutWidth = mParentView.getWidth();
+            mLayoutHeight = mParentView.getHeight();
+        }
+        if (mIsScreenRound) {
+            maybeSetUpCircularInitialLayout(mLayoutWidth, mLayoutHeight);
+            mAnchorOffsetXY[0] = mXCurveOffset;
+            mAnchorOffsetXY[1] = child.getHeight() / 2.0f;
+            adjustAnchorOffsetXY(child, mAnchorOffsetXY);
+            float minCenter = -(float) child.getHeight() / 2;
+            float maxCenter = mLayoutHeight + (float) child.getHeight() / 2;
+            float range = maxCenter - minCenter;
+            float verticalAnchor = (float) child.getTop() + mAnchorOffsetXY[1];
+            float mYScrollProgress = (verticalAnchor + Math.abs(minCenter)) / range;
+
+            mPathMeasure.getPosTan(mYScrollProgress * mPathLength, mPathPoints, mPathTangent);
+
+            boolean topClusterRisk =
+                    Math.abs(mPathPoints[1] - mCurveBottom) < EPSILON && minCenter < mPathPoints[1];
+            boolean bottomClusterRisk =
+                    Math.abs(mPathPoints[1] - mCurveTop) < EPSILON && maxCenter > mPathPoints[1];
+            // Continue offsetting the child along the straight-line part of the curve, if it has
+            // not gone off the screen when it reached the end of the original curve.
+            if (topClusterRisk || bottomClusterRisk) {
+                mPathPoints[1] = verticalAnchor;
+                mPathPoints[0] = (Math.abs(verticalAnchor) * mLineGradient);
+            }
+
+            // Offset the View to match the provided anchor point.
+            int newLeft = (int) (mPathPoints[0] - mAnchorOffsetXY[0]);
+            child.offsetLeftAndRight(newLeft - child.getLeft());
+            float verticalTranslation = mPathPoints[1] - verticalAnchor;
+            child.setTranslationY(verticalTranslation);
+        }
+    }
+
+    /**
+     * Override this method if you wish to adjust the anchor coordinates for each child view during
+     * a layout pass. In the override set the new desired anchor coordinates in the provided array.
+     * The coordinates should be provided in relation to the child view.
+     *
+     * @param child          The child view to which the anchor coordinates will apply.
+     * @param anchorOffsetXY The anchor coordinates for the provided child view, by default set to
+     *                       a pre-defined constant on the horizontal axis and half of the child
+     *                       height on the vertical axis (vertical center).
+     */
+    public void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) {
+        return;
+    }
+
+    /** Set up the initial layout for round screens. */
+    private void maybeSetUpCircularInitialLayout(int width, int height) {
+        // The values in this function are custom to the curve we use.
+        if (mCurvePathHeight != height) {
+            mCurvePathHeight = height;
+            mCurveBottom = -0.048f * height;
+            mCurveTop = 1.048f * height;
+            mLineGradient = 0.5f / 0.048f;
+            mCurvePath.reset();
+            mCurvePath.moveTo(0.5f * width, mCurveBottom);
+            mCurvePath.lineTo(0.34f * width, 0.075f * height);
+            mCurvePath.cubicTo(
+                    0.22f * width, 0.17f * height, 0.13f * width, 0.32f * height, 0.13f * width,
+                    height / 2);
+            mCurvePath.cubicTo(
+                    0.13f * width,
+                    0.68f * height,
+                    0.22f * width,
+                    0.83f * height,
+                    0.34f * width,
+                    0.925f * height);
+            mCurvePath.lineTo(width / 2, mCurveTop);
+            mPathMeasure.setPath(mCurvePath, false);
+            mPathLength = mPathMeasure.getLength();
+        }
+    }
+}
diff --git a/wearable/src/android/support/wearable/view/ScrollManager.java b/wearable/src/android/support/wearable/view/ScrollManager.java
new file mode 100644
index 0000000..4699d4b
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/ScrollManager.java
@@ -0,0 +1,236 @@
+/*
+ * 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.wearable.view;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.support.annotation.RestrictTo;
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+
+/**
+ * Class adding circular scrolling support to {@link WearableRecyclerView}.
+ *
+ * @hide
+ */
+@TargetApi(Build.VERSION_CODES.M)
+@RestrictTo(LIBRARY_GROUP)
+class ScrollManager {
+    // One second in milliseconds.
+    private static final int ONE_SEC_IN_MS = 1000;
+    private static final float VELOCITY_MULTIPLIER = 1.5f;
+    private static final float FLING_EDGE_RATIO = 1.5f;
+
+    /**
+     * Taps beyond this radius fraction are considered close enough to the bezel to be candidates
+     * for circular scrolling.
+     */
+    private float mMinRadiusFraction = 0.0f;
+
+    private float mMinRadiusFractionSquared = mMinRadiusFraction * mMinRadiusFraction;
+
+    /** How many degrees you have to drag along the bezel to scroll one screen height. */
+    private float mScrollDegreesPerScreen = 180;
+
+    private float mScrollRadiansPerScreen = (float) Math.toRadians(mScrollDegreesPerScreen);
+
+    /** Radius of screen in pixels, ignoring insets, if any. */
+    private float mScreenRadiusPx;
+
+    private float mScreenRadiusPxSquared;
+
+    /** How many pixels to scroll for each radian of bezel scrolling. */
+    private float mScrollPixelsPerRadian;
+
+    /** Whether an {@link MotionEvent#ACTION_DOWN} was received near the bezel. */
+    private boolean mDown;
+
+    /**
+     * Whether the user tapped near the bezel and dragged approximately tangentially to initiate
+     * bezel scrolling.
+     */
+    private boolean mScrolling;
+    /**
+     * The angle of the user's finger relative to the center of the screen for the last {@link
+     * MotionEvent} during bezel scrolling.
+     */
+    private float mLastAngleRadians;
+
+    private RecyclerView mRecyclerView;
+    VelocityTracker mVelocityTracker;
+
+    /** Should be called after the window is attached to the view. */
+    void setRecyclerView(RecyclerView recyclerView, int width, int height) {
+        mRecyclerView = recyclerView;
+        mScreenRadiusPx = Math.max(width, height) / 2f;
+        mScreenRadiusPxSquared = mScreenRadiusPx * mScreenRadiusPx;
+        mScrollPixelsPerRadian = height / mScrollRadiansPerScreen;
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    /** Remove the binding with a {@link RecyclerView} */
+    void clearRecyclerView() {
+        mRecyclerView = null;
+    }
+
+    /**
+     * Method dealing with touch events intercepted from the attached {@link RecyclerView}.
+     *
+     * @param event the intercepted touch event.
+     * @return true if the even was handled, false otherwise.
+     */
+    boolean onTouchEvent(MotionEvent event) {
+        float deltaX = event.getRawX() - mScreenRadiusPx;
+        float deltaY = event.getRawY() - mScreenRadiusPx;
+        float radiusSquared = deltaX * deltaX + deltaY * deltaY;
+        final MotionEvent vtev = MotionEvent.obtain(event);
+        mVelocityTracker.addMovement(vtev);
+        vtev.recycle();
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                if (radiusSquared / mScreenRadiusPxSquared > mMinRadiusFractionSquared) {
+                    mDown = true;
+                    return true; // Consume the event.
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (mScrolling) {
+                    float angleRadians = (float) Math.atan2(deltaY, deltaX);
+                    float deltaRadians = angleRadians - mLastAngleRadians;
+                    deltaRadians = normalizeAngleRadians(deltaRadians);
+                    int scrollPixels = Math.round(deltaRadians * mScrollPixelsPerRadian);
+                    if (scrollPixels != 0) {
+                        mRecyclerView.scrollBy(0 /* x */, scrollPixels /* y */);
+                        // Recompute deltaRadians in terms of rounded scrollPixels.
+                        deltaRadians = scrollPixels / mScrollPixelsPerRadian;
+                        mLastAngleRadians += deltaRadians;
+                        mLastAngleRadians = normalizeAngleRadians(mLastAngleRadians);
+                    }
+                    // Always consume the event so that we never break the circular scrolling
+                    // gesture.
+                    return true;
+                }
+
+                if (mDown) {
+                    float deltaXFromCenter = event.getRawX() - mScreenRadiusPx;
+                    float deltaYFromCenter = event.getRawY() - mScreenRadiusPx;
+                    float distFromCenter = (float) Math.hypot(deltaXFromCenter, deltaYFromCenter);
+                    if (distFromCenter != 0) {
+                        deltaXFromCenter /= distFromCenter;
+                        deltaYFromCenter /= distFromCenter;
+
+                        mScrolling = true;
+                        mRecyclerView.invalidate();
+                        mLastAngleRadians = (float) Math.atan2(deltaYFromCenter, deltaXFromCenter);
+                        return true; // Consume the event.
+                    }
+                } else {
+                    // Double check we're not missing an event we should really be handling.
+                    if (radiusSquared / mScreenRadiusPxSquared > mMinRadiusFractionSquared) {
+                        mDown = true;
+                        return true; // Consume the event.
+                    }
+                }
+                break;
+
+            case MotionEvent.ACTION_UP:
+                mDown = false;
+                mScrolling = false;
+                mVelocityTracker.computeCurrentVelocity(ONE_SEC_IN_MS,
+                        mRecyclerView.getMaxFlingVelocity());
+                int velocityY = (int) mVelocityTracker.getYVelocity();
+                if (event.getX() < FLING_EDGE_RATIO * mScreenRadiusPx) {
+                    velocityY = -velocityY;
+                }
+                mVelocityTracker.clear();
+                if (Math.abs(velocityY) > mRecyclerView.getMinFlingVelocity()) {
+                    return mRecyclerView.fling(0, (int) (VELOCITY_MULTIPLIER * velocityY));
+                }
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                if (mDown) {
+                    mDown = false;
+                    mScrolling = false;
+                    mRecyclerView.invalidate();
+                    return true; // Consume the event.
+                }
+                break;
+        }
+
+        return false;
+    }
+
+    /**
+     * Normalizes an angle to be in the range [-pi, pi] by adding or subtracting 2*pi if necessary.
+     *
+     * @param angleRadians an angle in radians. Must be no more than 2*pi out of normal range.
+     * @return an angle in radians in the range [-pi, pi]
+     */
+    private static float normalizeAngleRadians(float angleRadians) {
+        if (angleRadians < -Math.PI) {
+            angleRadians = (float) (angleRadians + Math.PI * 2);
+        }
+        if (angleRadians > Math.PI) {
+            angleRadians = (float) (angleRadians - Math.PI * 2);
+        }
+        return angleRadians;
+    }
+
+    /**
+     * Set how many degrees you have to drag along the bezel to scroll one screen height.
+     *
+     * @param degreesPerScreen desired degrees per screen scroll.
+     */
+    public void setScrollDegreesPerScreen(float degreesPerScreen) {
+        mScrollDegreesPerScreen = degreesPerScreen;
+        mScrollRadiansPerScreen = (float) Math.toRadians(mScrollDegreesPerScreen);
+    }
+
+    /**
+     * Sets the width of a virtual 'bezel' close to the edge of the screen within which taps can be
+     * recognized as belonging to a rotary scrolling gesture.
+     *
+     * @param fraction desired fraction of the width of the screen to be treated as a valid rotary
+     *                 scrolling target.
+     */
+    public void setBezelWidth(float fraction) {
+        mMinRadiusFraction = 1 - fraction;
+        mMinRadiusFractionSquared = mMinRadiusFraction * mMinRadiusFraction;
+    }
+
+    /**
+     * Returns how many degrees you have to drag along the bezel to scroll one screen height. See
+     * {@link #setScrollDegreesPerScreen(float)} for details.
+     */
+    public float getScrollDegreesPerScreen() {
+        return mScrollDegreesPerScreen;
+    }
+
+    /**
+     * Returns the current bezel width for circular scrolling. See {@link #setBezelWidth(float)}
+     * for details.
+     */
+    public float getBezelWidth() {
+        return 1 - mMinRadiusFraction;
+    }
+}
diff --git a/wearable/src/android/support/wearable/view/WearableRecyclerView.java b/wearable/src/android/support/wearable/view/WearableRecyclerView.java
new file mode 100644
index 0000000..5531417
--- /dev/null
+++ b/wearable/src/android/support/wearable/view/WearableRecyclerView.java
@@ -0,0 +1,334 @@
+/*
+ * 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.wearable.view;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Point;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.wearable.R;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * Wearable specific implementation of the {@link RecyclerView} enabling {@link
+ * #setCircularScrollingGestureEnabled(boolean)} circular scrolling} and semi-circular layouts.
+ *
+ * @see #setCircularScrollingGestureEnabled(boolean)
+ * @see #setOffsettingHelper(OffsettingHelper)
+ */
+@TargetApi(Build.VERSION_CODES.M)
+public class WearableRecyclerView extends RecyclerView {
+    private static final String TAG = "WearableRecyclerView";
+
+    private static final int NO_VALUE = Integer.MIN_VALUE;
+
+    /**
+     * This class defines the offsetting logic for updating layout of children in a
+     * WearableRecyclerView.
+     */
+    public abstract static class OffsettingHelper {
+
+        /**
+         * Override this method if you wish to implement custom child layout behavior on scroll.
+         *
+         * @param child  the current child to be affected.
+         * @param parent the {@link WearableRecyclerView} parent that this helper is attached to.
+         */
+        public abstract void updateChild(View child, WearableRecyclerView parent);
+    }
+
+    private final ScrollManager mScrollManager = new ScrollManager();
+    private OffsettingHelper mOffsettingHelper;
+    private boolean mCircularScrollingEnabled;
+    private boolean mEdgeItemsCenteringEnabled;
+
+    private int mOriginalPaddingTop = NO_VALUE;
+    private int mOriginalPaddingBottom = NO_VALUE;
+
+    public WearableRecyclerView(Context context) {
+        this(context, null);
+    }
+
+    public WearableRecyclerView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WearableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    public WearableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle,
+            int defStyleRes) {
+        super(context, attrs, defStyle);
+
+        setHasFixedSize(true);
+        // Padding is used to center the top and bottom items in the list, don't clip to padding to
+        // allows the items to draw in that space.
+        setClipToPadding(false);
+
+        if (attrs != null) {
+            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WearableRecyclerView,
+                    defStyle, defStyleRes);
+
+            setCircularScrollingGestureEnabled(
+                    a.getBoolean(
+                            R.styleable.WearableRecyclerView_circularScrollingGestureEnabled,
+                            mCircularScrollingEnabled));
+            setBezelWidthFraction(
+                    a.getFloat(R.styleable.WearableRecyclerView_bezelWidth,
+                            mScrollManager.getBezelWidth()));
+            setScrollDegreesPerScreen(
+                    a.getFloat(
+                            R.styleable.WearableRecyclerView_scrollDegreesPerScreen,
+                            mScrollManager.getScrollDegreesPerScreen()));
+            a.recycle();
+        }
+
+        setLayoutManager(new OffsettingLinearLayoutManager(getContext()));
+    }
+
+    private void setupCenteredPadding() {
+        if (getChildCount() < 1 || !mEdgeItemsCenteringEnabled) {
+            return;
+        }
+        // All the children in the view are the same size, as we set setHasFixedSize
+        // to true, so the height of the first child is the same as all of them.
+        View child = getChildAt(0);
+        int height = child.getHeight();
+        // This is enough padding to center the child view in the parent.
+        int desiredPadding = (int) ((getHeight() * 0.5f) - (height * 0.5f));
+
+        if (getPaddingTop() != desiredPadding) {
+            mOriginalPaddingTop = getPaddingTop();
+            mOriginalPaddingBottom = getPaddingBottom();
+            // The view is symmetric along the vertical axis, so the top and bottom
+            // can be the same.
+            setPadding(getPaddingLeft(), desiredPadding, getPaddingRight(), desiredPadding);
+
+            // The focused child should be in the center, so force a scroll to it.
+            View focusedChild = getFocusedChild();
+            int focusedPosition =
+                    (focusedChild != null) ? getLayoutManager().getPosition(
+                            focusedChild) : 0;
+            getLayoutManager().scrollToPosition(focusedPosition);
+        }
+    }
+
+    private void setupOriginalPadding() {
+        if (mOriginalPaddingTop == NO_VALUE) {
+            return;
+        } else {
+            setPadding(getPaddingLeft(), mOriginalPaddingTop, getPaddingRight(),
+                    mOriginalPaddingBottom);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mCircularScrollingEnabled && mScrollManager.onTouchEvent(event)) {
+            return true;
+        }
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Point screenSize = new Point();
+        getDisplay().getSize(screenSize);
+        mScrollManager.setRecyclerView(this, screenSize.x, screenSize.y);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mScrollManager.clearRecyclerView();
+    }
+
+    @Override
+    public void setLayoutManager(LayoutManager layoutManager) {
+        if (!(layoutManager instanceof OffsettingLinearLayoutManager)) {
+            throw new UnsupportedOperationException(
+                    "This class implements its own layout manager and does not take custom ones");
+        } else {
+            super.setLayoutManager(layoutManager);
+        }
+    }
+
+    /**
+     * Enables/disables circular touch scrolling for this view. When enabled, circular touch
+     * gestures around the edge of the screen will cause the view to scroll up or down. Related
+     * methods let you specify the characteristics of the scrolling, like the speed of the scroll
+     * or the are considered for the start of this scrolling gesture.
+     *
+     * @see #setScrollDegreesPerScreen(float)
+     * @see #setBezelWidthFraction(float)
+     */
+    public void setCircularScrollingGestureEnabled(boolean circularScrollingGestureEnabled) {
+        mCircularScrollingEnabled = circularScrollingGestureEnabled;
+    }
+
+    /**
+     * Returns whether circular scrolling is enabled for this view.
+     *
+     * @see #setCircularScrollingGestureEnabled(boolean)
+     */
+    public boolean isCircularScrollingGestureEnabled() {
+        return mCircularScrollingEnabled;
+    }
+
+    /**
+     * Sets how many degrees the user has to rotate by to scroll through one screen height when they
+     * are using the circular scrolling gesture.The default value equates 180 degrees scroll to one
+     * screen.
+     *
+     * @see #setCircularScrollingGestureEnabled(boolean)
+     *
+     * @param degreesPerScreen the number of degrees to rotate by to scroll through one whole
+     *                         height of the screen,
+     */
+    public void setScrollDegreesPerScreen(float degreesPerScreen) {
+        mScrollManager.setScrollDegreesPerScreen(degreesPerScreen);
+    }
+
+    /**
+     * Returns how many degrees does the user have to rotate for to scroll through one screen
+     * height.
+     *
+     * @see #setCircularScrollingGestureEnabled(boolean)
+     * @see #setScrollDegreesPerScreen(float).
+     */
+    public float getScrollDegreesPerScreen() {
+        return mScrollManager.getScrollDegreesPerScreen();
+    }
+
+    /**
+     * Taps within this radius and the radius of the screen are considered close enough to the
+     * bezel to be candidates for circular scrolling. Expressed as a fraction of the screen's
+     * radius. The default is the whole screen i.e 1.0f.
+     */
+    public void setBezelWidthFraction(float fraction) {
+        mScrollManager.setBezelWidth(fraction);
+    }
+
+    /**
+     * Returns the current bezel width for circular scrolling as a fraction of the screen's
+     * radius.
+     *
+     * @see #setBezelWidthFraction(float)
+     */
+    public float getBezelWidthFraction() {
+        return mScrollManager.getBezelWidth();
+    }
+
+    /**
+     * Sets the {@link WearableRecyclerView.OffsettingHelper} that this {@link
+     * WearableRecyclerView} will use.
+     *
+     * @param offsettingHelper the instance of {@link OffsettingHelper} to use. Pass null if you
+     *                         wish to clear the instance used.
+     */
+    public void setOffsettingHelper(@Nullable OffsettingHelper offsettingHelper) {
+        mOffsettingHelper = offsettingHelper;
+    }
+
+    /**
+     * Return the {@link WearableRecyclerView.OffsettingHelper} currently responsible for
+     * offsetting logic for this {@link WearableRecyclerView}.
+     *
+     * @return the currently used {@link OffsettingHelper} instance.
+     */
+    @Nullable
+    public OffsettingHelper getOffsettingHelper() {
+        return mOffsettingHelper;
+    }
+
+    /**
+     * Use this method to configure the {@link WearableRecyclerView} to always align the first and
+     * last items with the vertical center of the screen. This effectively moves the start and end
+     * of the list to the middle of the screen if the user has scrolled so far. It takes the height
+     * of the children into account so that they are correctly centered.
+     *
+     * @param isEnabled set to true if you wish to align the edge children (first and last)
+     *                        with the center of the screen.
+     */
+    public void setEdgeItemsCenteringEnabled(boolean isEnabled) {
+        mEdgeItemsCenteringEnabled = isEnabled;
+        if (mEdgeItemsCenteringEnabled) {
+            setupCenteredPadding();
+        } else {
+            setupOriginalPadding();
+        }
+    }
+
+    /**
+     * Returns whether the view is currently configured to center the edge children. See {@link
+     * #setEdgeItemsCenteringEnabled} for details.
+     */
+    public boolean getEdgeItemsCenteringEnabled() {
+        return mEdgeItemsCenteringEnabled;
+    }
+
+    /**
+     * Helper class which implements a vertical linear layout manager that encapsulates the logic
+     * for updating layout of children of a WearableRecyclerView.
+     */
+    private final class OffsettingLinearLayoutManager extends LinearLayoutManager {
+        /**
+         * Creates a vertical OffsettingLinearLayoutManager
+         *
+         * @param context Current context, will be used to access resources.
+         */
+        OffsettingLinearLayoutManager(Context context) {
+            super(context, VERTICAL, false);
+        }
+
+        @Override
+        public int scrollVerticallyBy(
+                int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
+            int scrolled = super.scrollVerticallyBy(dy, recycler, state);
+
+            updateLayout();
+            return scrolled;
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            super.onLayoutChildren(recycler, state);
+            if (getChildCount() == 0) {
+                return;
+            }
+
+            updateLayout();
+        }
+
+        private void updateLayout() {
+            if (mOffsettingHelper != null) {
+                for (int count = 0; count < getChildCount(); count++) {
+                    View child = getChildAt(count);
+                    mOffsettingHelper.updateChild(child, WearableRecyclerView.this);
+                }
+            }
+        }
+    }
+}
diff --git a/wearable/tests/Android.mk b/wearable/tests/Android.mk
deleted file mode 100644
index 41e00fb..0000000
--- a/wearable/tests/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/res \
-    $(LOCAL_PATH)/../res
-
-LOCAL_STATIC_JAVA_LIBRARIES  := \
-        android-support-wearable \
-        android-support-annotations
-
-LOCAL_PACKAGE_NAME := WearableViewTests
-LOCAL_AAPT_FLAGS := \
-        --auto-add-overlay \
-        --extra-packages android.support.wearable.view
-
-include $(BUILD_PACKAGE)
diff --git a/wearable/tests/AndroidManifest.xml b/wearable/tests/AndroidManifest.xml
index a0ab292..638532d 100644
--- a/wearable/tests/AndroidManifest.xml
+++ b/wearable/tests/AndroidManifest.xml
@@ -19,13 +19,12 @@
           package="android.support.wearable.test">
     <uses-sdk android:minSdkVersion="20"
               android:targetSdkVersion="23"
-              tools:overrideLibrary="android.support.test,
-                      android.app, android.support.test.rule, android.support.test.espresso,
-                      android.support.test.espresso.idling"/>
+              tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
+                      android.support.test.espresso, android.support.test.espresso.idling"/>
 
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
-    <application android:supportsRtl="true" >
+    <application android:supportsRtl="true">
         <activity android:name="android.support.wearable.view.LayoutTestActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -38,5 +37,12 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity android:name="android.support.wearable.view.WearableRecyclerViewTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/wearable/tests/res/layout/curved_offsetting_helper_child.xml b/wearable/tests/res/layout/curved_offsetting_helper_child.xml
new file mode 100644
index 0000000..781d6b3
--- /dev/null
+++ b/wearable/tests/res/layout/curved_offsetting_helper_child.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content1"
+    android:layout_width="100dp"
+    android:layout_height="50dp"
+    android:text="Test Case 1"/>
\ No newline at end of file
diff --git a/wearable/tests/res/layout/wearable_recycler_view_basic.xml b/wearable/tests/res/layout/wearable_recycler_view_basic.xml
new file mode 100644
index 0000000..3f2c255
--- /dev/null
+++ b/wearable/tests/res/layout/wearable_recycler_view_basic.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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.
+  -->
+
+<android.support.wearable.view.WearableRecyclerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/wrv">
+
+</android.support.wearable.view.WearableRecyclerView>
diff --git a/wearable/tests/src/android/support/wearable/view/BoxInsetLayoutTest.java b/wearable/tests/src/android/support/wearable/view/BoxInsetLayoutTest.java
index 98fa0f0..16d92d11 100644
--- a/wearable/tests/src/android/support/wearable/view/BoxInsetLayoutTest.java
+++ b/wearable/tests/src/android/support/wearable/view/BoxInsetLayoutTest.java
@@ -359,6 +359,6 @@
     }
 
     private abstract class ViewFetchingRunnable implements Runnable {
-        Map<Integer, View> mIdViewMap = new HashMap();
+        Map<Integer, View> mIdViewMap = new HashMap<>();
     }
 }
diff --git a/wearable/tests/src/android/support/wearable/view/CurvedOffsettingHelperTest.java b/wearable/tests/src/android/support/wearable/view/CurvedOffsettingHelperTest.java
new file mode 100644
index 0000000..69d86ce
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/CurvedOffsettingHelperTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2017 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.wearable.view;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.test.R;
+import android.support.wearable.view.util.WakeLockRule;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CurvedOffsettingHelperTest {
+
+    @Rule
+    public final WakeLockRule wakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<WearableRecyclerViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(WearableRecyclerViewTestActivity.class, true, true);
+
+    CurvedOffsettingHelper mCurvedOffsettingHelperUnderTest;
+
+    @Before
+    public void setUp() throws Throwable {
+        MockitoAnnotations.initMocks(this);
+        mCurvedOffsettingHelperUnderTest = new CurvedOffsettingHelper();
+    }
+
+    @Test
+    public void testOffsetting() throws Throwable {
+        ViewFetchingRunnable customRunnable = new ViewFetchingRunnable(){
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setLayoutParams(new FrameLayout.LayoutParams(390, 390));
+                wrv.invalidate();
+                mIdViewMap.put(R.id.wrv, wrv);
+            }
+        };
+        mActivityRule.runOnUiThread(customRunnable);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        WearableRecyclerView wrv = (WearableRecyclerView) customRunnable.mIdViewMap.get(R.id.wrv);
+        int offset = wrv.getResources().getDimensionPixelSize(R.dimen.wrv_curve_default_x_offset);
+        View child1 = wrv.getChildAt(0);
+        View child2 = wrv.getChildAt(1);
+        View child3 = wrv.getChildAt(2);
+        View child4 = wrv.getChildAt(3);
+        View child5 = wrv.getChildAt(4);
+
+        // When the child is updated by the curved offsetting helper
+        if (child1 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child1, wrv);
+        }
+        if (child2 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child2, wrv);
+        }
+        if (child3 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child3, wrv);
+        }
+        if (child4 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child4, wrv);
+        }
+        if (child5 != null) {
+            mCurvedOffsettingHelperUnderTest.updateChild(child5, wrv);
+        }
+        if (wrv.getResources().getConfiguration().isScreenRound()) {
+            // Then the left position and the translation of the child is modified if the screen is
+            // round
+            if (child1 != null) {
+                assertEquals(162 - offset, child1.getLeft(), 1);
+                assertEquals(-9.5, child1.getTranslationY(), 1);
+            }
+            if (child2 != null) {
+                assertEquals(129 - offset, child2.getLeft(), 1);
+                assertEquals(-16.7, child2.getTranslationY(), 1);
+            }
+            if (child3 != null) {
+                assertEquals(99 - offset, child3.getLeft(), 1);
+                assertEquals(-19.9, child3.getTranslationY(), 1);
+            }
+            if (child4 != null) {
+                assertEquals(76 - offset, child4.getLeft(), 1);
+                assertEquals(-17.9, child4.getTranslationY(), 1);
+            }
+            if (child5 != null) {
+                assertEquals(59 - offset, child5.getLeft(), 1);
+                assertEquals(-13, child5.getTranslationY(), 1);
+            }
+        } else {
+            // Then the child is not modified if the screen is not round.
+            if (child1 != null) {
+                assertEquals(0, child1.getLeft());
+                assertEquals(0.0f, child1.getTranslationY());
+            }
+            if (child2 != null) {
+                assertEquals(0, child2.getLeft());
+                assertEquals(0.0f, child2.getTranslationY());
+            }
+            if (child3 != null) {
+                assertEquals(0, child3.getLeft());
+                assertEquals(0.0f, child3.getTranslationY());
+            }
+            if (child4 != null) {
+                assertEquals(0, child4.getLeft());
+                assertEquals(0.0f, child4.getTranslationY());
+            }
+            if (child5 != null) {
+                assertEquals(0, child5.getLeft());
+                assertEquals(0.0f, child5.getTranslationY());
+            }
+        }
+    }
+
+    private abstract class ViewFetchingRunnable implements Runnable {
+        Map<Integer, View> mIdViewMap = new HashMap();
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/ScrollManagerTest.java b/wearable/tests/src/android/support/wearable/view/ScrollManagerTest.java
new file mode 100644
index 0000000..73b2bd0
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/ScrollManagerTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 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.wearable.view;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import static java.lang.Math.cos;
+import static java.lang.Math.sin;
+
+import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.view.util.WakeLockRule;
+import android.view.MotionEvent;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ScrollManagerTest {
+    private static final int TEST_WIDTH = 400;
+    private static final int TEST_HEIGHT = 400;
+    private static final int STEP_COUNT = 300;
+
+    private static final int EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE = 36;
+    private static final int EXPECTED_SCROLLS_FOR_CIRCULAR_GESTURE = 199;
+
+    @Rule
+    public final WakeLockRule wakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<WearableRecyclerViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(WearableRecyclerViewTestActivity.class, true, true);
+
+    @Mock
+    WearableRecyclerView mMockWearableRecyclerView;
+
+    ScrollManager mScrollManagerUnderTest;
+
+    @Before
+    public void setUp() throws Throwable {
+        MockitoAnnotations.initMocks(this);
+        mScrollManagerUnderTest = new ScrollManager();
+        mScrollManagerUnderTest.setRecyclerView(mMockWearableRecyclerView, TEST_WIDTH, TEST_HEIGHT);
+    }
+
+    @Test
+    public void testStraightUpScrollingGestureLeft() throws Throwable {
+        // Pretend to scroll in a straight line from center left to upper left
+        scroll(mScrollManagerUnderTest, 30, 30, 200, 150);
+        // The scroll manager should require the recycler view to scroll up and only up
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, 1);
+    }
+
+    @Test
+    public void testStraightDownScrollingGestureLeft() throws Throwable {
+        // Pretend to scroll in a straight line upper left to center left
+        scroll(mScrollManagerUnderTest, 30, 30, 150, 200);
+        // The scroll manager should require the recycler view to scroll down and only down
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, -1);
+    }
+
+    @Test
+    public void testStraightUpScrollingGestureRight() throws Throwable {
+        // Pretend to scroll in a straight line from center right to upper right
+        scroll(mScrollManagerUnderTest, 370, 370, 200, 150);
+        // The scroll manager should require the recycler view to scroll down and only down
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, -1);
+    }
+
+    @Test
+    public void testStraightDownScrollingGestureRight() throws Throwable {
+        // Pretend to scroll in a straight line upper right to center right
+        scroll(mScrollManagerUnderTest, 370, 370, 150, 200);
+        // The scroll manager should require the recycler view to scroll up and only up
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_STRAIGHT_GESTURE))
+                .scrollBy(0, 1);
+    }
+
+    @Test
+    public void testCircularScrollingGestureLeft() throws Throwable {
+        // Pretend to scroll in an arch from center left to center right
+        scrollOnArch(mScrollManagerUnderTest, 30, 200, 180.0f);
+        // The scroll manager should never reverse the scroll direction and scroll up
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_CIRCULAR_GESTURE))
+                .scrollBy(0, 1);
+    }
+
+    @Test
+    public void testCircularScrollingGestureRight() throws Throwable {
+        // Pretend to scroll in an arch from center left to center right
+        scrollOnArch(mScrollManagerUnderTest, 370, 200, -180.0f);
+        // The scroll manager should never reverse the scroll direction and scroll down.
+        verify(mMockWearableRecyclerView, times(EXPECTED_SCROLLS_FOR_CIRCULAR_GESTURE))
+                .scrollBy(0, -1);
+    }
+
+    private static void scroll(ScrollManager scrollManager, float fromX, float toX, float fromY,
+            float toY) {
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        float y = fromY;
+        float x = fromX;
+
+        float yStep = (toY - fromY) / STEP_COUNT;
+        float xStep = (toX - fromX) / STEP_COUNT;
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        scrollManager.onTouchEvent(event);
+        for (int i = 0; i < STEP_COUNT; ++i) {
+            y += yStep;
+            x += xStep;
+            eventTime = SystemClock.uptimeMillis();
+            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+            scrollManager.onTouchEvent(event);
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        scrollManager.onTouchEvent(event);
+    }
+
+    private static void scrollOnArch(ScrollManager scrollManager, float fromX, float fromY,
+            float deltaAngle) {
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        float stepAngle = deltaAngle / STEP_COUNT;
+        double relativeX = fromX - (TEST_WIDTH / 2);
+        double relativeY = fromY - (TEST_HEIGHT / 2);
+        float radius = (float) Math.sqrt(relativeX * relativeX + relativeY * relativeY);
+        float angle = getAngle(fromX, fromY, TEST_WIDTH, TEST_HEIGHT);
+
+        float y = fromY;
+        float x = fromX;
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        scrollManager.onTouchEvent(event);
+        for (int i = 0; i < STEP_COUNT; ++i) {
+            angle += stepAngle;
+            x = getX(angle, radius, TEST_WIDTH);
+            y = getY(angle, radius, TEST_HEIGHT);
+            eventTime = SystemClock.uptimeMillis();
+            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+            scrollManager.onTouchEvent(event);
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        scrollManager.onTouchEvent(event);
+    }
+
+    private static float getX(double angle, double radius, double viewWidth) {
+        double radianAngle = Math.toRadians(angle - 90);
+        double relativeX = cos(radianAngle) * radius;
+        return (float) (relativeX + (viewWidth / 2));
+    }
+
+    private static float getY(double angle, double radius, double viewHeight) {
+        double radianAngle = Math.toRadians(angle - 90);
+        double relativeY = sin(radianAngle) * radius;
+        return (float) (relativeY + (viewHeight / 2));
+    }
+
+    private static float getAngle(double x, double y, double viewWidth, double viewHeight) {
+        double relativeX = x - (viewWidth / 2);
+        double relativeY = y - (viewHeight / 2);
+        double rowAngle = Math.atan2(relativeX, relativeY);
+        double angle = -Math.toDegrees(rowAngle) - 180;
+        if (angle < 0) {
+            angle += 360;
+        }
+        return (float) angle;
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTest.java b/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTest.java
index 3b0ae41..b595138 100644
--- a/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTest.java
+++ b/wearable/tests/src/android/support/wearable/view/SwipeDismissFrameLayoutTest.java
@@ -218,8 +218,7 @@
     @SmallTest
     public void testSwipeDoesNotDismissViewIfStartsInWrongPosition() {
         // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned on, but only for an
-      // inner
-        // circle.
+        // inner circle.
         setUpSwipeableRegion();
         // WHEN we perform a swipe to dismiss from the left edge of the screen.
         onView(withId(R.id.swipe_dismiss_root)).perform(swipeRightFromLeftEdge());
@@ -231,8 +230,7 @@
     @SmallTest
     public void testSwipeDoesDismissViewIfStartsInRightPosition() {
         // GIVEN a freshly setup SwipeDismissFrameLayout with dismiss turned on, but only for an
-      // inner
-        // circle.
+        // inner circle.
         setUpSwipeableRegion();
         // WHEN we perform a swipe to dismiss from the center of the screen.
         onView(withId(R.id.swipe_dismiss_root)).perform(swipeRightFromCenter());
diff --git a/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTest.java b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTest.java
new file mode 100644
index 0000000..82a731d
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2017 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.wearable.view;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.wearable.view.util.AsyncViewActions.waitForMatchingView;
+import static android.support.wearable.view.util.MoreViewAssertions.withNoVerticalScrollOffset;
+import static android.support.wearable.view.util.MoreViewAssertions.withPositiveVerticalScrollOffset;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.support.annotation.IdRes;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.GeneralLocation;
+import android.support.test.espresso.action.GeneralSwipeAction;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swipe;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wearable.test.R;
+import android.support.wearable.view.util.WakeLockRule;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WearableRecyclerViewTest {
+
+    private static final long MAX_WAIT_TIME = 10000;
+    @Mock
+    WearableRecyclerView.OffsettingHelper mMockOffsettingHelper;
+
+    @Rule
+    public final WakeLockRule wakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<WearableRecyclerViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(WearableRecyclerViewTestActivity.class, true, true);
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testCaseInitState() {
+        WearableRecyclerView wrv = new WearableRecyclerView(mActivityRule.getActivity());
+
+        assertFalse(wrv.getEdgeItemsCenteringEnabled());
+        assertFalse(wrv.isCircularScrollingGestureEnabled());
+        assertNull(wrv.getOffsettingHelper());
+        assertEquals(1.0f, wrv.getBezelWidthFraction());
+        assertEquals(180.0f, wrv.getScrollDegreesPerScreen());
+    }
+
+    @Test
+    public void testEdgeItemsCenteringOnAndOff() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setEdgeItemsCenteringEnabled(true);
+            }
+        });
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                View child = wrv.getChildAt(0);
+                assertNotNull("child", child);
+                assertEquals((wrv.getHeight() - child.getHeight()) / 2, child.getTop());
+            }
+        });
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setEdgeItemsCenteringEnabled(false);
+            }
+        });
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                View child = wrv.getChildAt(0);
+                assertNotNull("child", child);
+                assertEquals(0, child.getTop());
+
+            }
+        });
+    }
+
+    @Test
+    public void testCircularScrollingGesture() throws Throwable {
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+        assertNotScrolledY(R.id.wrv);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setCircularScrollingGestureEnabled(true);
+            }
+        });
+
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+        assertScrolledY(R.id.wrv);
+    }
+
+    @Test
+    public void testOffsettingHelper() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setOffsettingHelper(mMockOffsettingHelper);
+            }
+        });
+
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+        verify(mMockOffsettingHelper, atLeast(1)).updateChild(any(View.class),
+                any(WearableRecyclerView.class));
+
+    }
+
+    @Test
+    public void testCurvedOffsettingHelper() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                WearableRecyclerView wrv =
+                        (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv);
+                wrv.setOffsettingHelper(new CurvedOffsettingHelper());
+            }
+        });
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        onView(withId(R.id.wrv)).perform(swipeDownFromTopRight());
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Activity activity = mActivityRule.getActivity();
+                WearableRecyclerView wrv = (WearableRecyclerView) activity.findViewById(R.id.wrv);
+                if (activity.getResources().getConfiguration().isScreenRound()) {
+                    View child = wrv.getChildAt(0);
+                    assertTrue(child.getLeft() > 0);
+                } else {
+                    for (int i = 0; i < wrv.getChildCount(); i++) {
+                        assertEquals(0, wrv.getChildAt(i).getLeft());
+                    }
+                }
+            }
+        });
+    }
+
+    private static ViewAction swipeDownFromTopRight() {
+        return new GeneralSwipeAction(
+                Swipe.FAST, GeneralLocation.TOP_RIGHT, GeneralLocation.BOTTOM_RIGHT,
+                Press.FINGER);
+    }
+
+    private void assertScrolledY(@IdRes int layoutId) {
+        onView(withId(layoutId)).perform(waitForMatchingView(
+                allOf(withId(layoutId), withPositiveVerticalScrollOffset()), MAX_WAIT_TIME));
+    }
+
+    private void assertNotScrolledY(@IdRes int layoutId) {
+        onView(withId(layoutId)).perform(waitForMatchingView(
+                allOf(withId(layoutId), withNoVerticalScrollOffset()), MAX_WAIT_TIME));
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTestActivity.java b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTestActivity.java
new file mode 100644
index 0000000..1c4c8be
--- /dev/null
+++ b/wearable/tests/src/android/support/wearable/view/WearableRecyclerViewTestActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 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.wearable.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.support.wearable.test.R;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class WearableRecyclerViewTestActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.wearable_recycler_view_basic);
+        WearableRecyclerView wrv =
+                (WearableRecyclerView) findViewById(android.support.wearable.test.R.id.wrv);
+        wrv.setAdapter(new TestAdapter());
+    }
+
+    private class ViewHolder extends RecyclerView.ViewHolder {
+        TextView mView;
+        ViewHolder(TextView itemView) {
+            super(itemView);
+            mView = itemView;
+        }
+    }
+
+    private class TestAdapter extends WearableRecyclerView.Adapter<ViewHolder> {
+
+        @Override
+        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            TextView view = new TextView(parent.getContext());
+            return new ViewHolder(view);
+        }
+
+        @Override
+        public void onBindViewHolder(ViewHolder holder, int position) {
+            holder.mView.setText("holder at position " + position);
+            holder.mView.setTag(position);
+        }
+
+        @Override
+        public int getItemCount() {
+            return 100;
+        }
+    }
+}
diff --git a/wearable/tests/src/android/support/wearable/view/util/MoreViewAssertions.java b/wearable/tests/src/android/support/wearable/view/util/MoreViewAssertions.java
index 929593a..79586ea 100644
--- a/wearable/tests/src/android/support/wearable/view/util/MoreViewAssertions.java
+++ b/wearable/tests/src/android/support/wearable/view/util/MoreViewAssertions.java
@@ -21,7 +21,7 @@
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.ViewAssertion;
 import android.support.test.espresso.util.HumanReadables;
-import android.util.Log;
+import android.support.wearable.view.WearableRecyclerView;
 import android.view.View;
 
 import org.hamcrest.Description;
@@ -30,13 +30,10 @@
 
 public class MoreViewAssertions {
 
-    public static final String TAG = "bilt";
-
     public static ViewAssertion left(final Matcher<Integer> matcher) {
         return new ViewAssertion() {
             @Override
             public void check(View view, NoMatchingViewException noViewException) {
-                Log.d(TAG, "l: " + view.getLeft());
                 assertThat("View left: " + HumanReadables.describe(view), view.getLeft(), matcher);
             }
         };
@@ -46,7 +43,6 @@
         return new ViewAssertion() {
             @Override
             public void check(View view, NoMatchingViewException noViewException) {
-                Log.d(TAG, "t: " + view.getPaddingTop());
                 assertThat("View top: " + HumanReadables.describe(view), ((double) view.getTop()),
                         matcher);
             }
@@ -57,7 +53,6 @@
         return new ViewAssertion() {
             @Override
             public void check(View view, NoMatchingViewException noViewException) {
-                Log.d(TAG, "t: " + view.getPaddingTop());
                 assertThat("View top: " + HumanReadables.describe(view), view.getTop(), matcher);
             }
         };
@@ -67,7 +62,6 @@
         return new ViewAssertion() {
             @Override
             public void check(View view, NoMatchingViewException noViewException) {
-                Log.d(TAG, "r: " + view.getPaddingRight());
                 assertThat("View right: " + HumanReadables.describe(view), view.getRight(),
                         matcher);
             }
@@ -78,7 +72,6 @@
         return new ViewAssertion() {
             @Override
             public void check(View view, NoMatchingViewException noViewException) {
-                Log.d(TAG, "b: " + view.getBottom());
                 assertThat("View bottom: " + HumanReadables.describe(view), view.getBottom(),
                         matcher);
             }
@@ -89,7 +82,6 @@
         return new ViewAssertion() {
             @Override
             public void check(View view, NoMatchingViewException noViewException) {
-                Log.d(TAG, "b: " + view.getBottom());
                 assertThat("View bottom: " + HumanReadables.describe(view), ((double) view
                         .getBottom()), matcher);
             }
@@ -184,4 +176,32 @@
             }
         };
     }
+
+    public static Matcher<WearableRecyclerView> withPositiveVerticalScrollOffset() {
+        return new TypeSafeMatcher<WearableRecyclerView>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("with positive y scroll offset");
+            }
+
+            @Override
+            public boolean matchesSafely(WearableRecyclerView view) {
+                return view.computeVerticalScrollOffset() > 0;
+            }
+        };
+    }
+
+    public static Matcher<WearableRecyclerView> withNoVerticalScrollOffset() {
+        return new TypeSafeMatcher<WearableRecyclerView>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("with no y scroll offset");
+            }
+
+            @Override
+            public boolean matchesSafely(WearableRecyclerView view) {
+                return view.computeVerticalScrollOffset() == 0;
+            }
+        };
+    }
 }