ActivityTransitionState.java revision 99c82fd1de23deeb8cf640bb574c76af76429df6
1/* 2 * Copyright (C) 2014 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 */ 16package android.app; 17 18import android.os.Bundle; 19import android.os.ResultReceiver; 20import android.transition.Transition; 21import android.util.ArrayMap; 22import android.util.SparseArray; 23import android.view.View; 24import android.view.ViewGroup; 25import android.view.Window; 26 27import java.lang.ref.WeakReference; 28import java.util.ArrayList; 29 30/** 31 * This class contains all persistence-related functionality for Activity Transitions. 32 * Activities start exit and enter Activity Transitions through this class. 33 */ 34class ActivityTransitionState { 35 36 private static final String ENTERING_SHARED_ELEMENTS = "android:enteringSharedElements"; 37 38 private static final String EXITING_MAPPED_FROM = "android:exitingMappedFrom"; 39 40 private static final String EXITING_MAPPED_TO = "android:exitingMappedTo"; 41 42 /** 43 * The shared elements that the calling Activity has said that they transferred to this 44 * Activity. 45 */ 46 private ArrayList<String> mEnteringNames; 47 48 /** 49 * The names of shared elements that were shared to the called Activity. 50 */ 51 private ArrayList<String> mExitingFrom; 52 53 /** 54 * The names of local Views that were shared out, mapped to those elements in mExitingFrom. 55 */ 56 private ArrayList<String> mExitingTo; 57 58 /** 59 * The local Views that were shared out, mapped to those elements in mExitingFrom. 60 */ 61 private ArrayList<View> mExitingToView; 62 63 /** 64 * The ExitTransitionCoordinator used to start an Activity. Used to make the elements restore 65 * Visibility of exited Views. 66 */ 67 private ExitTransitionCoordinator mCalledExitCoordinator; 68 69 /** 70 * We must be able to cancel entering transitions to stop changing the Window to 71 * opaque when we exit before making the Window opaque. 72 */ 73 private EnterTransitionCoordinator mEnterTransitionCoordinator; 74 75 /** 76 * ActivityOptions used on entering this Activity. 77 */ 78 private ActivityOptions mEnterActivityOptions; 79 80 /** 81 * Has an exit transition been started? If so, we don't want to double-exit. 82 */ 83 private boolean mHasExited; 84 85 /** 86 * Postpone painting and starting the enter transition until this is false. 87 */ 88 private boolean mIsEnterPostponed; 89 90 /** 91 * Potential exit transition coordinators. 92 */ 93 private SparseArray<WeakReference<ExitTransitionCoordinator>> mExitTransitionCoordinators; 94 95 /** 96 * Next key for mExitTransitionCoordinator. 97 */ 98 private int mExitTransitionCoordinatorsKey = 1; 99 100 private boolean mIsEnterTriggered; 101 102 public ActivityTransitionState() { 103 } 104 105 public int addExitTransitionCoordinator(ExitTransitionCoordinator exitTransitionCoordinator) { 106 if (mExitTransitionCoordinators == null) { 107 mExitTransitionCoordinators = 108 new SparseArray<WeakReference<ExitTransitionCoordinator>>(); 109 } 110 WeakReference<ExitTransitionCoordinator> ref = new WeakReference(exitTransitionCoordinator); 111 // clean up old references: 112 for (int i = mExitTransitionCoordinators.size() - 1; i >= 0; i--) { 113 WeakReference<ExitTransitionCoordinator> oldRef 114 = mExitTransitionCoordinators.valueAt(i); 115 if (oldRef.get() == null) { 116 mExitTransitionCoordinators.removeAt(i); 117 } 118 } 119 int newKey = mExitTransitionCoordinatorsKey++; 120 mExitTransitionCoordinators.append(newKey, ref); 121 return newKey; 122 } 123 124 public void readState(Bundle bundle) { 125 if (bundle != null) { 126 if (mEnterTransitionCoordinator == null || mEnterTransitionCoordinator.isReturning()) { 127 mEnteringNames = bundle.getStringArrayList(ENTERING_SHARED_ELEMENTS); 128 } 129 if (mEnterTransitionCoordinator == null) { 130 mExitingFrom = bundle.getStringArrayList(EXITING_MAPPED_FROM); 131 mExitingTo = bundle.getStringArrayList(EXITING_MAPPED_TO); 132 } 133 } 134 } 135 136 public void saveState(Bundle bundle) { 137 if (mEnteringNames != null) { 138 bundle.putStringArrayList(ENTERING_SHARED_ELEMENTS, mEnteringNames); 139 } 140 if (mExitingFrom != null) { 141 bundle.putStringArrayList(EXITING_MAPPED_FROM, mExitingFrom); 142 bundle.putStringArrayList(EXITING_MAPPED_TO, mExitingTo); 143 } 144 } 145 146 public void setEnterActivityOptions(Activity activity, ActivityOptions options) { 147 if (activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS) 148 && options != null && mEnterActivityOptions == null 149 && mEnterTransitionCoordinator == null 150 && options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { 151 mEnterActivityOptions = options; 152 mIsEnterTriggered = false; 153 if (mEnterActivityOptions.isReturning()) { 154 restoreExitedViews(); 155 int result = mEnterActivityOptions.getResultCode(); 156 if (result != 0) { 157 activity.onActivityReenter(result, mEnterActivityOptions.getResultData()); 158 } 159 } 160 } 161 } 162 163 public void enterReady(Activity activity) { 164 if (mEnterActivityOptions == null || mIsEnterTriggered) { 165 return; 166 } 167 mIsEnterTriggered = true; 168 mHasExited = false; 169 ArrayList<String> sharedElementNames = mEnterActivityOptions.getSharedElementNames(); 170 ResultReceiver resultReceiver = mEnterActivityOptions.getResultReceiver(); 171 if (mEnterActivityOptions.isReturning()) { 172 restoreExitedViews(); 173 activity.getWindow().getDecorView().setVisibility(View.VISIBLE); 174 } 175 mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity, 176 resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning()); 177 178 if (!mIsEnterPostponed) { 179 startEnter(); 180 } 181 } 182 183 public void postponeEnterTransition() { 184 mIsEnterPostponed = true; 185 } 186 187 public void startPostponedEnterTransition() { 188 if (mIsEnterPostponed) { 189 mIsEnterPostponed = false; 190 if (mEnterTransitionCoordinator != null) { 191 startEnter(); 192 } 193 } 194 } 195 196 private void startEnter() { 197 if (mEnterActivityOptions.isReturning()) { 198 if (mExitingToView != null) { 199 mEnterTransitionCoordinator.viewInstancesReady(mExitingFrom, mExitingTo, 200 mExitingToView); 201 } else { 202 mEnterTransitionCoordinator.namedViewsReady(mExitingFrom, mExitingTo); 203 } 204 } else { 205 mEnterTransitionCoordinator.namedViewsReady(null, null); 206 mEnteringNames = mEnterTransitionCoordinator.getAllSharedElementNames(); 207 } 208 209 mExitingFrom = null; 210 mExitingTo = null; 211 mExitingToView = null; 212 mEnterActivityOptions = null; 213 } 214 215 public void onStop() { 216 restoreExitedViews(); 217 if (mEnterTransitionCoordinator != null) { 218 mEnterTransitionCoordinator.stop(); 219 mEnterTransitionCoordinator = null; 220 } 221 } 222 223 public void onResume() { 224 restoreExitedViews(); 225 } 226 227 public void clear() { 228 mEnteringNames = null; 229 mExitingFrom = null; 230 mExitingTo = null; 231 mExitingToView = null; 232 mCalledExitCoordinator = null; 233 mEnterTransitionCoordinator = null; 234 mEnterActivityOptions = null; 235 mExitTransitionCoordinators = null; 236 } 237 238 private void restoreExitedViews() { 239 if (mCalledExitCoordinator != null) { 240 mCalledExitCoordinator.resetViews(); 241 mCalledExitCoordinator = null; 242 } 243 } 244 245 public boolean startExitBackTransition(Activity activity) { 246 if (mEnteringNames == null) { 247 return false; 248 } else { 249 if (!mHasExited) { 250 mHasExited = true; 251 Transition enterViewsTransition = null; 252 ViewGroup decor = null; 253 if (mEnterTransitionCoordinator != null) { 254 enterViewsTransition = mEnterTransitionCoordinator.getEnterViewsTransition(); 255 decor = mEnterTransitionCoordinator.getDecor(); 256 mEnterTransitionCoordinator.cancelEnter(); 257 mEnterTransitionCoordinator = null; 258 if (enterViewsTransition != null && decor != null) { 259 enterViewsTransition.pause(decor); 260 } 261 } 262 263 ExitTransitionCoordinator exitCoordinator = 264 new ExitTransitionCoordinator(activity, mEnteringNames, null, null, true); 265 if (enterViewsTransition != null && decor != null) { 266 enterViewsTransition.resume(decor); 267 } 268 exitCoordinator.startExit(activity.mResultCode, activity.mResultData); 269 } 270 return true; 271 } 272 } 273 274 public void startExitOutTransition(Activity activity, Bundle options) { 275 if (!activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) { 276 return; 277 } 278 ActivityOptions activityOptions = new ActivityOptions(options); 279 mEnterTransitionCoordinator = null; 280 if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { 281 int key = activityOptions.getExitCoordinatorKey(); 282 int index = mExitTransitionCoordinators.indexOfKey(key); 283 if (index >= 0) { 284 mCalledExitCoordinator = mExitTransitionCoordinators.valueAt(index).get(); 285 mExitTransitionCoordinators.removeAt(index); 286 if (mCalledExitCoordinator != null) { 287 mExitingFrom = mCalledExitCoordinator.getAcceptedNames(); 288 mExitingTo = mCalledExitCoordinator.getMappedNames(); 289 mExitingToView = mCalledExitCoordinator.copyMappedViews(); 290 mCalledExitCoordinator.startExit(); 291 } 292 } 293 } 294 } 295} 296