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