George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 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 | */ |
| 16 | package android.app; |
| 17 | |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 18 | import android.content.Context; |
| 19 | import android.content.res.Resources; |
| 20 | import android.graphics.Bitmap; |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 21 | import android.graphics.Matrix; |
| 22 | import android.graphics.RectF; |
| 23 | import android.graphics.drawable.BitmapDrawable; |
Dake Gu | 017b13a | 2014-09-30 15:44:09 -0700 | [diff] [blame] | 24 | import android.graphics.drawable.Drawable; |
| 25 | import android.os.Bundle; |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 26 | import android.os.Parcelable; |
George Mount | 79b2781 | 2014-09-12 16:39:04 -0700 | [diff] [blame] | 27 | import android.transition.TransitionUtils; |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 28 | import android.view.View; |
Dake Gu | 017b13a | 2014-09-30 15:44:09 -0700 | [diff] [blame] | 29 | import android.widget.ImageView; |
| 30 | import android.widget.ImageView.ScaleType; |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 31 | |
| 32 | import java.util.List; |
| 33 | import java.util.Map; |
| 34 | |
| 35 | /** |
| 36 | * Listener provided in |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 37 | * {@link Activity#setEnterSharedElementCallback(SharedElementCallback)} and |
| 38 | * {@link Activity#setExitSharedElementCallback(SharedElementCallback)} as well as |
George Mount | 85ea498 | 2014-09-12 14:16:18 -0700 | [diff] [blame] | 39 | * {@link Fragment#setEnterSharedElementCallback(SharedElementCallback)} and |
| 40 | * {@link Fragment#setExitSharedElementCallback(SharedElementCallback)} |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 41 | * to monitor the Shared element transitions. The events can be used to customize Activity |
| 42 | * and Fragment Transition behavior. |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 43 | */ |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 44 | public abstract class SharedElementCallback { |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 45 | private Matrix mTempMatrix; |
Dake Gu | 017b13a | 2014-09-30 15:44:09 -0700 | [diff] [blame] | 46 | 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 Mount | 800d72b | 2014-05-19 07:09:00 -0700 | [diff] [blame] | 49 | |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 50 | static final SharedElementCallback NULL_CALLBACK = new SharedElementCallback() { |
George Mount | 800d72b | 2014-05-19 07:09:00 -0700 | [diff] [blame] | 51 | }; |
| 52 | |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 53 | /** |
George Mount | 0c92278 | 2015-04-10 10:15:24 -0700 | [diff] [blame] | 54 | * 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 Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 71 | * |
| 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 Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 78 | * to the Window decor View. This list is null for Fragment |
| 79 | * Transitions. |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 80 | */ |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 81 | public void onSharedElementStart(List<String> sharedElementNames, |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 82 | List<View> sharedElements, List<View> sharedElementSnapshots) {} |
| 83 | |
| 84 | /** |
George Mount | 0c92278 | 2015-04-10 10:15:24 -0700 | [diff] [blame] | 85 | * 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 Mount | 800d72b | 2014-05-19 07:09:00 -0700 | [diff] [blame] | 89 | * <p> |
George Mount | 0c92278 | 2015-04-10 10:15:24 -0700 | [diff] [blame] | 90 | * 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 Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 102 | * |
| 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 Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 109 | * to the Window decor View. This list will be null for |
| 110 | * Fragment Transitions. |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 111 | */ |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 112 | public void onSharedElementEnd(List<String> sharedElementNames, |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 113 | List<View> sharedElements, List<View> sharedElementSnapshots) {} |
| 114 | |
| 115 | /** |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 116 | * Called after {@link #onMapSharedElements(java.util.List, java.util.Map)} when |
George Mount | 800d72b | 2014-05-19 07:09:00 -0700 | [diff] [blame] | 117 | * 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 Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 121 | * <code>SharedElementCallback</code>. |
George Mount | 800d72b | 2014-05-19 07:09:00 -0700 | [diff] [blame] | 122 | * <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 Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 128 | * <p>This method is not called for Fragment Transitions. All rejected shared elements |
| 129 | * will be handled by the exit transition.</p> |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 130 | * |
| 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 Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 137 | public void onRejectSharedElements(List<View> rejectedSharedElements) {} |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 138 | |
| 139 | /** |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 140 | * Lets the SharedElementCallback adjust the mapping of shared element names to |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 141 | * Views. |
George Mount | 800d72b | 2014-05-19 07:09:00 -0700 | [diff] [blame] | 142 | * |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 143 | * @param names The names of all shared elements transferred from the calling Activity |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 144 | * or Fragment in the order they were provided. |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 145 | * @param sharedElements The mapping of shared element names to Views. The best guess |
George Mount | 0a2ae00 | 2014-06-23 14:57:27 +0000 | [diff] [blame] | 146 | * will be filled into sharedElements based on the transitionNames. |
George Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 147 | */ |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 148 | public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {} |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 149 | |
| 150 | /** |
| 151 | * Creates a snapshot of a shared element to be used by the remote Activity and reconstituted |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 152 | * with {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)}. A |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 153 | * null return value will mean that the remote Activity will have a null snapshot View in |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 154 | * {@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 Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 158 | * |
| 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 Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 165 | * {@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 Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 168 | */ |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 169 | public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 170 | RectF screenBounds) { |
Dake Gu | 017b13a | 2014-09-30 15:44:09 -0700 | [diff] [blame] | 171 | 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 Mount | 79b2781 | 2014-09-12 16:39:04 -0700 | [diff] [blame] | 192 | if (mTempMatrix == null) { |
| 193 | mTempMatrix = new Matrix(viewToGlobalMatrix); |
| 194 | } else { |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 195 | mTempMatrix.set(viewToGlobalMatrix); |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 196 | } |
George Mount | 79b2781 | 2014-09-12 16:39:04 -0700 | [diff] [blame] | 197 | return TransitionUtils.createViewBitmap(sharedElement, mTempMatrix, screenBounds); |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | /** |
| 201 | * Reconstitutes a snapshot View from a Parcelable returned in |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 202 | * {@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 Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 205 | * 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 Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 208 | * <p>This is not called for Fragment Transitions.</p> |
| 209 | * |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 210 | * @param context The Context used to create the snapshot View. |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 211 | * @param snapshot The Parcelable returned by {@link #onCaptureSharedElementSnapshot( |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 212 | * android.view.View, android.graphics.Matrix, android.graphics.RectF)}. |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 213 | * @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 Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 215 | * java.util.List)}. A null value will produce a null snapshot value for those two methods. |
| 216 | */ |
George Mount | 6558056 | 2014-08-29 08:15:48 -0700 | [diff] [blame] | 217 | public View onCreateSnapshotView(Context context, Parcelable snapshot) { |
George Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 218 | View view = null; |
Dake Gu | 017b13a | 2014-09-30 15:44:09 -0700 | [diff] [blame] | 219 | 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 Mount | 480ca82 | 2014-08-08 16:35:48 -0700 | [diff] [blame] | 237 | 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 Mount | 4dc668c | 2015-04-09 20:55:59 +0000 | [diff] [blame] | 244 | |
| 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 Mount | 62ab9b7 | 2014-05-02 13:51:17 -0700 | [diff] [blame] | 282 | } |