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