ActivityTransitionState.java revision 1fecfb2ddcdf4335ff543bdd549b8e4d36139da8
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 public ActivityTransitionState() { 99 } 100 101 public int addExitTransitionCoordinator(ExitTransitionCoordinator exitTransitionCoordinator) { 102 if (mExitTransitionCoordinators == null) { 103 mExitTransitionCoordinators = 104 new SparseArray<WeakReference<ExitTransitionCoordinator>>(); 105 } 106 WeakReference<ExitTransitionCoordinator> ref = new WeakReference(exitTransitionCoordinator); 107 // clean up old references: 108 for (int i = mExitTransitionCoordinators.size() - 1; i >= 0; i--) { 109 WeakReference<ExitTransitionCoordinator> oldRef 110 = mExitTransitionCoordinators.valueAt(i); 111 if (oldRef.get() == null) { 112 mExitTransitionCoordinators.removeAt(i); 113 } 114 } 115 int newKey = mExitTransitionCoordinatorsKey++; 116 mExitTransitionCoordinators.append(newKey, ref); 117 return newKey; 118 } 119 120 public void readState(Bundle bundle) { 121 if (bundle != null) { 122 if (mEnterTransitionCoordinator == null || mEnterTransitionCoordinator.isReturning()) { 123 mEnteringNames = bundle.getStringArrayList(ENTERING_SHARED_ELEMENTS); 124 } 125 if (mEnterTransitionCoordinator == null) { 126 mExitingFrom = bundle.getStringArrayList(EXITING_MAPPED_FROM); 127 mExitingTo = bundle.getStringArrayList(EXITING_MAPPED_TO); 128 } 129 } 130 } 131 132 public void saveState(Bundle bundle) { 133 if (mEnteringNames != null) { 134 bundle.putStringArrayList(ENTERING_SHARED_ELEMENTS, mEnteringNames); 135 } 136 if (mExitingFrom != null) { 137 bundle.putStringArrayList(EXITING_MAPPED_FROM, mExitingFrom); 138 bundle.putStringArrayList(EXITING_MAPPED_TO, mExitingTo); 139 } 140 } 141 142 public void setEnterActivityOptions(Activity activity, ActivityOptions options) { 143 if (activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS) 144 && options != null && mEnterActivityOptions == null 145 && options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { 146 mEnterActivityOptions = options; 147 if (mEnterActivityOptions.isReturning()) { 148 int result = mEnterActivityOptions.getResultCode(); 149 if (result != 0) { 150 activity.onActivityReenter(result, mEnterActivityOptions.getResultData()); 151 } 152 } 153 } 154 } 155 156 public void enterReady(Activity activity) { 157 if (mEnterActivityOptions == null) { 158 return; 159 } 160 mHasExited = false; 161 ArrayList<String> sharedElementNames = mEnterActivityOptions.getSharedElementNames(); 162 ResultReceiver resultReceiver = mEnterActivityOptions.getResultReceiver(); 163 if (mEnterActivityOptions.isReturning()) { 164 restoreExitedViews(); 165 activity.getWindow().getDecorView().setVisibility(View.VISIBLE); 166 } 167 mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity, 168 resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning()); 169 170 if (!mIsEnterPostponed) { 171 startEnter(); 172 } 173 } 174 175 public void postponeEnterTransition() { 176 mIsEnterPostponed = true; 177 } 178 179 public void startPostponedEnterTransition() { 180 if (mIsEnterPostponed) { 181 mIsEnterPostponed = false; 182 if (mEnterTransitionCoordinator != null) { 183 startEnter(); 184 } 185 } 186 } 187 188 private void startEnter() { 189 if (mEnterActivityOptions.isReturning()) { 190 if (mExitingToView != null) { 191 mEnterTransitionCoordinator.viewInstancesReady(mExitingFrom, mExitingToView); 192 } else { 193 mEnterTransitionCoordinator.namedViewsReady(mExitingFrom, mExitingTo); 194 } 195 } else { 196 mEnterTransitionCoordinator.namedViewsReady(null, null); 197 mEnteringNames = mEnterTransitionCoordinator.getAllSharedElementNames(); 198 } 199 200 mExitingFrom = null; 201 mExitingTo = null; 202 mExitingToView = null; 203 mEnterActivityOptions = null; 204 } 205 206 public void onStop() { 207 restoreExitedViews(); 208 if (mEnterTransitionCoordinator != null) { 209 mEnterTransitionCoordinator.stop(); 210 mEnterTransitionCoordinator = null; 211 } 212 } 213 214 public void onResume() { 215 restoreExitedViews(); 216 } 217 218 private void restoreExitedViews() { 219 if (mCalledExitCoordinator != null) { 220 mCalledExitCoordinator.resetViews(); 221 mCalledExitCoordinator = null; 222 } 223 } 224 225 public boolean startExitBackTransition(Activity activity) { 226 if (mEnteringNames == null) { 227 return false; 228 } else { 229 if (!mHasExited) { 230 mHasExited = true; 231 if (mEnterTransitionCoordinator != null) { 232 mEnterTransitionCoordinator.stop(); 233 mEnterTransitionCoordinator = null; 234 } 235 ArrayMap<String, View> sharedElements = new ArrayMap<String, View>(); 236 activity.getWindow().getDecorView().findNamedViews(sharedElements); 237 238 ExitTransitionCoordinator exitCoordinator = 239 new ExitTransitionCoordinator(activity, mEnteringNames, null, null, true); 240 exitCoordinator.startExit(activity.mResultCode, activity.mResultData); 241 } 242 return true; 243 } 244 } 245 246 public void startExitOutTransition(Activity activity, Bundle options) { 247 if (!activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) { 248 return; 249 } 250 ActivityOptions activityOptions = new ActivityOptions(options); 251 if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { 252 int key = activityOptions.getExitCoordinatorKey(); 253 int index = mExitTransitionCoordinators.indexOfKey(key); 254 if (index >= 0) { 255 mCalledExitCoordinator = mExitTransitionCoordinators.valueAt(index).get(); 256 mExitTransitionCoordinators.removeAt(index); 257 if (mCalledExitCoordinator != null) { 258 mExitingFrom = mCalledExitCoordinator.getAcceptedNames(); 259 mExitingTo = mCalledExitCoordinator.getMappedNames(); 260 mExitingToView = mCalledExitCoordinator.getMappedViews(); 261 mCalledExitCoordinator.startExit(); 262 } 263 } 264 } 265 } 266} 267