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 android.support.v4.app;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.os.Parcelable;
22 import android.support.v4.util.SimpleArrayMap;
23 import android.util.AttributeSet;
24 import android.view.Menu;
25 import android.view.MenuInflater;
26 import android.view.MenuItem;
27 import android.view.View;
28 
29 import java.io.FileDescriptor;
30 import java.io.PrintWriter;
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 /**
35  * Provides integration points with a {@link FragmentManager} for a fragment host.
36  * <p>
37  * It is the responsibility of the host to take care of the Fragment's lifecycle.
38  * The methods provided by {@link FragmentController} are for that purpose.
39  */
40 public class FragmentController {
41     private final FragmentHostCallback<?> mHost;
42 
43     /**
44      * Returns a {@link FragmentController}.
45      */
createController(FragmentHostCallback<?> callbacks)46     public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
47         return new FragmentController(callbacks);
48     }
49 
FragmentController(FragmentHostCallback<?> callbacks)50     private FragmentController(FragmentHostCallback<?> callbacks) {
51         mHost = callbacks;
52     }
53 
54     /**
55      * Returns a {@link FragmentManager} for this controller.
56      */
getSupportFragmentManager()57     public FragmentManager getSupportFragmentManager() {
58         return mHost.getFragmentManagerImpl();
59     }
60 
61     /**
62      * Returns a {@link LoaderManager}.
63      */
getSupportLoaderManager()64     public LoaderManager getSupportLoaderManager() {
65         return mHost.getLoaderManagerImpl();
66     }
67 
68     /**
69      * Returns the number of active fragments.
70      */
getActiveFragmentsCount()71     public int getActiveFragmentsCount() {
72         final List<Fragment> actives = mHost.mFragmentManager.mActive;
73         return actives == null ? 0 : actives.size();
74     }
75 
76     /**
77      * Returns the list of active fragments.
78      */
getActiveFragments(List<Fragment> actives)79     public List<Fragment> getActiveFragments(List<Fragment> actives) {
80         if (mHost.mFragmentManager.mActive == null) {
81             return null;
82         }
83         if (actives == null) {
84             actives = new ArrayList<Fragment>(getActiveFragmentsCount());
85         }
86         actives.addAll(mHost.mFragmentManager.mActive);
87         return actives;
88     }
89 
90     /**
91      * Attaches the host to the FragmentManager for this controller. The host must be
92      * attached before the FragmentManager can be used to manage Fragments.
93      */
attachHost(Fragment parent)94     public void attachHost(Fragment parent) {
95         mHost.mFragmentManager.attachController(
96                 mHost, mHost /*container*/, parent);
97     }
98 
99     /**
100      * Instantiates a Fragment's view.
101      *
102      * @param parent The parent that the created view will be placed
103      * in; <em>note that this may be null</em>.
104      * @param name Tag name to be inflated.
105      * @param context The context the view is being created in.
106      * @param attrs Inflation attributes as specified in XML file.
107      *
108      * @return view the newly created view
109      */
onCreateView(View parent, String name, Context context, AttributeSet attrs)110     public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
111         return mHost.mFragmentManager.onCreateView(parent, name, context, attrs);
112     }
113 
114     /**
115      * Marks the fragment state as unsaved. This allows for "state loss" detection.
116      */
noteStateNotSaved()117     public void noteStateNotSaved() {
118         mHost.mFragmentManager.noteStateNotSaved();
119     }
120 
121     /**
122      * Saves the state for all Fragments.
123      */
saveAllState()124     public Parcelable saveAllState() {
125         return mHost.mFragmentManager.saveAllState();
126     }
127 
128     /**
129      * Restores the saved state for all Fragments. The given Fragment list are Fragment
130      * instances retained across configuration changes.
131      *
132      * @see #retainNonConfig()
133      */
restoreAllState(Parcelable state, List<Fragment> nonConfigList)134     public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) {
135         mHost.mFragmentManager.restoreAllState(state, nonConfigList);
136     }
137 
138     /**
139      * Returns a list of Fragments that have opted to retain their instance across
140      * configuration changes.
141      */
retainNonConfig()142     public List<Fragment> retainNonConfig() {
143         return mHost.mFragmentManager.retainNonConfig();
144     }
145 
146     /**
147      * Moves all Fragments managed by the controller's FragmentManager
148      * into the create state.
149      * <p>Call when Fragments should be created.
150      *
151      * @see Fragment#onCreate(Bundle)
152      */
dispatchCreate()153     public void dispatchCreate() {
154         mHost.mFragmentManager.dispatchCreate();
155     }
156 
157     /**
158      * Moves all Fragments managed by the controller's FragmentManager
159      * into the activity created state.
160      * <p>Call when Fragments should be informed their host has been created.
161      *
162      * @see Fragment#onActivityCreated(Bundle)
163      */
dispatchActivityCreated()164     public void dispatchActivityCreated() {
165         mHost.mFragmentManager.dispatchActivityCreated();
166     }
167 
168     /**
169      * Moves all Fragments managed by the controller's FragmentManager
170      * into the start state.
171      * <p>Call when Fragments should be started.
172      *
173      * @see Fragment#onStart()
174      */
dispatchStart()175     public void dispatchStart() {
176         mHost.mFragmentManager.dispatchStart();
177     }
178 
179     /**
180      * Moves all Fragments managed by the controller's FragmentManager
181      * into the resume state.
182      * <p>Call when Fragments should be resumed.
183      *
184      * @see Fragment#onResume()
185      */
dispatchResume()186     public void dispatchResume() {
187         mHost.mFragmentManager.dispatchResume();
188     }
189 
190     /**
191      * Moves all Fragments managed by the controller's FragmentManager
192      * into the pause state.
193      * <p>Call when Fragments should be paused.
194      *
195      * @see Fragment#onPause()
196      */
dispatchPause()197     public void dispatchPause() {
198         mHost.mFragmentManager.dispatchPause();
199     }
200 
201     /**
202      * Moves all Fragments managed by the controller's FragmentManager
203      * into the stop state.
204      * <p>Call when Fragments should be stopped.
205      *
206      * @see Fragment#onStop()
207      */
dispatchStop()208     public void dispatchStop() {
209         mHost.mFragmentManager.dispatchStop();
210     }
211 
dispatchReallyStop()212     public void dispatchReallyStop() {
213         mHost.mFragmentManager.dispatchReallyStop();
214     }
215 
216     /**
217      * Moves all Fragments managed by the controller's FragmentManager
218      * into the destroy view state.
219      * <p>Call when the Fragment's views should be destroyed.
220      *
221      * @see Fragment#onDestroyView()
222      */
dispatchDestroyView()223     public void dispatchDestroyView() {
224         mHost.mFragmentManager.dispatchDestroyView();
225     }
226 
227     /**
228      * Moves all Fragments managed by the controller's FragmentManager
229      * into the destroy state.
230      * <p>Call when Fragments should be destroyed.
231      *
232      * @see Fragment#onDestroy()
233      */
dispatchDestroy()234     public void dispatchDestroy() {
235         mHost.mFragmentManager.dispatchDestroy();
236     }
237 
238     /**
239      * Lets all Fragments managed by the controller's FragmentManager
240      * know a configuration change occurred.
241      * <p>Call when there is a configuration change.
242      *
243      * @see Fragment#onConfigurationChanged(Configuration)
244      */
dispatchConfigurationChanged(Configuration newConfig)245     public void dispatchConfigurationChanged(Configuration newConfig) {
246         mHost.mFragmentManager.dispatchConfigurationChanged(newConfig);
247     }
248 
249     /**
250      * Lets all Fragments managed by the controller's FragmentManager
251      * know the device is in a low memory condition.
252      * <p>Call when the device is low on memory and Fragment's should trim
253      * their memory usage.
254      *
255      * @see Fragment#onLowMemory()
256      */
dispatchLowMemory()257     public void dispatchLowMemory() {
258         mHost.mFragmentManager.dispatchLowMemory();
259     }
260 
261     /**
262      * Lets all Fragments managed by the controller's FragmentManager
263      * know they should create an options menu.
264      * <p>Call when the Fragment should create an options menu.
265      *
266      * @return {@code true} if the options menu contains items to display
267      * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater)
268      */
dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater)269     public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
270         return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
271     }
272 
273     /**
274      * Lets all Fragments managed by the controller's FragmentManager
275      * know they should prepare their options menu for display.
276      * <p>Call immediately before displaying the Fragment's options menu.
277      *
278      * @return {@code true} if the options menu contains items to display
279      * @see Fragment#onPrepareOptionsMenu(Menu)
280      */
dispatchPrepareOptionsMenu(Menu menu)281     public boolean dispatchPrepareOptionsMenu(Menu menu) {
282         return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu);
283     }
284 
285     /**
286      * Sends an option item selection event to the Fragments managed by the
287      * controller's FragmentManager. Once the event has been consumed,
288      * no additional handling will be performed.
289      * <p>Call immediately after an options menu item has been selected
290      *
291      * @return {@code true} if the options menu selection event was consumed
292      * @see Fragment#onOptionsItemSelected(MenuItem)
293      */
dispatchOptionsItemSelected(MenuItem item)294     public boolean dispatchOptionsItemSelected(MenuItem item) {
295         return mHost.mFragmentManager.dispatchOptionsItemSelected(item);
296     }
297 
298     /**
299      * Sends a context item selection event to the Fragments managed by the
300      * controller's FragmentManager. Once the event has been consumed,
301      * no additional handling will be performed.
302      * <p>Call immediately after an options menu item has been selected
303      *
304      * @return {@code true} if the context menu selection event was consumed
305      * @see Fragment#onContextItemSelected(MenuItem)
306      */
dispatchContextItemSelected(MenuItem item)307     public boolean dispatchContextItemSelected(MenuItem item) {
308         return mHost.mFragmentManager.dispatchContextItemSelected(item);
309     }
310 
311     /**
312      * Lets all Fragments managed by the controller's FragmentManager
313      * know their options menu has closed.
314      * <p>Call immediately after closing the Fragment's options menu.
315      *
316      * @see Fragment#onOptionsMenuClosed(Menu)
317      */
dispatchOptionsMenuClosed(Menu menu)318     public void dispatchOptionsMenuClosed(Menu menu) {
319         mHost.mFragmentManager.dispatchOptionsMenuClosed(menu);
320     }
321 
322     /**
323      * Execute any pending actions for the Fragments managed by the
324      * controller's FragmentManager.
325      * <p>Call when queued actions can be performed [eg when the
326      * Fragment moves into a start or resume state].
327      * @return {@code true} if queued actions were performed
328      */
execPendingActions()329     public boolean execPendingActions() {
330         return mHost.mFragmentManager.execPendingActions();
331     }
332 
333     /**
334      * Starts the loaders.
335      */
doLoaderStart()336     public void doLoaderStart() {
337         mHost.doLoaderStart();
338     }
339 
340     /**
341      * Stops the loaders, optionally retaining their state. This is useful for keeping the
342      * loader state across configuration changes.
343      *
344      * @param retain When {@code true}, the loaders aren't stopped, but, their instances
345      * are retained in a started state
346      */
doLoaderStop(boolean retain)347     public void doLoaderStop(boolean retain) {
348         mHost.doLoaderStop(retain);
349     }
350 
351     /**
352      * Retains the state of each of the loaders.
353      */
doLoaderRetain()354     public void doLoaderRetain() {
355         mHost.doLoaderRetain();
356     }
357 
358     /**
359      * Destroys the loaders and, if their state is not being retained, removes them.
360      */
doLoaderDestroy()361     public void doLoaderDestroy() {
362         mHost.doLoaderDestroy();
363     }
364 
365     /**
366      * Lets the loaders know the host is ready to receive notifications.
367      */
reportLoaderStart()368     public void reportLoaderStart() {
369         mHost.reportLoaderStart();
370     }
371 
372     /**
373      * Returns a list of LoaderManagers that have opted to retain their instance across
374      * configuration changes.
375      */
retainLoaderNonConfig()376     public SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() {
377         return mHost.retainLoaderNonConfig();
378     }
379 
380     /**
381      * Restores the saved state for all LoaderManagers. The given LoaderManager list are
382      * LoaderManager instances retained across configuration changes.
383      *
384      * @see #retainLoaderNonConfig()
385      */
restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers)386     public void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
387         mHost.restoreLoaderNonConfig(loaderManagers);
388     }
389 
390     /**
391      * Dumps the current state of the loaders.
392      */
dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)393     public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
394         mHost.dumpLoaders(prefix, fd, writer, args);
395     }
396 }
397