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 */ 16package android.support.v4.app.test; 17 18import android.app.Activity; 19import android.content.Context; 20import android.content.Intent; 21import android.os.Build.VERSION; 22import android.os.Build.VERSION_CODES; 23import android.os.Bundle; 24import android.support.v4.app.Fragment; 25import android.support.v4.app.FragmentActivity; 26import android.support.v4.test.R; 27import android.transition.Transition; 28import android.transition.Transition.TransitionListener; 29import android.transition.TransitionInflater; 30import android.view.LayoutInflater; 31import android.view.View; 32import android.view.ViewGroup; 33 34import java.util.concurrent.CountDownLatch; 35import java.util.concurrent.TimeUnit; 36 37/** 38 * A simple activity used for Fragment Transitions and lifecycle event ordering 39 */ 40public class FragmentTestActivity extends FragmentActivity { 41 @Override 42 public void onCreate(Bundle icicle) { 43 super.onCreate(icicle); 44 setContentView(R.layout.activity_content); 45 } 46 47 public static class TestFragment extends Fragment { 48 public static final int ENTER = 0; 49 public static final int RETURN = 1; 50 public static final int EXIT = 2; 51 public static final int REENTER = 3; 52 public static final int SHARED_ELEMENT_ENTER = 4; 53 public static final int SHARED_ELEMENT_RETURN = 5; 54 private static final int TRANSITION_COUNT = 6; 55 56 private static final String LAYOUT_ID = "layoutId"; 57 private static final String TRANSITION_KEY = "transition_"; 58 private int mLayoutId = R.layout.fragment_start; 59 private final int[] mTransitionIds = new int[] { 60 R.transition.fade, 61 R.transition.fade, 62 R.transition.fade, 63 R.transition.fade, 64 R.transition.change_bounds, 65 R.transition.change_bounds, 66 }; 67 private final Object[] mListeners = new Object[TRANSITION_COUNT]; 68 69 public TestFragment() { 70 if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { 71 for (int i = 0; i < TRANSITION_COUNT; i++) { 72 mListeners[i] = new TransitionCalledListener(); 73 } 74 } 75 } 76 77 public static TestFragment create(int layoutId) { 78 TestFragment testFragment = new TestFragment(); 79 testFragment.mLayoutId = layoutId; 80 return testFragment; 81 } 82 83 public void clearTransitions() { 84 for (int i = 0; i < TRANSITION_COUNT; i++) { 85 mTransitionIds[i] = 0; 86 } 87 } 88 89 public void clearNotifications() { 90 for (int i = 0; i < TRANSITION_COUNT; i++) { 91 ((TransitionCalledListener)mListeners[i]).startLatch = new CountDownLatch(1); 92 ((TransitionCalledListener)mListeners[i]).endLatch = new CountDownLatch(1); 93 } 94 } 95 96 @Override 97 public void onCreate(Bundle savedInstanceState) { 98 super.onCreate(savedInstanceState); 99 if (savedInstanceState != null) { 100 mLayoutId = savedInstanceState.getInt(LAYOUT_ID, mLayoutId); 101 for (int i = 0; i < TRANSITION_COUNT; i++) { 102 String key = TRANSITION_KEY + i; 103 mTransitionIds[i] = savedInstanceState.getInt(key, mTransitionIds[i]); 104 } 105 } 106 } 107 108 @Override 109 public void onSaveInstanceState(Bundle outState) { 110 super.onSaveInstanceState(outState); 111 outState.putInt(LAYOUT_ID, mLayoutId); 112 for (int i = 0; i < TRANSITION_COUNT; i++) { 113 String key = TRANSITION_KEY + i; 114 outState.putInt(key, mTransitionIds[i]); 115 } 116 } 117 118 @Override 119 public View onCreateView(LayoutInflater inflater, ViewGroup container, 120 Bundle savedInstanceState) { 121 return inflater.inflate(mLayoutId, container, false); 122 } 123 124 @SuppressWarnings("deprecation") 125 @Override 126 public void onAttach(Activity activity) { 127 super.onAttach(activity); 128 if (VERSION.SDK_INT > VERSION_CODES.KITKAT) { 129 setEnterTransition(loadTransition(ENTER)); 130 setReenterTransition(loadTransition(REENTER)); 131 setExitTransition(loadTransition(EXIT)); 132 setReturnTransition(loadTransition(RETURN)); 133 setSharedElementEnterTransition(loadTransition(SHARED_ELEMENT_ENTER)); 134 setSharedElementReturnTransition(loadTransition(SHARED_ELEMENT_RETURN)); 135 } 136 } 137 138 public boolean wasStartCalled(int transitionKey) { 139 return ((TransitionCalledListener)mListeners[transitionKey]).startLatch.getCount() == 0; 140 } 141 142 public boolean wasEndCalled(int transitionKey) { 143 return ((TransitionCalledListener)mListeners[transitionKey]).endLatch.getCount() == 0; 144 } 145 146 public boolean waitForStart(int transitionKey) 147 throws InterruptedException { 148 TransitionCalledListener l = ((TransitionCalledListener)mListeners[transitionKey]); 149 return l.startLatch.await(500,TimeUnit.MILLISECONDS); 150 } 151 152 public boolean waitForEnd(int transitionKey) 153 throws InterruptedException { 154 TransitionCalledListener l = ((TransitionCalledListener)mListeners[transitionKey]); 155 return l.endLatch.await(500,TimeUnit.MILLISECONDS); 156 } 157 158 private Transition loadTransition(int key) { 159 final int id = mTransitionIds[key]; 160 if (id == 0) { 161 return null; 162 } 163 Transition transition = TransitionInflater.from(getActivity()).inflateTransition(id); 164 transition.addListener(((TransitionCalledListener)mListeners[key])); 165 return transition; 166 } 167 168 private class TransitionCalledListener implements TransitionListener { 169 public CountDownLatch startLatch = new CountDownLatch(1); 170 public CountDownLatch endLatch = new CountDownLatch(1); 171 172 public TransitionCalledListener() { 173 } 174 175 @Override 176 public void onTransitionStart(Transition transition) { 177 startLatch.countDown(); 178 } 179 180 @Override 181 public void onTransitionEnd(Transition transition) { 182 endLatch.countDown(); 183 } 184 185 @Override 186 public void onTransitionCancel(Transition transition) { 187 } 188 189 @Override 190 public void onTransitionPause(Transition transition) { 191 } 192 193 @Override 194 public void onTransitionResume(Transition transition) { 195 } 196 } 197 } 198 199 public static class ParentFragment extends Fragment { 200 static final String CHILD_FRAGMENT_TAG = "childFragment"; 201 public boolean wasAttachedInTime; 202 203 private boolean mRetainChild; 204 205 @Override 206 public void onCreate(Bundle savedInstanceState) { 207 super.onCreate(savedInstanceState); 208 209 ChildFragment f = getChildFragment(); 210 if (f == null) { 211 f = new ChildFragment(); 212 if (mRetainChild) { 213 f.setRetainInstance(true); 214 } 215 getChildFragmentManager().beginTransaction().add(f, CHILD_FRAGMENT_TAG).commitNow(); 216 } 217 wasAttachedInTime = f.attached; 218 } 219 220 public ChildFragment getChildFragment() { 221 return (ChildFragment) getChildFragmentManager().findFragmentByTag(CHILD_FRAGMENT_TAG); 222 } 223 224 public void setRetainChildInstance(boolean retainChild) { 225 mRetainChild = retainChild; 226 } 227 } 228 229 public static class ChildFragment extends Fragment { 230 private OnAttachListener mOnAttachListener; 231 232 public boolean attached; 233 public boolean onActivityResultCalled; 234 public int onActivityResultRequestCode; 235 public int onActivityResultResultCode; 236 237 @Override 238 public void onAttach(Context activity) { 239 super.onAttach(activity); 240 attached = true; 241 if (mOnAttachListener != null) { 242 mOnAttachListener.onAttach(activity, this); 243 } 244 } 245 246 public void setOnAttachListener(OnAttachListener listener) { 247 mOnAttachListener = listener; 248 } 249 250 public interface OnAttachListener { 251 void onAttach(Context activity, ChildFragment fragment); 252 } 253 254 @Override 255 public void onActivityResult(int requestCode, int resultCode, Intent data) { 256 onActivityResultCalled = true; 257 onActivityResultRequestCode = requestCode; 258 onActivityResultResultCode = resultCode; 259 } 260 } 261} 262