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