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      */
restoreAllState(Parcelable state, List<Fragment> nonConfigList)121     public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) {
122         mHost.mFragmentManager.restoreAllState(state, nonConfigList);
123     }
124 
125     /**
126      * Returns a list of Fragments that have opted to retain their instance across
127      * configuration changes.
128      */
retainNonConfig()129     public List<Fragment> retainNonConfig() {
130         return mHost.mFragmentManager.retainNonConfig();
131     }
132 
133     /**
134      * Moves all Fragments managed by the controller's FragmentManager
135      * into the create state.
136      * <p>Call when Fragments should be created.
137      *
138      * @see Fragment#onCreate(Bundle)
139      */
dispatchCreate()140     public void dispatchCreate() {
141         mHost.mFragmentManager.dispatchCreate();
142     }
143 
144     /**
145      * Moves all Fragments managed by the controller's FragmentManager
146      * into the activity created state.
147      * <p>Call when Fragments should be informed their host has been created.
148      *
149      * @see Fragment#onActivityCreated(Bundle)
150      */
dispatchActivityCreated()151     public void dispatchActivityCreated() {
152         mHost.mFragmentManager.dispatchActivityCreated();
153     }
154 
155     /**
156      * Moves all Fragments managed by the controller's FragmentManager
157      * into the start state.
158      * <p>Call when Fragments should be started.
159      *
160      * @see Fragment#onStart()
161      */
dispatchStart()162     public void dispatchStart() {
163         mHost.mFragmentManager.dispatchStart();
164     }
165 
166     /**
167      * Moves all Fragments managed by the controller's FragmentManager
168      * into the resume state.
169      * <p>Call when Fragments should be resumed.
170      *
171      * @see Fragment#onResume()
172      */
dispatchResume()173     public void dispatchResume() {
174         mHost.mFragmentManager.dispatchResume();
175     }
176 
177     /**
178      * Moves all Fragments managed by the controller's FragmentManager
179      * into the pause state.
180      * <p>Call when Fragments should be paused.
181      *
182      * @see Fragment#onPause()
183      */
dispatchPause()184     public void dispatchPause() {
185         mHost.mFragmentManager.dispatchPause();
186     }
187 
188     /**
189      * Moves all Fragments managed by the controller's FragmentManager
190      * into the stop state.
191      * <p>Call when Fragments should be stopped.
192      *
193      * @see Fragment#onStop()
194      */
dispatchStop()195     public void dispatchStop() {
196         mHost.mFragmentManager.dispatchStop();
197     }
198 
199     /**
200      * Moves all Fragments managed by the controller's FragmentManager
201      * into the destroy view state.
202      * <p>Call when the Fragment's views should be destroyed.
203      *
204      * @see Fragment#onDestroyView()
205      */
dispatchDestroyView()206     public void dispatchDestroyView() {
207         mHost.mFragmentManager.dispatchDestroyView();
208     }
209 
210     /**
211      * Moves all Fragments managed by the controller's FragmentManager
212      * into the destroy state.
213      * <p>Call when Fragments should be destroyed.
214      *
215      * @see Fragment#onDestroy()
216      */
dispatchDestroy()217     public void dispatchDestroy() {
218         mHost.mFragmentManager.dispatchDestroy();
219     }
220 
221     /**
222      * Lets all Fragments managed by the controller's FragmentManager
223      * know a configuration change occurred.
224      * <p>Call when there is a configuration change.
225      *
226      * @see Fragment#onConfigurationChanged(Configuration)
227      */
dispatchConfigurationChanged(Configuration newConfig)228     public void dispatchConfigurationChanged(Configuration newConfig) {
229         mHost.mFragmentManager.dispatchConfigurationChanged(newConfig);
230     }
231 
232     /**
233      * Lets all Fragments managed by the controller's FragmentManager
234      * know the device is in a low memory condition.
235      * <p>Call when the device is low on memory and Fragment's should trim
236      * their memory usage.
237      *
238      * @see Fragment#onLowMemory()
239      */
dispatchLowMemory()240     public void dispatchLowMemory() {
241         mHost.mFragmentManager.dispatchLowMemory();
242     }
243 
244     /**
245      * Lets all Fragments managed by the controller's FragmentManager
246      * know they should trim their memory usage.
247      * <p>Call when the Fragment can release allocated memory [such as if
248      * the Fragment is in the background].
249      *
250      * @see Fragment#onTrimMemory(int)
251      */
dispatchTrimMemory(int level)252     public void dispatchTrimMemory(int level) {
253         mHost.mFragmentManager.dispatchTrimMemory(level);
254     }
255 
256     /**
257      * Lets all Fragments managed by the controller's FragmentManager
258      * know they should create an options menu.
259      * <p>Call when the Fragment should create an options menu.
260      *
261      * @return {@code true} if the options menu contains items to display
262      * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater)
263      */
dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater)264     public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
265         return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
266     }
267 
268     /**
269      * Lets all Fragments managed by the controller's FragmentManager
270      * know they should prepare their options menu for display.
271      * <p>Call immediately before displaying the Fragment's options menu.
272      *
273      * @return {@code true} if the options menu contains items to display
274      * @see Fragment#onPrepareOptionsMenu(Menu)
275      */
dispatchPrepareOptionsMenu(Menu menu)276     public boolean dispatchPrepareOptionsMenu(Menu menu) {
277         return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu);
278     }
279 
280     /**
281      * Sends an option item selection event to the Fragments managed by the
282      * controller's FragmentManager. Once the event has been consumed,
283      * no additional handling will be performed.
284      * <p>Call immediately after an options menu item has been selected
285      *
286      * @return {@code true} if the options menu selection event was consumed
287      * @see Fragment#onOptionsItemSelected(MenuItem)
288      */
dispatchOptionsItemSelected(MenuItem item)289     public boolean dispatchOptionsItemSelected(MenuItem item) {
290         return mHost.mFragmentManager.dispatchOptionsItemSelected(item);
291     }
292 
293     /**
294      * Sends a context item selection event to the Fragments managed by the
295      * controller's FragmentManager. Once the event has been consumed,
296      * no additional handling will be performed.
297      * <p>Call immediately after an options menu item has been selected
298      *
299      * @return {@code true} if the context menu selection event was consumed
300      * @see Fragment#onContextItemSelected(MenuItem)
301      */
dispatchContextItemSelected(MenuItem item)302     public boolean dispatchContextItemSelected(MenuItem item) {
303         return mHost.mFragmentManager.dispatchContextItemSelected(item);
304     }
305 
306     /**
307      * Lets all Fragments managed by the controller's FragmentManager
308      * know their options menu has closed.
309      * <p>Call immediately after closing the Fragment's options menu.
310      *
311      * @see Fragment#onOptionsMenuClosed(Menu)
312      */
dispatchOptionsMenuClosed(Menu menu)313     public void dispatchOptionsMenuClosed(Menu menu) {
314         mHost.mFragmentManager.dispatchOptionsMenuClosed(menu);
315     }
316 
317     /**
318      * Execute any pending actions for the Fragments managed by the
319      * controller's FragmentManager.
320      * <p>Call when queued actions can be performed [eg when the
321      * Fragment moves into a start or resume state].
322      * @return {@code true} if queued actions were performed
323      */
execPendingActions()324     public boolean execPendingActions() {
325         return mHost.mFragmentManager.execPendingActions();
326     }
327 
328     /**
329      * Starts the loaders.
330      */
doLoaderStart()331     public void doLoaderStart() {
332         mHost.doLoaderStart();
333     }
334 
335     /**
336      * Stops the loaders, optionally retaining their state. This is useful for keeping the
337      * loader state across configuration changes.
338      *
339      * @param retain When {@code true}, the loaders aren't stopped, but, their instances
340      * are retained in a started state
341      */
doLoaderStop(boolean retain)342     public void doLoaderStop(boolean retain) {
343         mHost.doLoaderStop(retain);
344     }
345 
346     /**
347      * Destroys the loaders and, if their state is not being retained, removes them.
348      */
doLoaderDestroy()349     public void doLoaderDestroy() {
350         mHost.doLoaderDestroy();
351     }
352 
353     /**
354      * Lets the loaders know the host is ready to receive notifications.
355      */
reportLoaderStart()356     public void reportLoaderStart() {
357         mHost.reportLoaderStart();
358     }
359 
360     /**
361      * Returns a list of LoaderManagers that have opted to retain their instance across
362      * configuration changes.
363      */
retainLoaderNonConfig()364     public ArrayMap<String, LoaderManager> retainLoaderNonConfig() {
365         return mHost.retainLoaderNonConfig();
366     }
367 
368     /**
369      * Restores the saved state for all LoaderManagers. The given LoaderManager list are
370      * LoaderManager instances retained across configuration changes.
371      *
372      * @see #retainLoaderNonConfig()
373      */
restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers)374     public void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
375         mHost.restoreLoaderNonConfig(loaderManagers);
376     }
377 
378     /**
379      * Dumps the current state of the loaders.
380      */
dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)381     public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
382         mHost.dumpLoaders(prefix, fd, writer, args);
383     }
384 }
385