Merge "Bump minSdk to 9 everywhere where it was < 9"
diff --git a/build.gradle b/build.gradle
index a58ad47..3c11c7e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,7 +9,7 @@
         maven { url "../../prebuilts/maven_repo/android" }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.0-alpha1'
+        classpath 'com.android.tools.build:gradle:2.1.0-alpha4'
     }
 }
 
diff --git a/customtabs/api/current.txt b/customtabs/api/current.txt
index 556da16..9b24129 100644
--- a/customtabs/api/current.txt
+++ b/customtabs/api/current.txt
@@ -14,7 +14,10 @@
 
   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);
   }
diff --git a/customtabs/src/android/support/customtabs/CustomTabsClient.java b/customtabs/src/android/support/customtabs/CustomTabsClient.java
index 7cc5c76..75e99bd 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsClient.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsClient.java
@@ -20,11 +20,15 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.support.annotation.Nullable;
 import android.text.TextUtils;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -62,7 +66,95 @@
     }
 
     /**
+     * Returns the preferred package to use for Custom Tabs, preferring the default VIEW handler.
+     *
+     * @see {@link #getPackageName(Context, List<String>, boolean)}.
+     */
+    public static String getPackageName(Context context, @Nullable List<String> packages) {
+        return getPackageName(context, packages, false);
+    }
+
+    /**
+     * Returns the preferred package to use for Custom Tabs.
+     *
+     * Unless <code>ignoreDefault</code> is true, if the default VIEW handler supports Custom Tabs,
+     * its package name will be returned, irrespective of the content of <code>packages</code>.
+     *
+     * @param context       {@link Context} to use for querying the packages.
+     * @param packages      Ordered list of packages to test for Custom Tabs support, in
+     *                      decreasing order of priority.
+     * @param ignoreDefault If set, don't systematically prefer the default VIEW handler.
+     * @return The preferred package name for handling Custom Tabs, or <code>null</code>.
+     */
+    public static String getPackageName(
+        Context context, @Nullable List<String> packages, boolean ignoreDefault) {
+        PackageManager pm = context.getPackageManager();
+
+        List<String> packageNames = packages == null ? new ArrayList<String>() : packages;
+        Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));
+
+        if (!ignoreDefault) {
+            ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
+            if (defaultViewHandlerInfo != null) {
+                String packageName = defaultViewHandlerInfo.activityInfo.packageName;
+                packageNames = new ArrayList<String>(packageNames.size() + 1);
+                packageNames.add(packageName);
+                if (packages != null) packageNames.addAll(packages);
+            }
+        }
+
+        Intent serviceIntent = new Intent(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
+        for (String packageName : packageNames) {
+            serviceIntent.setPackage(packageName);
+            if (pm.resolveService(serviceIntent, 0) != null) return packageName;
+        }
+        return null;
+    }
+
+    /**
+     * Connects to the Custom Tabs warmup service, and initializes the browser.
+     *
+     * This convenience method connects to the service, and immediately warms up the Custom Tabs
+     * implementation. Since service connection is asynchronous, the return code is not the return
+     * code of warmup.
+     * This call is optional, and clients are encouraged to connect to the service, call
+     * <code>warmup()</code> and create a session. In this case, calling this method is not
+     * necessary.
+     *
+     * @param context     {@link Context} to use to connect to the remote service.
+     * @param packageName Package name of the target implamentation.
+     * @return Whether the binding was successful.
+     */
+    public static boolean connectAndInitialize(Context context, String packageName) {
+        if (packageName == null) return false;
+        final Context applicationContext = context.getApplicationContext();
+        CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
+            @Override
+            public final void onCustomTabsServiceConnected(
+                    ComponentName name, CustomTabsClient client) {
+                client.warmup(0);
+                // Unbinding immediately makes the target process "Empty", provided that it is
+                // not used by anyone else, and doesn't contain any Activity. This makes it
+                // likely to get killed, but is preferable to keeping the connection around.
+                applicationContext.unbindService(this);
+            }
+
+           @Override
+           public final void onServiceDisconnected(ComponentName componentName) { }
+        };
+        try {
+            return bindCustomTabsService(applicationContext, packageName, connection);
+        } catch (SecurityException e) {
+            return false;
+        }
+    }
+
+    /**
      * Warm up the browser process.
+     *
+     * Allows the browser application to pre-initialize itself in the background. Significantly
+     * speeds up URL opening in the browser. This is asynchronous and can be called several times.
+     *
      * @param flags Reserved for future use.
      * @return      Whether the warmup was successful.
      */
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
index 9e170f7..bfd0f14 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
@@ -616,22 +616,23 @@
             Animator navigatorFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
                     R.animator.lb_onboarding_page_indicator_fade_out);
             navigatorFadeOutAnimator.setTarget(mPageIndicator);
