Merge "Physics-based animation - SpringAnimation" into nyc-support-25.3-dev
diff --git a/exifinterface/src/android/support/media/ExifInterface.java b/exifinterface/src/android/support/media/ExifInterface.java
index 4830ecc..4ae0312 100644
--- a/exifinterface/src/android/support/media/ExifInterface.java
+++ b/exifinterface/src/android/support/media/ExifInterface.java
@@ -2971,9 +2971,9 @@
 
         if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) {
             long[] stripOffsets =
-                    (long[]) stripOffsetsAttribute.getValue(mExifByteOrder);
+                    convertToLongArray(stripOffsetsAttribute.getValue(mExifByteOrder));
             long[] stripByteCounts =
-                    (long[]) stripByteCountsAttribute.getValue(mExifByteOrder);
+                    convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
 
             if (stripOffsets == null) {
                 Log.w(TAG, "stripOffsets should not be null.");
@@ -3807,4 +3807,22 @@
         }
         return total;
     }
+
+    /**
+     * Convert given int[] to long[]. If long[] is given, just return it.
+     * Return null for other types of input.
+     */
+    private static long[] convertToLongArray(Object inputObj) {
+        if (inputObj instanceof int[]) {
+            int[] input = (int[]) inputObj;
+            long[] result = new long[input.length];
+            for (int i = 0; i < input.length; i++) {
+                result[i] = input[i];
+            }
+            return result;
+        } else if (inputObj instanceof long[]) {
+            return (long[]) inputObj;
+        }
+        return null;
+    }
 }
diff --git a/fragment/java/android/support/v4/app/FragmentTransition.java b/fragment/java/android/support/v4/app/FragmentTransition.java
index 5e0d9e3..f93a5c3 100644
--- a/fragment/java/android/support/v4/app/FragmentTransition.java
+++ b/fragment/java/android/support/v4/app/FragmentTransition.java
@@ -759,7 +759,9 @@
             names = inTransaction.mSharedElementTargetNames;
         }
 
