1 /*
2  * Copyright (C) 2015 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 
17 package com.android.tv.common.ui.setup;
18 
19 import android.app.Fragment;
20 import android.os.Bundle;
21 import android.support.annotation.IntDef;
22 import android.transition.Transition;
23 import android.transition.Transition.TransitionListener;
24 import android.view.Gravity;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.view.View.OnClickListener;
28 import android.view.ViewGroup;
29 
30 import com.android.tv.common.ui.setup.animation.FadeAndShortSlide;
31 import com.android.tv.common.ui.setup.animation.SetupAnimationHelper;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 
36 /**
37  * A fragment which slides when it is entering/exiting.
38  */
39 public abstract class SetupFragment extends Fragment {
40     @Retention(RetentionPolicy.SOURCE)
41     @IntDef(flag = true,
42             value = {FRAGMENT_ENTER_TRANSITION, FRAGMENT_EXIT_TRANSITION,
43                     FRAGMENT_REENTER_TRANSITION, FRAGMENT_RETURN_TRANSITION})
44     public @interface FragmentTransitionType {}
45     public static final int FRAGMENT_ENTER_TRANSITION = 0x01;
46     public static final int FRAGMENT_EXIT_TRANSITION = FRAGMENT_ENTER_TRANSITION << 1;
47     public static final int FRAGMENT_REENTER_TRANSITION = FRAGMENT_ENTER_TRANSITION << 2;
48     public static final int FRAGMENT_RETURN_TRANSITION = FRAGMENT_ENTER_TRANSITION << 3;
49 
50     private OnActionClickListener mOnActionClickListener;
51 
52     private boolean mEnterTransitionRunning;
53 
54     private TransitionListener mTransitionListener = new TransitionListener() {
55         @Override
56         public void onTransitionStart(Transition transition) {
57             mEnterTransitionRunning = true;
58         }
59 
60         @Override
61         public void onTransitionEnd(Transition transition) {
62             mEnterTransitionRunning = false;
63             onEnterTransitionEnd();
64         }
65 
66         @Override
67         public void onTransitionCancel(Transition transition) { }
68 
69         @Override
70         public void onTransitionPause(Transition transition) { }
71 
72         @Override
73         public void onTransitionResume(Transition transition) { }
74     };
75 
76     /**
77      * Returns {@code true} if the enter/reenter transition is running.
78      */
isEnterTransitionRunning()79     protected boolean isEnterTransitionRunning() {
80         return mEnterTransitionRunning;
81     }
82 
83     /**
84      * Called when the enter/reenter transition ends.
85      */
onEnterTransitionEnd()86     protected void onEnterTransitionEnd() { }
87 
SetupFragment()88     public SetupFragment() {
89         setAllowEnterTransitionOverlap(false);
90         setAllowReturnTransitionOverlap(false);
91         enableFragmentTransition(FRAGMENT_ENTER_TRANSITION | FRAGMENT_EXIT_TRANSITION
92                 | FRAGMENT_REENTER_TRANSITION | FRAGMENT_RETURN_TRANSITION);
93     }
94 
95     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)96     public View onCreateView(LayoutInflater inflater, ViewGroup container,
97             Bundle savedInstanceState) {
98         View view = inflater.inflate(getLayoutResourceId(), container, false);
99         // After the transition animation, we need to request the focus. If not, this fragment
100         // doesn't have the focus.
101         view.requestFocus();
102         return view;
103     }
104 
105     /**
106      * Returns action click listener.
107      */
getOnActionClickListener()108     public OnActionClickListener getOnActionClickListener() {
109         return mOnActionClickListener;
110     }
111 
112     /**
113      * Sets action click listener.
114      */
setOnActionClickListener(OnActionClickListener onActionClickListener)115     public void setOnActionClickListener(OnActionClickListener onActionClickListener) {
116         mOnActionClickListener = onActionClickListener;
117     }
118 
119     /**
120      * Returns the layout resource ID for this fragment.
121      */
getLayoutResourceId()122     abstract protected int getLayoutResourceId();
123 
setOnClickAction(View view, final String category, final int actionId)124     protected void setOnClickAction(View view, final String category, final int actionId) {
125         view.setOnClickListener(new OnClickListener() {
126             @Override
127             public void onClick(View view) {
128                 onActionClick(category, actionId);
129             }
130         });
131     }
132 
onActionClick(String category, int actionId)133     protected void onActionClick(String category, int actionId) {
134         SetupActionHelper.onActionClick(this, category, actionId);
135     }
136 
137     @Override
setEnterTransition(Transition transition)138     public void setEnterTransition(Transition transition) {
139         super.setEnterTransition(transition);
140         if (transition != null) {
141             transition.addListener(mTransitionListener);
142         }
143     }
144 
145     @Override
setReenterTransition(Transition transition)146     public void setReenterTransition(Transition transition) {
147         super.setReenterTransition(transition);
148         if (transition != null) {
149             transition.addListener(mTransitionListener);
150         }
151     }
152 
153     /**
154      * Enables fragment transition according to the given {@code mask}.
155      *
156      * @param mask This value is the combination of {@link #FRAGMENT_ENTER_TRANSITION},
157      * {@link #FRAGMENT_EXIT_TRANSITION}, {@link #FRAGMENT_REENTER_TRANSITION}, and
158      * {@link #FRAGMENT_RETURN_TRANSITION}.
159      */
enableFragmentTransition(@ragmentTransitionType int mask)160     public void enableFragmentTransition(@FragmentTransitionType int mask) {
161         setEnterTransition((mask & FRAGMENT_ENTER_TRANSITION) == 0 ? null
162                 : createTransition(Gravity.END));
163         setExitTransition((mask & FRAGMENT_EXIT_TRANSITION) == 0 ? null
164                 : createTransition(Gravity.START));
165         setReenterTransition((mask & FRAGMENT_REENTER_TRANSITION) == 0 ? null
166                 : createTransition(Gravity.START));
167         setReturnTransition((mask & FRAGMENT_RETURN_TRANSITION) == 0 ? null
168                 : createTransition(Gravity.END));
169     }
170 
171     /**
172      * Sets the transition with the given {@code slidEdge}.
173      */
setFragmentTransition(@ragmentTransitionType int transitionType, int slideEdge)174     public void setFragmentTransition(@FragmentTransitionType int transitionType, int slideEdge) {
175         switch (transitionType) {
176             case FRAGMENT_ENTER_TRANSITION:
177                 setEnterTransition(createTransition(slideEdge));
178                 break;
179             case FRAGMENT_EXIT_TRANSITION:
180                 setExitTransition(createTransition(slideEdge));
181                 break;
182             case FRAGMENT_REENTER_TRANSITION:
183                 setReenterTransition(createTransition(slideEdge));
184                 break;
185             case FRAGMENT_RETURN_TRANSITION:
186                 setReturnTransition(createTransition(slideEdge));
187                 break;
188         }
189     }
190 
createTransition(int slideEdge)191     private Transition createTransition(int slideEdge) {
192         return new SetupAnimationHelper.TransitionBuilder()
193                 .setSlideEdge(slideEdge)
194                 .setParentIdsForDelay(getParentIdsForDelay())
195                 .setExcludeIds(getExcludedTargetIds())
196                 .build();
197     }
198 
199     /**
200      * Changes the move distance of the transitions to short distance.
201      */
setShortDistance(@ragmentTransitionType int mask)202     public void setShortDistance(@FragmentTransitionType int mask) {
203         if ((mask & FRAGMENT_ENTER_TRANSITION) != 0) {
204             Transition transition = getEnterTransition();
205             if (transition instanceof FadeAndShortSlide) {
206                 SetupAnimationHelper.setShortDistance((FadeAndShortSlide) transition);
207             }
208         }
209         if ((mask & FRAGMENT_EXIT_TRANSITION) != 0) {
210             Transition transition = getExitTransition();
211             if (transition instanceof FadeAndShortSlide) {
212                 SetupAnimationHelper.setShortDistance((FadeAndShortSlide) transition);
213             }
214         }
215         if ((mask & FRAGMENT_REENTER_TRANSITION) != 0) {
216             Transition transition = getReenterTransition();
217             if (transition instanceof FadeAndShortSlide) {
218                 SetupAnimationHelper.setShortDistance((FadeAndShortSlide) transition);
219             }
220         }
221         if ((mask & FRAGMENT_RETURN_TRANSITION) != 0) {
222             Transition transition = getReturnTransition();
223             if (transition instanceof FadeAndShortSlide) {
224                 SetupAnimationHelper.setShortDistance((FadeAndShortSlide) transition);
225             }
226         }
227     }
228 
229     /**
230      * Returns the ID's of the view's whose descendants will perform delayed move.
231      *
232      * @see com.android.tv.common.ui.setup.animation.SetupAnimationHelper.TransitionBuilder
233      * #setParentIdsForDelay
234      */
getParentIdsForDelay()235     protected int[] getParentIdsForDelay() {
236         return null;
237     }
238 
239     /**
240      * Sets the ID's of the views which will not be included in the transition.
241      *
242      * @see com.android.tv.common.ui.setup.animation.SetupAnimationHelper.TransitionBuilder
243      * #setExcludeIds
244      */
getExcludedTargetIds()245     protected int[] getExcludedTargetIds() {
246         return null;
247     }
248 
249     /**
250      * Returns the ID's of the shared elements.
251      *
252      * <p>Note that the shared elements should have their own transition names.
253      */
getSharedElementIds()254     public int[] getSharedElementIds() {
255         return null;
256     }
257 }
258