-            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
-                    R.animator.lb_onboarding_start_button_fade_in);
-            buttonFadeInAnimator.setTarget(mStartButton);
-            animators.add(navigatorFadeOutAnimator);
             navigatorFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     mPageIndicator.setVisibility(View.GONE);
                 }
             });
+            animators.add(navigatorFadeOutAnimator);
+            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
+                    R.animator.lb_onboarding_start_button_fade_in);
+            buttonFadeInAnimator.setTarget(mStartButton);
             animators.add(buttonFadeInAnimator);
         } else if (previousPage == getPageCount() - 1) {
             mPageIndicator.setVisibility(View.VISIBLE);
             Animator navigatorFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
                     R.animator.lb_onboarding_page_indicator_fade_in);
             navigatorFadeInAnimator.setTarget(mPageIndicator);
+            animators.add(navigatorFadeInAnimator);
             Animator buttonFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
                     R.animator.lb_onboarding_start_button_fade_out);
             buttonFadeOutAnimator.setTarget(mStartButton);
@@ -641,9 +642,7 @@
                     mStartButton.setVisibility(View.GONE);
                 }
             });
-            mAnimator = new AnimatorSet();
-            mAnimator.playTogether(navigatorFadeInAnimator, buttonFadeOutAnimator);
-            mAnimator.start();
+            animators.add(buttonFadeOutAnimator);
         }
         mAnimator = new AnimatorSet();
         mAnimator.playTogether(animators);
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
index 4fc4718..d873f61 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
@@ -618,22 +618,23 @@
             Animator navigatorFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
                     R.animator.lb_onboarding_page_indicator_fade_out);
             navigatorFadeOutAnimator.setTarget(mPageIndicator);
-            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
-                    R.animator.lb_onboarding_start_button_fade_in);
-            buttonFadeInAnimator.setTarget(mStartButton);
-            animators.add(navigatorFadeOutAnimator);
             navigatorFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     mPageIndicator.setVisibility(View.GONE);
                 }
             });
+            animators.add(navigatorFadeOutAnimator);
+            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
+                    R.animator.lb_onboarding_start_button_fade_in);
+            buttonFadeInAnimator.setTarget(mStartButton);
             animators.add(buttonFadeInAnimator);
         } else if (previousPage == getPageCount() - 1) {
             mPageIndicator.setVisibility(View.VISIBLE);
             Animator navigatorFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
                     R.animator.lb_onboarding_page_indicator_fade_in);
             navigatorFadeInAnimator.setTarget(mPageIndicator);
+            animators.add(navigatorFadeInAnimator);
             Animator buttonFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
                     R.animator.lb_onboarding_start_button_fade_out);
             buttonFadeOutAnimator.setTarget(mStartButton);
@@ -643,9 +644,7 @@
                     mStartButton.setVisibility(View.GONE);
                 }
             });
-            mAnimator = new AnimatorSet();
-            mAnimator.playTogether(navigatorFadeInAnimator, buttonFadeOutAnimator);
-            mAnimator.start();
+            animators.add(buttonFadeOutAnimator);
         }
         mAnimator = new AnimatorSet();
         mAnimator.playTogether(animators);
diff --git a/v4/api/current.txt b/v4/api/current.txt
index d8c4df3..9921c59 100644
--- a/v4/api/current.txt
+++ b/v4/api/current.txt
@@ -536,6 +536,7 @@
     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";
@@ -664,6 +665,7 @@
     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);
diff --git a/v4/api24/android/support/v4/app/NotificationCompatApi24.java b/v4/api24/android/support/v4/app/NotificationCompatApi24.java
index 91ad8e4..f775255 100644
--- a/v4/api24/android/support/v4/app/NotificationCompatApi24.java
+++ b/v4/api24/android/support/v4/app/NotificationCompatApi24.java
@@ -57,7 +57,7 @@
                 boolean useChronometer, int priority, CharSequence subText, boolean localOnly,
                 String category, ArrayList<String> people, Bundle extras, int color,
                 int visibility, Notification publicVersion, String groupKey, boolean groupSummary,