-        inSharedElements.retainAll(names);
+        if (names != null) {
+            inSharedElements.retainAll(names);
+        }
         if (sharedElementCallback != null) {
             sharedElementCallback.onMapSharedElements(names, inSharedElements);
             for (int i = names.size() - 1; i >= 0; i--) {
@@ -809,7 +811,8 @@
             FragmentContainerTransition fragments,
             Object enterTransition, boolean inIsPop) {
         BackStackRecord inTransaction = fragments.lastInTransaction;
-        if (enterTransition != null && inTransaction.mSharedElementSourceNames != null
+        if (enterTransition != null && inSharedElements != null
+                && inTransaction.mSharedElementSourceNames != null
                 && !inTransaction.mSharedElementSourceNames.isEmpty()) {
             final String targetName = inIsPop
                     ? inTransaction.mSharedElementSourceNames.get(0)
@@ -898,7 +901,9 @@
         if (transition != null) {
             viewList = new ArrayList<>();
             View root = fragment.getView();
-            FragmentTransitionCompat21.captureTransitioningViews(viewList, root);
+            if (root != null) {
+                FragmentTransitionCompat21.captureTransitioningViews(viewList, root);
+            }
             if (sharedElements != null) {
                 viewList.removeAll(sharedElements);
             }
diff --git a/fragment/tests/java/android/support/v4/app/FragmentTransitionTest.java b/fragment/tests/java/android/support/v4/app/FragmentTransitionTest.java
index ab319b7..b255ee3 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentTransitionTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentTransitionTest.java
@@ -698,6 +698,73 @@
         verifyNoOtherTransitions(fragment);
     }
 
+    // No crash when transitioning a shared element and there is no shared element transition.
+    @Test
+    public void noSharedElementTransition() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+        final View midGreen = findGreen();
+        final View midBlue = findBlue();
+        final Rect midBlueBounds = getBoundsOnScreen(midBlue);
+        verifyAndClearTransition(fragment1.exitTransition, startBlueBounds, startGreen);
+        verifyAndClearTransition(fragment2.sharedElementEnter, startBlueBounds, startBlue, midBlue);
+        verifyAndClearTransition(fragment2.enterTransition, midBlueBounds, midGreen);
+        verifyNoOtherTransitions(fragment1);
+        verifyNoOtherTransitions(fragment2);
+
+        final TransitionFragment fragment3 = new TransitionFragment();
+        fragment3.setLayoutId(R.layout.scene3);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager();
+                fm.popBackStack();
+                fm.beginTransaction()
+                        .setAllowOptimization(mOptimize)
+                        .replace(R.id.fragmentContainer, fragment3)
+                        .addToBackStack(null)
+                        .commit();
+            }
+        });
+
+        // This shouldn't give an error.
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        fragment2.waitForTransition();
+        // It does not transition properly for unoptimized transactions, though.
+        if (mOptimize) {
+            verifyAndClearTransition(fragment2.returnTransition, null, midGreen, midBlue);
+            final View endGreen = findGreen();
+            final View endBlue = findBlue();
+            final View endRed = findRed();
+            verifyAndClearTransition(fragment3.enterTransition, null, endGreen, endBlue, endRed);
+            verifyNoOtherTransitions(fragment2);
+            verifyNoOtherTransitions(fragment3);
+        } else {
+            // fragment3 doesn't get a transition since it conflicts with the pop transition
+            verifyNoOtherTransitions(fragment3);
+            // Everything else is just doing its best. Unoptimized transactions can't handle
+            // multiple transitions acting together except for popping multiple together.
+        }
+    }
+
     private TransitionFragment setupInitialFragment() throws Throwable {
         TransitionFragment fragment1 = new TransitionFragment();
         fragment1.setLayoutId(R.layout.scene1);
diff --git a/samples/SupportLeanbackDemos/res/values/themes.xml b/samples/SupportLeanbackDemos/res/values/themes.xml
index 58ae373..e2292b5 100644
--- a/samples/SupportLeanbackDemos/res/values/themes.xml
+++ b/samples/SupportLeanbackDemos/res/values/themes.xml
@@ -14,7 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources>
+<resources xmlns:tools="http://schemas.android.com/tools" >
     <style name="Theme.Example.Leanback" parent="Theme.Leanback">
     </style>
     <style name="Theme.Example.Leanback.Browse" parent="Theme.Leanback.Browse">
@@ -45,8 +45,8 @@
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:backgroundDimEnabled">true</item>
-        <item name="android:colorPrimary">@color/settings_background</item>
-        <item name="android:colorAccent">?attr/defaultBrandColor</item>
+        <item name="android:colorPrimary" tools:targetApi="21" >@color/settings_background</item>
+        <item name="android:colorAccent" tools:targetApi="21">?attr/defaultBrandColor</item>
     </style>
     <style name="Theme.Example.Leanback.Onboarding" parent="Theme.Leanback.Onboarding">
         <item name="onboardingLogoStyle">@style/Widget.Example.Leanback.OnboardingLogoStyle</item>
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java
index 01bd583..4f8546e 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java
@@ -76,7 +76,7 @@
             String title = getString(R.string.guidedstep_second_title);
             String breadcrumb = getString(R.string.guidedstep_second_breadcrumb);
             String description = getString(R.string.guidedstep_second_description);
-            Drawable icon = getActivity().getDrawable(R.drawable.ic_main_icon);
+            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
             return new Guidance(title, description, breadcrumb, icon);
         }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
index 94f7d6c..a311338 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
@@ -403,8 +403,8 @@
 
         @Override
         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
