blob: bac84a4fcc9d863b9bc4b86361ff866837c94121 [file] [log] [blame]
George Mount62ab9b72014-05-02 13:51:17 -07001/*
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
George Mount480ca822014-08-08 16:35:48 -070018import android.content.Context;
19import android.content.res.Resources;
20import android.graphics.Bitmap;
George Mount480ca822014-08-08 16:35:48 -070021import android.graphics.Matrix;
22import android.graphics.RectF;
23import android.graphics.drawable.BitmapDrawable;
Dake Gu017b13a2014-09-30 15:44:09 -070024import android.graphics.drawable.Drawable;
25import android.os.Bundle;
George Mount480ca822014-08-08 16:35:48 -070026import android.os.Parcelable;
George Mount79b27812014-09-12 16:39:04 -070027import android.transition.TransitionUtils;
George Mount62ab9b72014-05-02 13:51:17 -070028import android.view.View;
Dake Gu017b13a2014-09-30 15:44:09 -070029import android.widget.ImageView;
30import android.widget.ImageView.ScaleType;
George Mount62ab9b72014-05-02 13:51:17 -070031
32import java.util.List;
33import java.util.Map;
34
35/**
36 * Listener provided in
George Mount65580562014-08-29 08:15:48 -070037 * {@link Activity#setEnterSharedElementCallback(SharedElementCallback)} and
38 * {@link Activity#setExitSharedElementCallback(SharedElementCallback)} as well as
George Mount85ea4982014-09-12 14:16:18 -070039 * {@link Fragment#setEnterSharedElementCallback(SharedElementCallback)} and
40 * {@link Fragment#setExitSharedElementCallback(SharedElementCallback)}
George Mount65580562014-08-29 08:15:48 -070041 * to monitor the Shared element transitions. The events can be used to customize Activity
42 * and Fragment Transition behavior.
George Mount62ab9b72014-05-02 13:51:17 -070043 */
George Mount65580562014-08-29 08:15:48 -070044public abstract class SharedElementCallback {
George Mount480ca822014-08-08 16:35:48 -070045 private Matrix mTempMatrix;
Dake Gu017b13a2014-09-30 15:44:09 -070046 private static final String BUNDLE_SNAPSHOT_BITMAP = "sharedElement:snapshot:bitmap";
47 private static final String BUNDLE_SNAPSHOT_IMAGE_SCALETYPE = "sharedElement:snapshot:imageScaleType";
48 private static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "sharedElement:snapshot:imageMatrix";
George Mount800d72b2014-05-19 07:09:00 -070049
George Mount65580562014-08-29 08:15:48 -070050 static final SharedElementCallback NULL_CALLBACK = new SharedElementCallback() {
George Mount800d72b2014-05-19 07:09:00 -070051 };
52
George Mount62ab9b72014-05-02 13:51:17 -070053 /**
George Mount0c922782015-04-10 10:15:24 -070054 * In Activity Transitions, onSharedElementStart is called immediately before
55 * capturing the start of the shared element state on enter and reenter transitions and
56 * immediately before capturing the end of the shared element state for exit and return
57 * transitions.
58 * <p>
59 * In Fragment Transitions, onSharedElementStart is called immediately before capturing the
60 * start state of all shared element transitions.
61 * <p>
62 * This call can be used to adjust the transition start state by modifying the shared
63 * element Views. Note that no layout step will be executed between onSharedElementStart
64 * and the transition state capture.
65 * <p>
66 * For Activity Transitions, any changes made in {@link #onSharedElementEnd(List, List, List)}
67 * that are not updated during by layout should be corrected in onSharedElementStart for exit and
68 * return transitions. For example, rotation or scale will not be affected by layout and
69 * if changed in {@link #onSharedElementEnd(List, List, List)}, it will also have to be reset
70 * in onSharedElementStart again to correct the end state.
George Mount62ab9b72014-05-02 13:51:17 -070071 *
72 * @param sharedElementNames The names of the shared elements that were accepted into
73 * the View hierarchy.
74 * @param sharedElements The shared elements that are part of the View hierarchy.
75 * @param sharedElementSnapshots The Views containing snap shots of the shared element
76 * from the launching Window. These elements will not
77 * be part of the scene, but will be positioned relative
George Mount65580562014-08-29 08:15:48 -070078 * to the Window decor View. This list is null for Fragment
79 * Transitions.
George Mount62ab9b72014-05-02 13:51:17 -070080 */
George Mount65580562014-08-29 08:15:48 -070081 public void onSharedElementStart(List<String> sharedElementNames,
George Mount62ab9b72014-05-02 13:51:17 -070082 List<View> sharedElements, List<View> sharedElementSnapshots) {}
83
84 /**
George Mount0c922782015-04-10 10:15:24 -070085 * In Activity Transitions, onSharedElementEnd is called immediately before
86 * capturing the end of the shared element state on enter and reenter transitions and
87 * immediately before capturing the start of the shared element state for exit and return
88 * transitions.
George Mount800d72b2014-05-19 07:09:00 -070089 * <p>
George Mount0c922782015-04-10 10:15:24 -070090 * In Fragment Transitions, onSharedElementEnd is called immediately before capturing the
91 * end state of all shared element transitions.
92 * <p>
93 * This call can be used to adjust the transition end state by modifying the shared
94 * element Views. Note that no layout step will be executed between onSharedElementEnd
95 * and the transition state capture.
96 * <p>
97 * Any changes made in {@link #onSharedElementStart(List, List, List)} that are not updated
98 * during layout should be corrected in onSharedElementEnd. For example, rotation or scale
99 * will not be affected by layout and if changed in
100 * {@link #onSharedElementStart(List, List, List)}, it will also have to be reset in
101 * onSharedElementEnd again to correct the end state.
George Mount62ab9b72014-05-02 13:51:17 -0700102 *
103 * @param sharedElementNames The names of the shared elements that were accepted into
104 * the View hierarchy.
105 * @param sharedElements The shared elements that are part of the View hierarchy.
106 * @param sharedElementSnapshots The Views containing snap shots of the shared element
107 * from the launching Window. These elements will not
108 * be part of the scene, but will be positioned relative
George Mount65580562014-08-29 08:15:48 -0700109 * to the Window decor View. This list will be null for
110 * Fragment Transitions.
George Mount62ab9b72014-05-02 13:51:17 -0700111 */
George Mount65580562014-08-29 08:15:48 -0700112 public void onSharedElementEnd(List<String> sharedElementNames,
George Mount62ab9b72014-05-02 13:51:17 -0700113 List<View> sharedElements, List<View> sharedElementSnapshots) {}
114
115 /**
George Mount65580562014-08-29 08:15:48 -0700116 * Called after {@link #onMapSharedElements(java.util.List, java.util.Map)} when
George Mount800d72b2014-05-19 07:09:00 -0700117 * transferring shared elements in. Any shared elements that have no mapping will be in
118 * <var>rejectedSharedElements</var>. The elements remaining in
119 * <var>rejectedSharedElements</var> will be transitioned out of the Scene. If a
120 * View is removed from <var>rejectedSharedElements</var>, it must be handled by the
George Mount65580562014-08-29 08:15:48 -0700121 * <code>SharedElementCallback</code>.
George Mount800d72b2014-05-19 07:09:00 -0700122 * <p>
123 * Views in rejectedSharedElements will have their position and size set to the
124 * position of the calling shared element, relative to the Window decor View and contain
125 * snapshots of the View from the calling Activity or Fragment. This
126 * view may be safely added to the decor View's overlay to remain in position.
127 * </p>
George Mount65580562014-08-29 08:15:48 -0700128 * <p>This method is not called for Fragment Transitions. All rejected shared elements
129 * will be handled by the exit transition.</p>
George Mount62ab9b72014-05-02 13:51:17 -0700130 *
131 * @param rejectedSharedElements Views containing visual information of shared elements
132 * that are not part of the entering scene. These Views
133 * are positioned relative to the Window decor View. A
134 * View removed from this list will not be transitioned
135 * automatically.
136 */
George Mount65580562014-08-29 08:15:48 -0700137 public void onRejectSharedElements(List<View> rejectedSharedElements) {}
George Mount62ab9b72014-05-02 13:51:17 -0700138
139 /**
George Mount65580562014-08-29 08:15:48 -0700140 * Lets the SharedElementCallback adjust the mapping of shared element names to
George Mount62ab9b72014-05-02 13:51:17 -0700141 * Views.
George Mount800d72b2014-05-19 07:09:00 -0700142 *
George Mount62ab9b72014-05-02 13:51:17 -0700143 * @param names The names of all shared elements transferred from the calling Activity
George Mount65580562014-08-29 08:15:48 -0700144 * or Fragment in the order they were provided.
George Mount62ab9b72014-05-02 13:51:17 -0700145 * @param sharedElements The mapping of shared element names to Views. The best guess
George Mount0a2ae002014-06-23 14:57:27 +0000146 * will be filled into sharedElements based on the transitionNames.
George Mount62ab9b72014-05-02 13:51:17 -0700147 */
George Mount65580562014-08-29 08:15:48 -0700148 public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {}
George Mount480ca822014-08-08 16:35:48 -0700149
150 /**
151 * Creates a snapshot of a shared element to be used by the remote Activity and reconstituted
George Mount65580562014-08-29 08:15:48 -0700152 * with {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)}. A
George Mount480ca822014-08-08 16:35:48 -0700153 * null return value will mean that the remote Activity will have a null snapshot View in
George Mount65580562014-08-29 08:15:48 -0700154 * {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and
155 * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}.
156 *
157 * <p>This is not called for Fragment Transitions.</p>
George Mount480ca822014-08-08 16:35:48 -0700158 *
159 * @param sharedElement The shared element View to create a snapshot for.
160 * @param viewToGlobalMatrix A matrix containing a transform from the view to the screen
161 * coordinates.
162 * @param screenBounds The bounds of shared element in screen coordinate space. This is
163 * the bounds of the view with the viewToGlobalMatrix applied.
164 * @return A snapshot to send to the remote Activity to be reconstituted with
George Mount65580562014-08-29 08:15:48 -0700165 * {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)} and passed
166 * into {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and
167 * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}.
George Mount480ca822014-08-08 16:35:48 -0700168 */
George Mount65580562014-08-29 08:15:48 -0700169 public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix,
George Mount480ca822014-08-08 16:35:48 -0700170 RectF screenBounds) {
Dake Gu017b13a2014-09-30 15:44:09 -0700171 if (sharedElement instanceof ImageView) {
172 ImageView imageView = ((ImageView) sharedElement);
173 Drawable d = imageView.getDrawable();
174 Drawable bg = imageView.getBackground();
175 if (d != null && (bg == null || bg.getAlpha() == 0)) {
176 Bitmap bitmap = TransitionUtils.createDrawableBitmap(d);
177 if (bitmap != null) {
178 Bundle bundle = new Bundle();
179 bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap);
180 bundle.putString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE,
181 imageView.getScaleType().toString());
182 if (imageView.getScaleType() == ScaleType.MATRIX) {
183 Matrix matrix = imageView.getImageMatrix();
184 float[] values = new float[9];
185 matrix.getValues(values);
186 bundle.putFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX, values);
187 }
188 return bundle;
189 }
190 }
191 }
George Mount79b27812014-09-12 16:39:04 -0700192 if (mTempMatrix == null) {
193 mTempMatrix = new Matrix(viewToGlobalMatrix);
194 } else {
George Mount480ca822014-08-08 16:35:48 -0700195 mTempMatrix.set(viewToGlobalMatrix);
George Mount480ca822014-08-08 16:35:48 -0700196 }
George Mount79b27812014-09-12 16:39:04 -0700197 return TransitionUtils.createViewBitmap(sharedElement, mTempMatrix, screenBounds);
George Mount480ca822014-08-08 16:35:48 -0700198 }
199
200 /**
201 * Reconstitutes a snapshot View from a Parcelable returned in
George Mount65580562014-08-29 08:15:48 -0700202 * {@link #onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix,
203 * android.graphics.RectF)} to be used in {@link #onSharedElementStart(java.util.List,
204 * java.util.List, java.util.List)} and {@link #onSharedElementEnd(java.util.List,
George Mount480ca822014-08-08 16:35:48 -0700205 * java.util.List, java.util.List)}. The returned View will be sized and positioned after
206 * this call so that it is ready to be added to the decor View's overlay.
207 *
George Mount65580562014-08-29 08:15:48 -0700208 * <p>This is not called for Fragment Transitions.</p>
209 *
George Mount480ca822014-08-08 16:35:48 -0700210 * @param context The Context used to create the snapshot View.
George Mount65580562014-08-29 08:15:48 -0700211 * @param snapshot The Parcelable returned by {@link #onCaptureSharedElementSnapshot(
George Mount480ca822014-08-08 16:35:48 -0700212 * android.view.View, android.graphics.Matrix, android.graphics.RectF)}.
George Mount65580562014-08-29 08:15:48 -0700213 * @return A View to be sent in {@link #onSharedElementStart(java.util.List, java.util.List,
214 * java.util.List)} and {@link #onSharedElementEnd(java.util.List, java.util.List,
George Mount480ca822014-08-08 16:35:48 -0700215 * java.util.List)}. A null value will produce a null snapshot value for those two methods.
216 */
George Mount65580562014-08-29 08:15:48 -0700217 public View onCreateSnapshotView(Context context, Parcelable snapshot) {
George Mount480ca822014-08-08 16:35:48 -0700218 View view = null;
Dake Gu017b13a2014-09-30 15:44:09 -0700219 if (snapshot instanceof Bundle) {
220 Bundle bundle = (Bundle) snapshot;
221 Bitmap bitmap = (Bitmap) bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP);
222 if (bitmap == null) {
223 return null;
224 }
225 ImageView imageView = new ImageView(context);
226 view = imageView;
227 imageView.setImageBitmap(bitmap);
228 imageView.setScaleType(
229 ScaleType.valueOf(bundle.getString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE)));
230 if (imageView.getScaleType() == ScaleType.MATRIX) {
231 float[] values = bundle.getFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX);
232 Matrix matrix = new Matrix();
233 matrix.setValues(values);
234 imageView.setImageMatrix(matrix);
235 }
236 } else if (snapshot instanceof Bitmap) {
George Mount480ca822014-08-08 16:35:48 -0700237 Bitmap bitmap = (Bitmap) snapshot;
238 view = new View(context);
239 Resources resources = context.getResources();
240 view.setBackground(new BitmapDrawable(resources, bitmap));
241 }
242 return view;
243 }
George Mount4dc668c2015-04-09 20:55:59 +0000244
245 /**
246 * Called during an Activity Transition when the shared elements have arrived at the
247 * final location and are ready to be transferred. This method is called for both the
248 * source and destination Activities.
249 * <p>
250 * When the shared elements are ready to be transferred,
251 * {@link OnSharedElementsReadyListener#onSharedElementsReady()}
252 * must be called to trigger the transfer.
253 * <p>
254 * The default behavior is to trigger the transfer immediately.
255 *
256 * @param sharedElementNames The names of the shared elements that are being transferred..
257 * @param sharedElements The shared elements that are part of the View hierarchy.
258 * @param listener The listener to call when the shared elements are ready to be hidden
259 * in the source Activity or shown in the destination Activity.
260 */
261 public void onSharedElementsArrived(List<String> sharedElementNames,
262 List<View> sharedElements, OnSharedElementsReadyListener listener) {
263 listener.onSharedElementsReady();
264 }
265
266 /**
267 * Listener to be called after {@link
268 * SharedElementCallback#onSharedElementsArrived(List, List, OnSharedElementsReadyListener)}
269 * when the shared elements are ready to be hidden in the source Activity and shown in the
270 * destination Activity.
271 */
272 public interface OnSharedElementsReadyListener {
273
274 /**
275 * Call this method during or after the OnSharedElementsReadyListener has been received
276 * in {@link SharedElementCallback#onSharedElementsArrived(List, List,
277 * OnSharedElementsReadyListener)} to indicate that the shared elements are ready to be
278 * hidden in the source and shown in the destination Activity.
279 */
280 void onSharedElementsReady();
281 }
George Mount62ab9b72014-05-02 13:51:17 -0700282}