1 package com.xtremelabs.robolectric.tester.android.util; 2 3 import android.os.Bundle; 4 import android.os.Handler; 5 import android.os.Looper; 6 import android.support.v4.app.*; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import com.xtremelabs.robolectric.Robolectric; 10 import com.xtremelabs.robolectric.shadows.SerializedFragmentState; 11 import com.xtremelabs.robolectric.shadows.ShadowFragment; 12 import com.xtremelabs.robolectric.shadows.ShadowFragmentActivity; 13 14 import java.io.FileDescriptor; 15 import java.io.PrintWriter; 16 import java.util.ArrayList; 17 import java.util.HashMap; 18 import java.util.List; 19 import java.util.Map; 20 21 import static com.xtremelabs.robolectric.Robolectric.shadowOf; 22 23 public class TestFragmentManager extends FragmentManager { 24 private Map<Integer, Fragment> fragmentsById = new HashMap<Integer, Fragment>(); 25 private Map<String, Fragment> fragmentsByTag = new HashMap<String, Fragment>(); 26 private FragmentActivity activity; 27 private List<TestFragmentTransaction> transactions = new ArrayList<TestFragmentTransaction>(); 28 private List<Runnable> transactionsToRunLater = new ArrayList<Runnable>(); 29 30 public TestFragmentManager(FragmentActivity activity) { 31 this.activity = activity; 32 } 33 34 public FragmentActivity getActivity() { 35 return activity; 36 } 37 38 @Override 39 public FragmentTransaction beginTransaction() { 40 return new TestFragmentTransaction(this); 41 } 42 43 @Override 44 public boolean executePendingTransactions() { 45 if (transactionsToRunLater.size() > 0) { 46 for (Runnable runnable : new ArrayList<Runnable>(transactionsToRunLater)) { 47 runnable.run(); 48 shadowOf(Looper.getMainLooper()).getScheduler().remove(runnable); 49 } 50 return true; 51 } 52 return false; 53 } 54 55 @Override 56 public Fragment findFragmentById(int id) { 57 return fragmentsById.get(id); 58 } 59 60 @Override 61 public Fragment findFragmentByTag(String tag) { 62 return fragmentsByTag.get(tag); 63 } 64 65 @Override 66 public void popBackStack() { 67 } 68 69 @Override 70 public boolean popBackStackImmediate() { 71 return false; 72 } 73 74 @Override 75 public void popBackStack(String name, int flags) { 76 } 77 78 @Override 79 public boolean popBackStackImmediate(String name, int flags) { 80 return false; 81 } 82 83 @Override 84 public void popBackStack(int id, int flags) { 85 } 86 87 @Override 88 public boolean popBackStackImmediate(int id, int flags) { 89 return false; 90 } 91 92 @Override 93 public int getBackStackEntryCount() { 94 return 0; 95 } 96 97 @Override 98 public BackStackEntry getBackStackEntryAt(int index) { 99 return null; 100 } 101 102 @Override 103 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) { 104 } 105 106 @Override 107 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) { 108 } 109 110 @Override 111 public void putFragment(Bundle bundle, String key, Fragment fragment) { 112 } 113 114 @Override 115 public Fragment getFragment(Bundle bundle, String key) { 116 Object[] fragments = (Object[]) bundle.getSerializable(ShadowFragmentActivity.FRAGMENTS_TAG); 117 for (Object object : fragments) { 118 SerializedFragmentState fragment = (SerializedFragmentState) object; 119 if (fragment.tag.equals(key)) { 120 // TODO deserialize state 121 return Robolectric.newInstanceOf(fragment.fragmentClass); 122 } 123 } 124 return null; 125 } 126 127 @Override 128 public Fragment.SavedState saveFragmentInstanceState(Fragment f) { 129 return null; 130 } 131 132 @Override 133 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 134 } 135 136 public void addDialogFragment(String tag, DialogFragment fragment) { 137 fragmentsByTag.put(tag, fragment); 138 } 139 140 public void addFragment(int containerViewId, String tag, Fragment fragment, boolean replace) { 141 fragmentsById.put(containerViewId, fragment); 142 fragmentsByTag.put(tag, fragment); 143 144 ShadowFragment shadowFragment = shadowOf(fragment); 145 shadowFragment.setTag(tag); 146 shadowFragment.setContainerViewId(containerViewId); 147 shadowFragment.setShouldReplace(replace); 148 shadowFragment.setActivity(activity); 149 150 fragment.onAttach(activity); 151 fragment.onCreate(shadowFragment.getSavedInstanceState()); 152 } 153 154 public void startFragment(Fragment fragment) { 155 ViewGroup container = null; 156 ShadowFragment shadowFragment = shadowOf(fragment); 157 if (shadowOf(activity).getContentView() != null) { 158 container = (ViewGroup) activity.findViewById(shadowFragment.getContainerViewId()); 159 } 160 161 View view = fragment.onCreateView(activity.getLayoutInflater(), container, shadowFragment.getSavedInstanceState()); 162 shadowFragment.setView(view); 163 164 fragment.onViewCreated(view, null); 165 if (container != null) { 166 if (shadowFragment.getShouldReplace()) { 167 container.removeAllViews(); 168 } 169 if (view != null) { 170 container.addView(view); 171 } 172 } 173 174 fragment.onActivityCreated(shadowFragment.getSavedInstanceState()); 175 fragment.onStart(); 176 } 177 178 public HashMap<Integer, Fragment> getFragments() { 179 return new HashMap<Integer, Fragment>(fragmentsById); 180 } 181 182 public List<TestFragmentTransaction> getCommittedTransactions() { 183 return transactions; 184 } 185 186 public void commitTransaction(TestFragmentTransaction t) { 187 transactions.add(t); 188 if (t.isStarting()) { 189 addFragment(t.getContainerViewId(), t.getTag(), t.getFragment(), t.isReplacing()); 190 startFragment(t.getFragment()); 191 } 192 if (t.isRemoving()) { 193 Fragment fragment = t.getFragmentToRemove(); 194 if (fragment instanceof DialogFragment) { 195 ((DialogFragment)fragment).dismiss(); 196 } 197 } 198 if (t.isAttaching()) { 199 shadowOf(t.getFragmentToAttach()).setAttached(true); 200 } 201 if (t.isHiding()) { 202 Fragment fragment = t.getFragment(); 203 if (!fragment.isHidden()) { 204 shadowOf(fragment).setHidden(true); 205 fragment.onHiddenChanged(true); 206 } 207 } 208 if (t.isShowing()) { 209 Fragment fragment = t.getFragment(); 210 if (fragment.isHidden()) { 211 shadowOf(fragment).setHidden(false); 212 fragment.onHiddenChanged(false); 213 } 214 } 215 } 216 217 void commitLater(final TestFragmentTransaction testFragmentTransaction) { 218 Runnable transactionCommit = new Runnable() { 219 @Override 220 public void run() { 221 commitTransaction(testFragmentTransaction); 222 transactionsToRunLater.remove(this); 223 } 224 }; 225 transactionsToRunLater.add(transactionCommit); 226 new Handler().post(transactionCommit); 227 } 228 } 229