Fix NPE when a shared element doesn't have a matching transitionName.

Bug 33053923

Also added an early error check when the same shared element is
used for multiple shared elements in the source or target fragment.

Test: If5dfbac66cfd9e60660439ce5c519547de3ef1d0

Change-Id: Iac3ab8c1b8ea0208a0c76e043654184dd634948d
This commit is contained in:
George Mount
2016-11-21 16:33:22 -08:00
parent d4f9d37424
commit 4efeb4f4d4
2 changed files with 40 additions and 5 deletions

View File

@@ -534,6 +534,12 @@ final class BackStackRecord extends FragmentTransaction implements
if (mSharedElementSourceNames == null) {
mSharedElementSourceNames = new ArrayList<String>();
mSharedElementTargetNames = new ArrayList<String>();
} else if (mSharedElementTargetNames.contains(name)) {
throw new IllegalArgumentException("A shared element with the target name '"
+ name + "' has already been added to the transaction.");
} else if (mSharedElementSourceNames.contains(transitionName)) {
throw new IllegalArgumentException("A shared element with the source name '"
+ transitionName + " has already been added to the transaction.");
}
mSharedElementSourceNames.add(transitionName);
mSharedElementTargetNames.add(name);

View File

@@ -367,9 +367,11 @@ class FragmentTransition {
}
if (exitingViews != null) {
ArrayList<View> tempExiting = new ArrayList<>();
tempExiting.add(nonExistentView);
replaceTargets(exitTransition, exitingViews, tempExiting);
if (exitTransition != null) {
ArrayList<View> tempExiting = new ArrayList<>();
tempExiting.add(nonExistentView);
replaceTargets(exitTransition, exitingViews, tempExiting);
}
exitingViews.clear();
exitingViews.add(nonExistentView);
}
@@ -490,9 +492,17 @@ class FragmentTransition {
if (nameOverrides.isEmpty()) {
sharedElementTransition = null;
if (outSharedElements != null) {
outSharedElements.clear();
}
if (inSharedElements != null) {
inSharedElements.clear();
}
} else {
sharedElementsOut.addAll(outSharedElements.values());
sharedElementsIn.addAll(inSharedElements.values());
addSharedElementsWithMatchingNames(sharedElementsOut, outSharedElements,
nameOverrides.keySet());
addSharedElementsWithMatchingNames(sharedElementsIn, inSharedElements,
nameOverrides.values());
}
if (enterTransition == null && exitTransition == null && sharedElementTransition == null) {
@@ -537,6 +547,25 @@ class FragmentTransition {
return sharedElementTransition;
}
/**
* Add Views from sharedElements into views that have the transitionName in the
* nameOverridesSet.
*
* @param views Views list to add shared elements to
* @param sharedElements List of shared elements
* @param nameOverridesSet The transition names for all views to be copied from
* sharedElements to views.
*/
private static void addSharedElementsWithMatchingNames(ArrayList<View> views,
ArrayMap<String, View> sharedElements, Collection<String> nameOverridesSet) {
for (int i = sharedElements.size() - 1; i >= 0; i--) {
View view = sharedElements.valueAt(i);
if (view != null && nameOverridesSet.contains(view.getTransitionName())) {
views.add(view);
}
}
}
/**
* Configures the shared elements of an unoptimized fragment transaction's transition.
* This retrieves the shared elements of the incoming fragments, and schedules capturing