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