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
17package android.app;
18
19import android.annotation.Nullable;
20import android.content.Context;
21import android.content.res.Configuration;
22import android.os.Bundle;
23import android.os.Parcelable;
24import android.util.ArrayMap;
25import android.util.AttributeSet;
26import android.view.Menu;
27import android.view.MenuInflater;
28import android.view.MenuItem;
29import android.view.View;
30
31import java.io.FileDescriptor;
32import java.io.PrintWriter;
33import 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 */
41public class FragmentController {
42    private final FragmentHostCallback<?> mHost;
43
44    /**
45     * Returns a {@link FragmentController}.
46     */
47    public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
48        return new FragmentController(callbacks);
49    }
50
51    private FragmentController(FragmentHostCallback<?> callbacks) {
52        mHost = callbacks;
53    }
54
55    /**
56     * Returns a {@link FragmentManager} for this controller.
57     */
58    public FragmentManager getFragmentManager() {
59        return mHost.getFragmentManagerImpl();
60    }
61
62    /**
63     * Returns a {@link LoaderManager}.
64     */
65    public LoaderManager getLoaderManager() {
66        return mHost.getLoaderManagerImpl();
67    }
68
69    /**
70     * Returns a fragment with the given identifier.
71     */
72    @Nullable
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     * */
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     */
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     */
104    public void noteStateNotSaved() {
105        mHost.mFragmentManager.noteStateNotSaved();
106    }
107
108    /**
109     * Saves the state for all Fragments.
110     */
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    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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
324    public boolean execPendingActions() {
325        return mHost.mFragmentManager.execPendingActions();
326    }
327
328    /**
329     * Starts the loaders.
330     */
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     */
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     */
349    public void doLoaderDestroy() {
350        mHost.doLoaderDestroy();
351    }
352
353    /**
354     * Lets the loaders know the host is ready to receive notifications.
355     */
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     */
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     */
374    public void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
375        mHost.restoreLoaderNonConfig(loaderManagers);
376    }
377
378    /**
379     * Dumps the current state of the loaders.
380     */
381    public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
382        mHost.dumpLoaders(prefix, fd, writer, args);
383    }
384}
385