1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.transition; 18 19import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 20 21import android.graphics.Rect; 22import android.support.annotation.NonNull; 23import android.support.annotation.RestrictTo; 24import android.support.v4.app.FragmentTransitionImpl; 25import android.view.View; 26import android.view.ViewGroup; 27 28import java.util.ArrayList; 29import java.util.List; 30 31 32/** 33 * @hide 34 */ 35// This is instantiated in android.support.v4.app.FragmentTransition 36@SuppressWarnings("unused") 37@RestrictTo(LIBRARY_GROUP) 38public class FragmentTransitionSupport extends FragmentTransitionImpl { 39 40 @Override 41 public boolean canHandle(Object transition) { 42 return transition instanceof Transition; 43 } 44 45 @Override 46 public Object cloneTransition(Object transition) { 47 Transition copy = null; 48 if (transition != null) { 49 copy = ((Transition) transition).clone(); 50 } 51 return copy; 52 } 53 54 @Override 55 public Object wrapTransitionInSet(Object transition) { 56 if (transition == null) { 57 return null; 58 } 59 TransitionSet transitionSet = new TransitionSet(); 60 transitionSet.addTransition((Transition) transition); 61 return transitionSet; 62 } 63 64 @Override 65 public void setSharedElementTargets(Object transitionObj, 66 View nonExistentView, ArrayList<View> sharedViews) { 67 TransitionSet transition = (TransitionSet) transitionObj; 68 final List<View> views = transition.getTargets(); 69 views.clear(); 70 final int count = sharedViews.size(); 71 for (int i = 0; i < count; i++) { 72 final View view = sharedViews.get(i); 73 bfsAddViewChildren(views, view); 74 } 75 views.add(nonExistentView); 76 sharedViews.add(nonExistentView); 77 addTargets(transition, sharedViews); 78 } 79 80 @Override 81 public void setEpicenter(Object transitionObj, View view) { 82 if (view != null) { 83 Transition transition = (Transition) transitionObj; 84 final Rect epicenter = new Rect(); 85 getBoundsOnScreen(view, epicenter); 86 87 transition.setEpicenterCallback(new Transition.EpicenterCallback() { 88 @Override 89 public Rect onGetEpicenter(@NonNull Transition transition) { 90 return epicenter; 91 } 92 }); 93 } 94 } 95 96 @Override 97 public void addTargets(Object transitionObj, ArrayList<View> views) { 98 Transition transition = (Transition) transitionObj; 99 if (transition == null) { 100 return; 101 } 102 if (transition instanceof TransitionSet) { 103 TransitionSet set = (TransitionSet) transition; 104 int numTransitions = set.getTransitionCount(); 105 for (int i = 0; i < numTransitions; i++) { 106 Transition child = set.getTransitionAt(i); 107 addTargets(child, views); 108 } 109 } else if (!hasSimpleTarget(transition)) { 110 List<View> targets = transition.getTargets(); 111 if (isNullOrEmpty(targets)) { 112 // We can just add the target views 113 int numViews = views.size(); 114 for (int i = 0; i < numViews; i++) { 115 transition.addTarget(views.get(i)); 116 } 117 } 118 } 119 } 120 121 private static boolean hasSimpleTarget(Transition transition) { 122 return !isNullOrEmpty(transition.getTargetIds()) 123 || !isNullOrEmpty(transition.getTargetNames()) 124 || !isNullOrEmpty(transition.getTargetTypes()); 125 } 126 127 @Override 128 public Object mergeTransitionsTogether(Object transition1, Object transition2, 129 Object transition3) { 130 TransitionSet transitionSet = new TransitionSet(); 131 if (transition1 != null) { 132 transitionSet.addTransition((Transition) transition1); 133 } 134 if (transition2 != null) { 135 transitionSet.addTransition((Transition) transition2); 136 } 137 if (transition3 != null) { 138 transitionSet.addTransition((Transition) transition3); 139 } 140 return transitionSet; 141 } 142 143 @Override 144 public void scheduleHideFragmentView(Object exitTransitionObj, final View fragmentView, 145 final ArrayList<View> exitingViews) { 146 Transition exitTransition = (Transition) exitTransitionObj; 147 exitTransition.addListener(new Transition.TransitionListener() { 148 @Override 149 public void onTransitionStart(@NonNull Transition transition) { 150 } 151 152 @Override 153 public void onTransitionEnd(@NonNull Transition transition) { 154 transition.removeListener(this); 155 fragmentView.setVisibility(View.GONE); 156 final int numViews = exitingViews.size(); 157 for (int i = 0; i < numViews; i++) { 158 exitingViews.get(i).setVisibility(View.VISIBLE); 159 } 160 } 161 162 @Override 163 public void onTransitionCancel(@NonNull Transition transition) { 164 } 165 166 @Override 167 public void onTransitionPause(@NonNull Transition transition) { 168 } 169 170 @Override 171 public void onTransitionResume(@NonNull Transition transition) { 172 } 173 }); 174 } 175 176 @Override 177 public Object mergeTransitionsInSequence(Object exitTransitionObj, 178 Object enterTransitionObj, Object sharedElementTransitionObj) { 179 // First do exit, then enter, but allow shared element transition to happen 180 // during both. 181 Transition staggered = null; 182 final Transition exitTransition = (Transition) exitTransitionObj; 183 final Transition enterTransition = (Transition) enterTransitionObj; 184 final Transition sharedElementTransition = (Transition) sharedElementTransitionObj; 185 if (exitTransition != null && enterTransition != null) { 186 staggered = new TransitionSet() 187 .addTransition(exitTransition) 188 .addTransition(enterTransition) 189 .setOrdering(TransitionSet.ORDERING_SEQUENTIAL); 190 } else if (exitTransition != null) { 191 staggered = exitTransition; 192 } else if (enterTransition != null) { 193 staggered = enterTransition; 194 } 195 if (sharedElementTransition != null) { 196 TransitionSet together = new TransitionSet(); 197 if (staggered != null) { 198 together.addTransition(staggered); 199 } 200 together.addTransition(sharedElementTransition); 201 return together; 202 } else { 203 return staggered; 204 } 205 } 206 207 @Override 208 public void beginDelayedTransition(ViewGroup sceneRoot, Object transition) { 209 TransitionManager.beginDelayedTransition(sceneRoot, (Transition) transition); 210 } 211 212 @Override 213 public void scheduleRemoveTargets(final Object overallTransitionObj, 214 final Object enterTransition, final ArrayList<View> enteringViews, 215 final Object exitTransition, final ArrayList<View> exitingViews, 216 final Object sharedElementTransition, final ArrayList<View> sharedElementsIn) { 217 final Transition overallTransition = (Transition) overallTransitionObj; 218 overallTransition.addListener(new Transition.TransitionListener() { 219 @Override 220 public void onTransitionStart(@NonNull Transition transition) { 221 if (enterTransition != null) { 222 replaceTargets(enterTransition, enteringViews, null); 223 } 224 if (exitTransition != null) { 225 replaceTargets(exitTransition, exitingViews, null); 226 } 227 if (sharedElementTransition != null) { 228 replaceTargets(sharedElementTransition, sharedElementsIn, null); 229 } 230 } 231 232 @Override 233 public void onTransitionEnd(@NonNull Transition transition) { 234 } 235 236 @Override 237 public void onTransitionCancel(@NonNull Transition transition) { 238 } 239 240 @Override 241 public void onTransitionPause(@NonNull Transition transition) { 242 } 243 244 @Override 245 public void onTransitionResume(@NonNull Transition transition) { 246 } 247 }); 248 } 249 250 @Override 251 public void swapSharedElementTargets(Object sharedElementTransitionObj, 252 ArrayList<View> sharedElementsOut, ArrayList<View> sharedElementsIn) { 253 TransitionSet sharedElementTransition = (TransitionSet) sharedElementTransitionObj; 254 if (sharedElementTransition != null) { 255 sharedElementTransition.getTargets().clear(); 256 sharedElementTransition.getTargets().addAll(sharedElementsIn); 257 replaceTargets(sharedElementTransition, sharedElementsOut, sharedElementsIn); 258 } 259 } 260 261 @Override 262 public void replaceTargets(Object transitionObj, ArrayList<View> oldTargets, 263 ArrayList<View> newTargets) { 264 Transition transition = (Transition) transitionObj; 265 if (transition instanceof TransitionSet) { 266 TransitionSet set = (TransitionSet) transition; 267 int numTransitions = set.getTransitionCount(); 268 for (int i = 0; i < numTransitions; i++) { 269 Transition child = set.getTransitionAt(i); 270 replaceTargets(child, oldTargets, newTargets); 271 } 272 } else if (!hasSimpleTarget(transition)) { 273 List<View> targets = transition.getTargets(); 274 if (targets.size() == oldTargets.size() 275 && targets.containsAll(oldTargets)) { 276 // We have an exact match. We must have added these earlier in addTargets 277 final int targetCount = newTargets == null ? 0 : newTargets.size(); 278 for (int i = 0; i < targetCount; i++) { 279 transition.addTarget(newTargets.get(i)); 280 } 281 for (int i = oldTargets.size() - 1; i >= 0; i--) { 282 transition.removeTarget(oldTargets.get(i)); 283 } 284 } 285 } 286 } 287 288 @Override 289 public void addTarget(Object transitionObj, View view) { 290 if (transitionObj != null) { 291 Transition transition = (Transition) transitionObj; 292 transition.addTarget(view); 293 } 294 } 295 296 @Override 297 public void removeTarget(Object transitionObj, View view) { 298 if (transitionObj != null) { 299 Transition transition = (Transition) transitionObj; 300 transition.removeTarget(view); 301 } 302 } 303 304 @Override 305 public void setEpicenter(Object transitionObj, final Rect epicenter) { 306 if (transitionObj != null) { 307 Transition transition = (Transition) transitionObj; 308 transition.setEpicenterCallback(new Transition.EpicenterCallback() { 309 @Override 310 public Rect onGetEpicenter(@NonNull Transition transition) { 311 if (epicenter == null || epicenter.isEmpty()) { 312 return null; 313 } 314 return epicenter; 315 } 316 }); 317 } 318 } 319 320} 321