-            addEditableAction(getContext(), actions, FIRST_NAME, "Pat", "Your first name");
-            addEditableAction(getContext(), actions, LAST_NAME, "Smith", "Your last name");
+            addEditableAction(getActivity(), actions, FIRST_NAME, "Pat", "Your first name");
+            addEditableAction(getActivity(), actions, LAST_NAME, "Smith", "Your last name");
             List<GuidedAction> subActions = new ArrayList<GuidedAction>();
             updatePaymentAction(addAction(actions, PAYMENT, "Select Payment", "", subActions));
             addEditableDescriptionAction(actions, PASSWORD, "Password", "", "",
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
index bb9aa1e..0cd6edd 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
@@ -406,8 +406,8 @@
 
         @Override
         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
-            addEditableAction(getContext(), actions, FIRST_NAME, "Pat", "Your first name");
-            addEditableAction(getContext(), actions, LAST_NAME, "Smith", "Your last name");
+            addEditableAction(getActivity(), actions, FIRST_NAME, "Pat", "Your first name");
+            addEditableAction(getActivity(), actions, LAST_NAME, "Smith", "Your last name");
             List<GuidedAction> subActions = new ArrayList<GuidedAction>();
             updatePaymentAction(addAction(actions, PAYMENT, "Select Payment", "", subActions));
             addEditableDescriptionAction(actions, PASSWORD, "Password", "", "",
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
index 9b48371..9b801dc 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
@@ -16,6 +16,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.app.DetailsFragmentBackgroundController;
@@ -76,8 +77,8 @@
             new DetailsFragmentBackgroundController(this);
 
     private void initializeTest() {
-        TEST_SHARED_ELEMENT_TRANSITION = null != getActivity().getWindow()
-                .getSharedElementEnterTransition();
+        TEST_SHARED_ELEMENT_TRANSITION = Build.VERSION.SDK_INT >= 21
+                && null != getActivity().getWindow().getSharedElementEnterTransition();
         TEST_OVERVIEW_ROW_ON_SECOND = !TEST_SHARED_ELEMENT_TRANSITION;
         TEST_ENTRANCE_TRANSITION = false;
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
index ef41be0..77ce368 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.app.DetailsSupportFragmentBackgroundController;
@@ -79,8 +80,8 @@
             new DetailsSupportFragmentBackgroundController(this);
 
     private void initializeTest() {
-        TEST_SHARED_ELEMENT_TRANSITION = null != getActivity().getWindow()
-                .getSharedElementEnterTransition();
+        TEST_SHARED_ELEMENT_TRANSITION = Build.VERSION.SDK_INT >= 21
+                && null != getActivity().getWindow().getSharedElementEnterTransition();
         TEST_OVERVIEW_ROW_ON_SECOND = !TEST_SHARED_ELEMENT_TRANSITION;
         TEST_ENTRANCE_TRANSITION = false;
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
index a29a995..91ecd62 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
@@ -17,6 +17,7 @@
 package com.example.android.leanback;
 
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.support.v17.leanback.app.PlaybackFragmentGlueHost;
 import android.support.v17.leanback.widget.Action;
@@ -86,7 +87,9 @@
             @Override
             public void onActionClicked(Action action) {
                 if (action.getId() == R.id.lb_control_picture_in_picture) {
-                    getActivity().enterPictureInPictureMode();
+                    if (Build.VERSION.SDK_INT >= 24) {
+                        getActivity().enterPictureInPictureMode();
+                    }
                     return;
                 }
                 super.onActionClicked(action);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index bca057f..8e9dde2 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -14,6 +14,7 @@
 package com.example.android.leanback;
 
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.Action;
@@ -123,7 +124,9 @@
             @Override
             public void onActionClicked(Action action) {
                 if (action.getId() == R.id.lb_control_picture_in_picture) {
-                    getActivity().enterPictureInPictureMode();
+                    if (Build.VERSION.SDK_INT >= 24) {
+                        getActivity().enterPictureInPictureMode();
+                    }
                     return;
                 }
                 super.onActionClicked(action);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
index b806a9a..f2de9a9 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
@@ -17,6 +17,7 @@
 package com.example.android.leanback;
 
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.Action;
@@ -126,7 +127,9 @@
             @Override
             public void onActionClicked(Action action) {
                 if (action.getId() == R.id.lb_control_picture_in_picture) {
-                    getActivity().enterPictureInPictureMode();
+                    if (Build.VERSION.SDK_INT >= 24) {
+                        getActivity().enterPictureInPictureMode();
+                    }
                     return;
                 }
                 super.onActionClicked(action);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
index 6d2fa51..64effab 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
@@ -20,6 +20,7 @@
 package com.example.android.leanback;
 
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.support.v17.leanback.app.PlaybackSupportFragmentGlueHost;
 import android.support.v17.leanback.widget.Action;
@@ -89,7 +90,9 @@
             @Override
             public void onActionClicked(Action action) {
                 if (action.getId() == R.id.lb_control_picture_in_picture) {
-                    getActivity().enterPictureInPictureMode();
+                    if (Build.VERSION.SDK_INT >= 24) {
+                        getActivity().enterPictureInPictureMode();
+                    }
                     return;
                 }
                 super.onActionClicked(action);