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