Merge "Backport endTransitions" into oc-support-26.0-dev
diff --git a/api/25.4.0-SNAPSHOT.ignore b/api/25.4.0.ignore
similarity index 100%
rename from api/25.4.0-SNAPSHOT.ignore
rename to api/25.4.0.ignore
diff --git a/api/25.4.0-SNAPSHOT.txt b/api/25.4.0.txt
similarity index 100%
rename from api/25.4.0-SNAPSHOT.txt
rename to api/25.4.0.txt
diff --git a/api/26.0.0-SNAPSHOT.txt b/api/26.0.0-SNAPSHOT.txt
index b2ef083..a38526f 100644
--- a/api/26.0.0-SNAPSHOT.txt
+++ b/api/26.0.0-SNAPSHOT.txt
@@ -10312,7 +10312,6 @@
   public abstract class AppCompatDelegate {
     method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public abstract boolean applyDayNight();
-    method public abstract boolean checkActionBarFocusKey(android.view.KeyEvent);
     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);
diff --git a/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy b/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
index 77a58f8..0ffd3d7 100644
--- a/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
+++ b/buildSrc/src/main/groovy/android/support/SupportLibraryPlugin.groovy
@@ -190,6 +190,7 @@
 
                             // Enforce the following checks.
                             '-Xep:MissingOverride:ERROR',
+                            '-Xep:ClassNewInstance:ERROR',
                     ]
                 }
             }
diff --git a/compat/res-public/values/public_attrs.xml b/compat/res-public/values/public_attrs.xml
index eb60607..e45f8c2 100644
--- a/compat/res-public/values/public_attrs.xml
+++ b/compat/res-public/values/public_attrs.xml
@@ -21,8 +21,8 @@
      <public type="attr" name="fontProviderPackage"/>
      <public type="attr" name="fontProviderQuery"/>
      <public type="attr" name="fontProviderCerts"/>
