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.support.v4.app;
17
18import android.content.Context;
19import android.content.res.Resources;
20import android.graphics.Bitmap;
21import android.graphics.Canvas;
22import android.graphics.Matrix;
23import android.graphics.RectF;
24import android.graphics.drawable.BitmapDrawable;
25import android.os.Parcelable;
26import android.view.View;
27import android.widget.ImageView;
28
29import java.util.List;
30import java.util.Map;
31
32/**
33 * Listener provided in
34 * {@link FragmentActivity#setEnterSharedElementCallback(SharedElementCallback)} and
35 * {@link FragmentActivity#setExitSharedElementCallback(SharedElementCallback)}
36 * to monitor the Activity transitions. The events can be used to customize Activity
37 * Transition behavior.
38 */
39public abstract class SharedElementCallback {
40    private Matrix mTempMatrix;
41
42    /**
43     * Called immediately after the start state is set for the shared element.
44     * The shared element will start at the size and position of the shared element
45     * in the launching Activity or Fragment.
46     *
47     * @param sharedElementNames The names of the shared elements that were accepted into
48     *                           the View hierarchy.
49     * @param sharedElements The shared elements that are part of the View hierarchy.
50     * @param sharedElementSnapshots The Views containing snap shots of the shared element
51     *                               from the launching Window. These elements will not
52     *                               be part of the scene, but will be positioned relative
53     *                               to the Window decor View. This list is null for Fragment
54     *                               Transitions.
55     */
56    public void onSharedElementStart(List<String> sharedElementNames,
57            List<View> sharedElements, List<View> sharedElementSnapshots) {}
58
59    /**
60     * Called after the end state is set for the shared element, but before the end state
61     * is captured by the shared element transition.
62     * <p>
63     *     Any customization done in
64     *     {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)}
65     *     may need to be modified to the final state of the shared element if it is not
66     *     automatically corrected by layout. For example, rotation or scale will not
67     *     be affected by layout and if changed in {@link #onSharedElementStart(java.util.List,
68     *     java.util.List, java.util.List)}, it will also have to be set here again to correct
69     *     the end state.
70     * </p>
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
78     *                               to the Window decor View. This list will be null for
79     *                               Fragment Transitions.
80     */
81    public void onSharedElementEnd(List<String> sharedElementNames,
82            List<View> sharedElements, List<View> sharedElementSnapshots) {}
83
84    /**
85     * Called after {@link #onMapSharedElements(java.util.List, java.util.Map)} when
86     * transferring shared elements in. Any shared elements that have no mapping will be in
87     * <var>rejectedSharedElements</var>. The elements remaining in
88     * <var>rejectedSharedElements</var> will be transitioned out of the Scene. If a
89     * View is removed from <var>rejectedSharedElements</var>, it must be handled by the
90     * <code>SharedElementListener</code>.
91     * <p>
92     * Views in rejectedSharedElements will have their position and size set to the
93     * position of the calling shared element, relative to the Window decor View and contain
94     * snapshots of the View from the calling Activity or Fragment. This
95     * view may be safely added to the decor View's overlay to remain in position.
96     * </p>
97     * <p>This method is not called for Fragment Transitions. All rejected shared elements
98     * will be handled by the exit transition.</p>
99     *
100     * @param rejectedSharedElements Views containing visual information of shared elements
101     *                               that are not part of the entering scene. These Views
102     *                               are positioned relative to the Window decor View. A
103     *                               View removed from this list will not be transitioned
104     *                               automatically.
105     */
106    public void onRejectSharedElements(List<View> rejectedSharedElements) {}
107
108    /**
109     * Lets the SharedElementCallback adjust the mapping of shared element names to
110     * Views.
111     *
112     * @param names The names of all shared elements transferred from the calling Activity
113     *              or Fragment in the order they were provided.
114     * @param sharedElements The mapping of shared element names to Views. The best guess
115     *                       will be filled into sharedElements based on the transitionNames.
116     */
117    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {}
118
119
120    /**
121     * Creates a snapshot of a shared element to be used by the remote Activity and reconstituted
122     * with {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)}. A
123     * null return value will mean that the remote Activity will have a null snapshot View in
124     * {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and
125     * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}.
126     *
127     * <p>This is not called for Fragment Transitions.</p>
128     *
129     * @param sharedElement The shared element View to create a snapshot for.
130     * @param viewToGlobalMatrix A matrix containing a transform from the view to the screen
131     *                           coordinates.
132     * @param screenBounds The bounds of shared element in screen coordinate space. This is
133     *                     the bounds of the view with the viewToGlobalMatrix applied.
134     * @return A snapshot to send to the remote Activity to be reconstituted with
135     * {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)} and passed
136     * into {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and
137     * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}.
138     */
139    public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix,
140            RectF screenBounds) {
141        int bitmapWidth = Math.round(screenBounds.width());
142        int bitmapHeight = Math.round(screenBounds.height());
143        Bitmap bitmap = null;
144        if (bitmapWidth > 0 && bitmapHeight > 0) {
145            if (mTempMatrix == null) {
146                mTempMatrix = new Matrix();
147            }
148            mTempMatrix.set(viewToGlobalMatrix);
149            mTempMatrix.postTranslate(-screenBounds.left, -screenBounds.top);
150            bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
151            Canvas canvas = new Canvas(bitmap);
152            canvas.concat(mTempMatrix);
153            sharedElement.draw(canvas);
154        }
155        return bitmap;
156    }
157
158    /**
159     * Reconstitutes a snapshot View from a Parcelable returned in
160     * {@link #onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix,
161     * android.graphics.RectF)} to be used in {@link #onSharedElementStart(java.util.List,
162     * java.util.List, java.util.List)} and {@link #onSharedElementEnd(java.util.List,
163     * java.util.List, java.util.List)}. The returned View will be sized and positioned after
164     * this call so that it is ready to be added to the decor View's overlay.
165     *
166     * <p>This is not called for Fragment Transitions.</p>
167     *
168     * @param context The Context used to create the snapshot View.
169     * @param snapshot The Parcelable returned by {@link #onCaptureSharedElementSnapshot(
170     * android.view.View, android.graphics.Matrix, android.graphics.RectF)}.
171     * @return A View to be sent in {@link #onSharedElementStart(java.util.List, java.util.List,
172     * java.util.List)} and {@link #onSharedElementEnd(java.util.List, java.util.List,
173     * java.util.List)}. A null value will produce a null snapshot value for those two methods.
174     */
175    public View onCreateSnapshotView(Context context, Parcelable snapshot) {
176        ImageView view = null;
177        if (snapshot instanceof Bitmap) {
178            Bitmap bitmap = (Bitmap) snapshot;
179            view = new ImageView(context);
180            view.setImageBitmap(bitmap);
181        }
182        return view;
183    }
184
185}
186