1package com.xtremelabs.robolectric.tester.android.util;
2
3import android.os.Bundle;
4import android.os.Handler;
5import android.os.Looper;
6import android.support.v4.app.*;
7import android.view.View;
8import android.view.ViewGroup;
9import com.xtremelabs.robolectric.Robolectric;
10import com.xtremelabs.robolectric.shadows.SerializedFragmentState;
11import com.xtremelabs.robolectric.shadows.ShadowFragment;
12import com.xtremelabs.robolectric.shadows.ShadowFragmentActivity;
13
14import java.io.FileDescriptor;
15import java.io.PrintWriter;
16import java.util.ArrayList;
17import java.util.HashMap;
18import java.util.List;
19import java.util.Map;
20
21import static com.xtremelabs.robolectric.Robolectric.shadowOf;
22
23public 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