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