-     <public type="attr" name="fontProviderStrategy"/>
-     <public type="attr" name="fontProviderTimeout"/>
+     <public type="attr" name="fontProviderFetchStrategy"/>
+     <public type="attr" name="fontProviderFetchTimeout"/>
      <public type="attr" name="fontStyle"/>
      <public type="attr" name="font"/>
      <public type="attr" name="fontWeight"/>
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index e5c52b3..2f87edf 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -627,7 +627,8 @@
             }
             if (defaultBehavior != null) {
                 try {
-                    result.setBehavior(defaultBehavior.value().newInstance());
+                    result.setBehavior(
+                            defaultBehavior.value().getDeclaredConstructor().newInstance());
                 } catch (Exception e) {
                     Log.e(TAG, "Default behavior class " + defaultBehavior.value().getName() +
                             " could not be instantiated. Did you forget a default constructor?", e);
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
index 3d9647a..78136e2 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
@@ -524,9 +524,6 @@
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        if (getDelegate().checkActionBarFocusKey(event)) {
-            return true;
-        }
         // Let support action bars open menus in response to the menu key prioritized over
         // the window handling it
         final int keyCode = event.getKeyCode();
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
index a2fac6f..5d0bf6b 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
@@ -31,13 +31,11 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.app.FragmentActivity;
-import android.support.v4.os.BuildCompat;
 import android.support.v4.view.WindowCompat;
 import android.support.v7.view.ActionMode;
 import android.support.v7.widget.Toolbar;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.KeyEvent;
 import android.view.MenuInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -196,9 +194,7 @@
 
     private static AppCompatDelegate create(Context context, Window window,
             AppCompatCallback callback) {
-        if (BuildCompat.isAtLeastO()) {
-            return new AppCompatDelegateImplO(context, window, callback);
-        } else if (Build.VERSION.SDK_INT >= 24) {
+        if (Build.VERSION.SDK_INT >= 24) {
             return new AppCompatDelegateImplN(context, window, callback);
         } else if (Build.VERSION.SDK_INT >= 23) {
             return new AppCompatDelegateImplV23(context, window, callback);
@@ -425,13 +421,6 @@
     public abstract void onSaveInstanceState(Bundle outState);
 
     /**
-     * Gives AppCompat an opportunity to send focus to the ActionBar.
-     *
-     * @return false if ActionBar was not focused.
-     */
-    public abstract boolean checkActionBarFocusKey(KeyEvent event);
-
-    /**
      * Allow AppCompat to apply the {@code night} and {@code notnight} resource qualifiers.
      *
      * <p>Doing this enables the
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
index 08271d0..5bb5ca6 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
@@ -294,26 +294,6 @@
         // no-op
     }
 
-    @Override
-    public boolean checkActionBarFocusKey(KeyEvent event) {
-        if (event.isCtrlPressed()
-                && event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') {
-            // Capture the Control-< and send focus to the ActionBar
-            final int action = event.getAction();
-            if (action == KeyEvent.ACTION_DOWN) {
-                final ActionBar actionBar = getSupportActionBar();
-                if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {
-                    mEatKeyUpEvent = true;
-                    return true;
-                }
-            } else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {
-                mEatKeyUpEvent = false;
-                return true;
-            }
-        }
-        return false;
-    }
-
     abstract void onTitleChanged(CharSequence title);
 
     final CharSequence getTitle() {
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplO.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplO.java
deleted file mode 100644
index 9a60612..0000000
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplO.java
+++ /dev/null
@@ -1,36 +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.v7.app;
-
-import android.content.Context;
-import android.support.annotation.RequiresApi;
-import android.view.KeyEvent;
-import android.view.Window;
-
-@RequiresApi(26)
-class AppCompatDelegateImplO extends AppCompatDelegateImplN {
-
-    AppCompatDelegateImplO(Context context, Window window, AppCompatCallback callback) {
-        super(context, window, callback);
-    }
-
-    @Override
-    public boolean checkActionBarFocusKey(KeyEvent event) {
-        // In O+, ActionBar's make use of cluster navigation instead of a specific hotkey
-        return false;
-    }
-}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
index c22207c..fc2b2ae 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
@@ -20,12 +20,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.os.Build;
 import android.os.SystemClock;
 import android.support.test.filters.SmallTest;
-import android.support.v4.os.BuildCompat;
 import android.support.v7.testutils.BaseTestActivity;
 import android.support.v7.widget.Toolbar;
-import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MenuItem;
 import android.view.View;
@@ -42,6 +41,10 @@
     @Test
     @SmallTest
     public void testAccessActionBar() throws Throwable {
+        // Since O, we rely on keyboard navigation clusters for jumping to actionbar
+        if (Build.VERSION.SDK_INT <= 25) {
+            return;
+        }
         final BaseTestActivity activity = getActivity();
 
         final View editText = activity.findViewById(android.support.v7.appcompat.test.R.id.editText);
@@ -53,15 +56,9 @@
         });
 
         getInstrumentation().waitForIdleSync();
-        if (BuildCompat.isAtLeastO()) {
-            // Since O, we rely on keyboard navigation clusters for jumping to actionbar
-            sendMetaKey(KeyEvent.KEYCODE_TAB);
-        } else {
-            sendControlChar('<');
-        }
+        sendMetaKey(KeyEvent.KEYCODE_TAB);
         getInstrumentation().waitForIdleSync();
 
-        // Should jump to the action bar after control-<
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -70,13 +67,10 @@
                 assertTrue(toolbar.hasFocus());
             }
         });
-        if (BuildCompat.isAtLeastO()) {
-            // Since O, we rely on keyboard navigation clusters for jumping out of actionbar since
-            // normal navigation no-longer leaves it.
-            sendMetaKey(KeyEvent.KEYCODE_TAB);
-        } else {
-            getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
-        }
+        // We rely on keyboard navigation clusters for jumping out of actionbar since normal
+        // navigation won't leaves it.
+        sendMetaKey(KeyEvent.KEYCODE_TAB);
+
         getInstrumentation().waitForIdleSync();
 
         // Should jump to the first view again.
@@ -147,19 +141,6 @@
         assertEquals(0, activity.mCreateMenuCount);
     }
 
-    private void sendControlChar(char key) throws Throwable {
-        KeyEvent tempEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
-        KeyCharacterMap map = tempEvent.getKeyCharacterMap();
-        KeyEvent[] events = map.getEvents(new char[] {key});
-        for (int i = 0; i < events.length; i++) {
-            long time = SystemClock.uptimeMillis();
-            KeyEvent event = events[i];
-            KeyEvent controlKey = new KeyEvent(time, time, event.getAction(), event.getKeyCode(),
-                    event.getRepeatCount(), event.getMetaState() | KeyEvent.META_CTRL_ON);
-            getInstrumentation().sendKeySync(controlKey);
-        }
-    }
-
     private void sendMetaKey(int keyCode) throws Throwable {
         long time = SystemClock.uptimeMillis();
         KeyEvent keyDown = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
diff --git a/v7/mediarouter/res/drawable/mr_button_dark_static.xml b/v7/mediarouter/res/drawable/mr_button_dark_static.xml
new file mode 100644
index 0000000..20cb447
--- /dev/null
+++ b/v7/mediarouter/res/drawable/mr_button_dark_static.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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+        android:drawable="@drawable/ic_mr_button_disconnected_dark" />
+    <item android:drawable="@drawable/ic_mr_button_disabled_dark" />
+</selector>
diff --git a/v7/mediarouter/res/drawable/mr_button_light_static.xml b/v7/mediarouter/res/drawable/mr_button_light_static.xml
new file mode 100644
index 0000000..9d805d1
--- /dev/null
+++ b/v7/mediarouter/res/drawable/mr_button_light_static.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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+        android:drawable="@drawable/ic_mr_button_disconnected_light" />
+    <item android:drawable="@drawable/ic_mr_button_disabled_light" />
+</selector>
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/res/values/attrs.xml
index e9f20a5..abd5815 100644
--- a/v7/mediarouter/res/values/attrs.xml
+++ b/v7/mediarouter/res/values/attrs.xml
@@ -21,6 +21,10 @@
              and non-checked / non-checkable indicates
              that media is playing to the local device only. -->
         <attr name="externalRouteEnabledDrawable" format="reference" />
+        <!-- This drawable is a static version of the above animation drawable.
+             In order to speed up inflation, the static drawable is loaded first and
+             the animation drawable will be loaded in a worker thread separately. -->
+        <attr name="externalRouteEnabledDrawableStatic" format="reference" />
         <!-- Tint to apply to the media route button -->
         <attr name="mediaRouteButtonTint" format="color" />
 
diff --git a/v7/mediarouter/res/values/styles.xml b/v7/mediarouter/res/values/styles.xml
index e8e00e7..2611804 100644
--- a/v7/mediarouter/res/values/styles.xml
+++ b/v7/mediarouter/res/values/styles.xml
@@ -17,11 +17,13 @@
 <resources>
     <style name="Widget.MediaRouter.MediaRouteButton"
             parent="Widget.AppCompat.ActionButton">
+        <item name="externalRouteEnabledDrawableStatic">@drawable/mr_button_dark_static</item>
         <item name="externalRouteEnabledDrawable">@drawable/mr_button_dark</item>
     </style>
 
     <style name="Widget.MediaRouter.Light.MediaRouteButton"
             parent="Widget.AppCompat.Light.ActionButton">
+        <item name="externalRouteEnabledDrawableStatic">@drawable/mr_button_light_static</item>
         <item name="externalRouteEnabledDrawable">@drawable/mr_button_light</item>
     </style>
 
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
index 22ab925..a7e8cb5 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
@@ -24,6 +24,7 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
 import android.support.annotation.NonNull;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
@@ -34,6 +35,7 @@
 import android.support.v7.widget.TooltipCompat;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.SoundEffectConstants;
 import android.view.View;
 
@@ -127,7 +129,22 @@
                 R.styleable.MediaRouteButton, defStyleAttr, 0);
         mButtonTint = a.getColorStateList(R.styleable.MediaRouteButton_mediaRouteButtonTint);
         setRemoteIndicatorDrawable(a.getDrawable(
-                R.styleable.MediaRouteButton_externalRouteEnabledDrawable));
+                R.styleable.MediaRouteButton_externalRouteEnabledDrawableStatic));
+        final TypedValue value = new TypedValue();
+        a.getValue(R.styleable.MediaRouteButton_externalRouteEnabledDrawable, value);
+        new AsyncTask<Void, Void, Drawable>() {
+            @Override
+            protected Drawable doInBackground(Void... params) {
+                return getContext().getResources().getDrawable(value.resourceId);
+            }
+
+            @Override
+            protected void onPostExecute(Drawable result) {
+                if (result != null) {
+                    setRemoteIndicatorDrawable(result);
+                }
+            }
+        }.execute();
         mMinWidth = a.getDimensionPixelSize(
                 R.styleable.MediaRouteButton_android_minWidth, 0);
         mMinHeight = a.getDimensionPixelSize(