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