-                String sortKey) {
+                String sortKey, CharSequence[] remoteInputHistory) {
             b = new Notification.Builder(context)
                     .setWhen(n.when)
                     .setShowWhen(showWhen)
@@ -92,7 +92,8 @@
                     .setCategory(category)
                     .setColor(color)
                     .setVisibility(visibility)
-                    .setPublicVersion(publicVersion);
+                    .setPublicVersion(publicVersion)
+                    .setRemoteInputHistory(remoteInputHistory);
             for (String person: people) {
                 b.addPerson(person);
             }
diff --git a/v4/java/android/support/v4/app/NotificationCompat.java b/v4/java/android/support/v4/app/NotificationCompat.java
index 819cd14..8b1bc10 100644
--- a/v4/java/android/support/v4/app/NotificationCompat.java
+++ b/v4/java/android/support/v4/app/NotificationCompat.java
@@ -220,6 +220,22 @@
     public static final String EXTRA_SUB_TEXT = "android.subText";
 
     /**
+     * Notification extras key: this is the remote input history, as supplied to
+     * {@link Builder#setRemoteInputHistory(CharSequence[])}.
+     *
+     * Apps can fill this through {@link Builder#setRemoteInputHistory(CharSequence[])}
+     * with the most recent inputs that have been sent through a {@link RemoteInput} of this
+     * Notification and are expected to clear it once the it is no longer relevant (e.g. for chat
+     * notifications once the other party has responded).
+     *
+     * The extra with this key is of type CharSequence[] and contains the most recent entry at
+     * the 0 index, the second most recent at the 1 index, etc.
+     *
+     * @see Builder#setRemoteInputHistory(CharSequence[])
+     */
+    public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+
+    /**
      * Notification extras key: this is a small piece of additional text as supplied to
      * {@link Builder#setContentInfo(CharSequence)}.
      */
@@ -837,7 +853,7 @@
                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
                     b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion,
-                    b.mGroupKey, b.mGroupSummary, b.mSortKey);
+                    b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mRemoteInputHistory);
             addActionsToBuilder(builder, b.mActions);
             addStyleToBuilderApi24(builder, b.mStyle);
             Notification notification = extender.build(b, builder);
@@ -992,6 +1008,8 @@
         public Style mStyle;
         /** @hide */
         public CharSequence mSubText;
+        /** @hide */
+        public CharSequence[] mRemoteInputHistory;
         int mProgressMax;
         int mProgress;
         boolean mProgressIndeterminate;
@@ -1125,6 +1143,25 @@
         }
 
         /**
+         * Set the remote input history.
+         *
+         * This should be set to the most recent inputs that have been sent
+         * through a {@link RemoteInput} of this Notification and cleared once the it is no
+         * longer relevant (e.g. for chat notifications once the other party has responded).
+         *
+         * The most recent input must be stored at the 0 index, the second most recent at the
+         * 1 index, etc. Note that the system will limit both how far back the inputs will be shown
+         * and how much of each individual input is shown.
+         *
+         * <p>Note: The reply text will only be shown on notifications that have least one action
+         * with a {@code RemoteInput}.</p>
+         */
+        public Builder setRemoteInputHistory(CharSequence[] text) {
+            mRemoteInputHistory = text;
+            return this;
+        }
+
+        /**
          * Set the large number at the right-hand side of the notification.  This is
          * equivalent to setContentInfo, although it might show the number in a different
          * font size for readability.
diff --git a/v4/java/android/support/v4/widget/MaterialProgressDrawable.java b/v4/java/android/support/v4/widget/MaterialProgressDrawable.java
index db46186..50939ad 100644
--- a/v4/java/android/support/v4/widget/MaterialProgressDrawable.java
+++ b/v4/java/android/support/v4/widget/MaterialProgressDrawable.java
@@ -16,11 +16,6 @@
 
 package android.support.v4.widget;
 
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.Animation;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.Transformation;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -32,13 +27,17 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.util.DisplayMetrics;
 import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.Transformation;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -54,7 +53,7 @@
     private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
 
     private static final float FULL_ROTATION = 1080.0f;
-    @Retention(RetentionPolicy.CLASS)
+    @Retention(RetentionPolicy.SOURCE)
     @IntDef({LARGE, DEFAULT})
     public @interface ProgressDrawableSize {}
     // Maps to ProgressBar.Large style