blob: d869168e2b6a55a266093c22a6ab1f44d37483fd [file] [log] [blame]
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001/*
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
Svetoslav970b59c2015-06-09 16:05:21 -070019import android.annotation.NonNull;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070020import android.annotation.Nullable;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070021import android.content.Context;
22import android.content.Intent;
Clara Bayarria0c2dc32016-04-12 12:00:15 +010023import android.content.IntentSender;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070024import android.os.Bundle;
25import android.os.Handler;
26import android.util.ArrayMap;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070027import android.view.LayoutInflater;
28import android.view.View;
29
30import java.io.FileDescriptor;
31import java.io.PrintWriter;
32
33/**
34 * Integration points with the Fragment host.
35 * <p>
36 * Fragments may be hosted by any object; such as an {@link Activity}. In order to
37 * host fragments, implement {@link FragmentHostCallback}, overriding the methods
38 * applicable to the host.
39 */
40public abstract class FragmentHostCallback<E> extends FragmentContainer {
41 private final Activity mActivity;
42 final Context mContext;
43 private final Handler mHandler;
44 final int mWindowAnimations;
45 final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -070046 /** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
Todd Kennedya5fc6f02015-04-14 18:22:54 -070047 private ArrayMap<String, LoaderManager> mAllLoaderManagers;
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -070048 /** Whether or not fragment loaders should retain their state */
49 private boolean mRetainLoaders;
50 /** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */
Todd Kennedya5fc6f02015-04-14 18:22:54 -070051 private LoaderManagerImpl mLoaderManager;
52 private boolean mCheckedForLoaderManager;
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -070053 /** Whether or not the fragment host loader manager was started */
Todd Kennedya5fc6f02015-04-14 18:22:54 -070054 private boolean mLoadersStarted;
55
56 public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
57 this(null /*activity*/, context, handler, windowAnimations);
58 }
59
60 FragmentHostCallback(Activity activity) {
61 this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
62 }
63
64 FragmentHostCallback(Activity activity, Context context, Handler handler,
65 int windowAnimations) {
66 mActivity = activity;
67 mContext = context;
68 mHandler = handler;
69 mWindowAnimations = windowAnimations;
70 }
71
72 /**
73 * Print internal state into the given stream.
74 *
75 * @param prefix Desired prefix to prepend at each line of output.
76 * @param fd The raw file descriptor that the dump is being sent to.
77 * @param writer The PrintWriter to which you should dump your state. This will be closed
78 * for you after you return.
79 * @param args additional arguments to the dump request.
80 */
81 public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
82 }
83
84 /**
85 * Return {@code true} if the fragment's state needs to be saved.
86 */
87 public boolean onShouldSaveFragmentState(Fragment fragment) {
88 return true;
89 }
90
91 /**
92 * Return a {@link LayoutInflater}.
93 * See {@link Activity#getLayoutInflater()}.
94 */
95 public LayoutInflater onGetLayoutInflater() {
96 return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
97 }
98
99 /**
100 * Return {@code true} if the FragmentManager's LayoutInflaterFactory should be used.
101 */
102 public boolean onUseFragmentManagerInflaterFactory() {
103 return false;
104 }
105
106 /**
107 * Return the object that's currently hosting the fragment. If a {@link Fragment}
108 * is hosted by a {@link Activity}, the object returned here should be the same
109 * object returned from {@link Fragment#getActivity()}.
110 */
111 @Nullable
112 public abstract E onGetHost();
113
114 /**
115 * Invalidates the activity's options menu.
116 * See {@link Activity#invalidateOptionsMenu()}
117 */
118 public void onInvalidateOptionsMenu() {
119 }
120
121 /**
122 * Starts a new {@link Activity} from the given fragment.
123 * See {@link Activity#startActivityForResult(Intent, int)}.
124 */
125 public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode,
126 Bundle options) {
127 if (requestCode != -1) {
128 throw new IllegalStateException(
129 "Starting activity with a requestCode requires a FragmentActivity host");
130 }
131 mContext.startActivity(intent);
132 }
133
134 /**
Clara Bayarria0c2dc32016-04-12 12:00:15 +0100135 * Starts a new {@link IntentSender} from the given fragment.
136 * See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}.
137 */
138 public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
139 int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
140 int extraFlags, Bundle options) throws IntentSender.SendIntentException {
141 if (requestCode != -1) {
142 throw new IllegalStateException(
143 "Starting intent sender with a requestCode requires a FragmentActivity host");
144 }
145 mContext.startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags,
146 options);
147 }
148
149 /**
Svetoslav970b59c2015-06-09 16:05:21 -0700150 * Requests permissions from the given fragment.
151 * See {@link Activity#requestPermissions(String[], int)}
152 */
153 public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
154 @NonNull String[] permissions, int requestCode) {
155 }
156
157 /**
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700158 * Return {@code true} if there are window animations.
159 */
160 public boolean onHasWindowAnimations() {
161 return true;
162 }
163
164 /**
165 * Return the window animations.
166 */
167 public int onGetWindowAnimations() {
168 return mWindowAnimations;
169 }
170
Todd Kennedy434bd652015-05-04 12:29:50 -0700171 /**
172 * Called when a {@link Fragment} is being attached to this host, immediately
173 * after the call to its {@link Fragment#onAttach(Context)} method and before
174 * {@link Fragment#onCreate(Bundle)}.
175 */
176 public void onAttachFragment(Fragment fragment) {
177 }
178
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700179 @Nullable
180 @Override
181 public View onFindViewById(int id) {
182 return null;
183 }
184
185 @Override
186 public boolean onHasView() {
187 return true;
188 }
189
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -0700190 boolean getRetainLoaders() {
191 return mRetainLoaders;
192 }
193
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700194 Activity getActivity() {
195 return mActivity;
196 }
197
198 Context getContext() {
199 return mContext;
200 }
201
202 Handler getHandler() {
203 return mHandler;
204 }
205
206 FragmentManagerImpl getFragmentManagerImpl() {
207 return mFragmentManager;
208 }
209
210 LoaderManagerImpl getLoaderManagerImpl() {
211 if (mLoaderManager != null) {
212 return mLoaderManager;
213 }
214 mCheckedForLoaderManager = true;
215 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
216 return mLoaderManager;
217 }
218
219 void inactivateFragment(String who) {
220 //Log.v(TAG, "invalidateSupportFragment: who=" + who);
221 if (mAllLoaderManagers != null) {
222 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
223 if (lm != null && !lm.mRetaining) {
224 lm.doDestroy();
225 mAllLoaderManagers.remove(who);
226 }
227 }
228 }
229
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700230 void doLoaderStart() {
231 if (mLoadersStarted) {
232 return;
233 }
234 mLoadersStarted = true;
235
236 if (mLoaderManager != null) {
237 mLoaderManager.doStart();
238 } else if (!mCheckedForLoaderManager) {
239 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
240 }
241 mCheckedForLoaderManager = true;
242 }
243
244 void doLoaderStop(boolean retain) {
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -0700245 mRetainLoaders = retain;
246
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700247 if (mLoaderManager == null) {
248 return;
249 }
250
251 if (!mLoadersStarted) {
252 return;
253 }
254 mLoadersStarted = false;
255
256 if (retain) {
257 mLoaderManager.doRetain();
258 } else {
259 mLoaderManager.doStop();
260 }
261 }
262
263 void doLoaderRetain() {
264 if (mLoaderManager == null) {
265 return;
266 }
267 mLoaderManager.doRetain();
268 }
269
270 void doLoaderDestroy() {
271 if (mLoaderManager == null) {
272 return;
273 }
274 mLoaderManager.doDestroy();
275 }
276
277 void reportLoaderStart() {
278 if (mAllLoaderManagers != null) {
279 final int N = mAllLoaderManagers.size();
280 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
281 for (int i=N-1; i>=0; i--) {
282 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
283 }
284 for (int i=0; i<N; i++) {
285 LoaderManagerImpl lm = loaders[i];
286 lm.finishRetain();
287 lm.doReportStart();
288 }
289 }
290 }
291
292 LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
293 if (mAllLoaderManagers == null) {
294 mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
295 }
296 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
297 if (lm == null) {
298 if (create) {
299 lm = new LoaderManagerImpl(who, this, started);
300 mAllLoaderManagers.put(who, lm);
301 }
302 } else {
303 lm.updateHostController(this);
304 }
305 return lm;
306 }
307
308 ArrayMap<String, LoaderManager> retainLoaderNonConfig() {
309 boolean retainLoaders = false;
310 if (mAllLoaderManagers != null) {
Adam Powellcbade7f2016-04-15 11:14:37 -0700311 // Restart any loader managers that were already stopped so that they
312 // will be ready to retain
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700313 final int N = mAllLoaderManagers.size();
314 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
315 for (int i=N-1; i>=0; i--) {
316 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
317 }
Adam Powellcbade7f2016-04-15 11:14:37 -0700318 final boolean doRetainLoaders = getRetainLoaders();
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700319 for (int i=0; i<N; i++) {
320 LoaderManagerImpl lm = loaders[i];
Adam Powellcbade7f2016-04-15 11:14:37 -0700321 if (!lm.mRetaining && doRetainLoaders) {
322 if (!lm.mStarted) {
323 lm.doStart();
324 }
325 lm.doRetain();
326 }
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700327 if (lm.mRetaining) {
328 retainLoaders = true;
329 } else {
330 lm.doDestroy();
331 mAllLoaderManagers.remove(lm.mWho);
332 }
333 }
334 }
335
336 if (retainLoaders) {
337 return mAllLoaderManagers;
338 }
339 return null;
340 }
341
342 void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
Adam Powell100ba762016-09-22 10:47:40 -0700343 if (loaderManagers != null) {
344 for (int i = 0, N = loaderManagers.size(); i < N; i++) {
345 ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
346 }
Adam Powell180202f2016-09-21 15:41:47 -0700347 }
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700348 mAllLoaderManagers = loaderManagers;
349 }
350
351 void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
352 writer.print(prefix); writer.print("mLoadersStarted=");
353 writer.println(mLoadersStarted);
354 if (mLoaderManager != null) {
355 writer.print(prefix); writer.print("Loader Manager ");
356 writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
357 writer.println(":");
358 mLoaderManager.dump(prefix + " ", fd, writer, args);
359 }
360 }
361}