blob: 26b4a11f4c104466f82788f72b16b4c577a69d2f [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;
Mathew Inwood4fb17d12018-08-14 14:25:44 +010021import android.annotation.UnsupportedAppUsage;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070022import android.content.Context;
23import android.content.Intent;
Clara Bayarria0c2dc32016-04-12 12:00:15 +010024import android.content.IntentSender;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070025import android.os.Bundle;
26import android.os.Handler;
Tony Mak96d26fe2017-04-11 20:05:39 +010027import android.os.UserHandle;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070028import android.util.ArrayMap;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070029import android.view.LayoutInflater;
30import android.view.View;
31
32import java.io.FileDescriptor;
33import java.io.PrintWriter;
34
35/**
36 * Integration points with the Fragment host.
37 * <p>
38 * Fragments may be hosted by any object; such as an {@link Activity}. In order to
39 * host fragments, implement {@link FragmentHostCallback}, overriding the methods
40 * applicable to the host.
Ian Lake0a1feb82017-11-13 10:26:46 -080041 *
Ian Lake1f4e67b2017-12-18 10:36:18 -080042 * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
43 * {@link android.support.v4.app.FragmentHostCallback}
Todd Kennedya5fc6f02015-04-14 18:22:54 -070044 */
Ian Lake0a1feb82017-11-13 10:26:46 -080045@Deprecated
Todd Kennedya5fc6f02015-04-14 18:22:54 -070046public abstract class FragmentHostCallback<E> extends FragmentContainer {
47 private final Activity mActivity;
48 final Context mContext;
49 private final Handler mHandler;
50 final int mWindowAnimations;
51 final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -070052 /** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
Todd Kennedya5fc6f02015-04-14 18:22:54 -070053 private ArrayMap<String, LoaderManager> mAllLoaderManagers;
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -070054 /** Whether or not fragment loaders should retain their state */
55 private boolean mRetainLoaders;
kopriva82c591b2018-10-08 15:57:00 -070056 /** The loader manager for the fragment host [i.e. Activity#getLoaderManager()] */
Todd Kennedya5fc6f02015-04-14 18:22:54 -070057 private LoaderManagerImpl mLoaderManager;
58 private boolean mCheckedForLoaderManager;
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -070059 /** Whether or not the fragment host loader manager was started */
Mathew Inwood4fb17d12018-08-14 14:25:44 +010060 @UnsupportedAppUsage
Todd Kennedya5fc6f02015-04-14 18:22:54 -070061 private boolean mLoadersStarted;
62
63 public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
George Mount86bfc662016-07-12 16:06:06 -070064 this((context instanceof Activity) ? (Activity)context : null, context,
65 chooseHandler(context, handler), windowAnimations);
Todd Kennedya5fc6f02015-04-14 18:22:54 -070066 }
67
68 FragmentHostCallback(Activity activity) {
69 this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
70 }
71
72 FragmentHostCallback(Activity activity, Context context, Handler handler,
73 int windowAnimations) {
74 mActivity = activity;
75 mContext = context;
76 mHandler = handler;
77 mWindowAnimations = windowAnimations;
78 }
79
80 /**
George Mount86bfc662016-07-12 16:06:06 -070081 * Used internally in {@link #FragmentHostCallback(Context, Handler, int)} to choose
82 * the Activity's handler or the provided handler.
83 */
84 private static Handler chooseHandler(Context context, Handler handler) {
85 if (handler == null && context instanceof Activity) {
86 Activity activity = (Activity) context;
87 return activity.mHandler;
88 } else {
89 return handler;
90 }
91 }
92
93 /**
Todd Kennedya5fc6f02015-04-14 18:22:54 -070094 * Print internal state into the given stream.
95 *
96 * @param prefix Desired prefix to prepend at each line of output.
97 * @param fd The raw file descriptor that the dump is being sent to.
98 * @param writer The PrintWriter to which you should dump your state. This will be closed
99 * for you after you return.
100 * @param args additional arguments to the dump request.
101 */
102 public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
103 }
104
105 /**
106 * Return {@code true} if the fragment's state needs to be saved.
107 */
108 public boolean onShouldSaveFragmentState(Fragment fragment) {
109 return true;
110 }
111
112 /**
113 * Return a {@link LayoutInflater}.
114 * See {@link Activity#getLayoutInflater()}.
115 */
116 public LayoutInflater onGetLayoutInflater() {
117 return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
118 }
119
120 /**
121 * Return {@code true} if the FragmentManager's LayoutInflaterFactory should be used.
122 */
123 public boolean onUseFragmentManagerInflaterFactory() {
124 return false;
125 }
126
127 /**
128 * Return the object that's currently hosting the fragment. If a {@link Fragment}
129 * is hosted by a {@link Activity}, the object returned here should be the same
130 * object returned from {@link Fragment#getActivity()}.
131 */
132 @Nullable
133 public abstract E onGetHost();
134
135 /**
136 * Invalidates the activity's options menu.
137 * See {@link Activity#invalidateOptionsMenu()}
138 */
139 public void onInvalidateOptionsMenu() {
140 }
141
142 /**
143 * Starts a new {@link Activity} from the given fragment.
144 * See {@link Activity#startActivityForResult(Intent, int)}.
145 */
146 public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode,
147 Bundle options) {
148 if (requestCode != -1) {
149 throw new IllegalStateException(
150 "Starting activity with a requestCode requires a FragmentActivity host");
151 }
152 mContext.startActivity(intent);
153 }
154
155 /**
Tony Mak96d26fe2017-04-11 20:05:39 +0100156 * @hide
157 * Starts a new {@link Activity} from the given fragment.
158 * See {@link Activity#startActivityForResult(Intent, int)}.
159 */
160 public void onStartActivityAsUserFromFragment(Fragment fragment, Intent intent, int requestCode,
161 Bundle options, UserHandle userHandle) {
162 if (requestCode != -1) {
163 throw new IllegalStateException(
164 "Starting activity with a requestCode requires a FragmentActivity host");
165 }
166 mContext.startActivityAsUser(intent, userHandle);
167 }
168
169 /**
Clara Bayarria0c2dc32016-04-12 12:00:15 +0100170 * Starts a new {@link IntentSender} from the given fragment.
171 * See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}.
172 */
173 public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
174 int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
175 int extraFlags, Bundle options) throws IntentSender.SendIntentException {
176 if (requestCode != -1) {
177 throw new IllegalStateException(
178 "Starting intent sender with a requestCode requires a FragmentActivity host");
179 }
180 mContext.startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags,
181 options);
182 }
183
184 /**
Svetoslav970b59c2015-06-09 16:05:21 -0700185 * Requests permissions from the given fragment.
186 * See {@link Activity#requestPermissions(String[], int)}
187 */
188 public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
189 @NonNull String[] permissions, int requestCode) {
190 }
191
192 /**
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700193 * Return {@code true} if there are window animations.
194 */
195 public boolean onHasWindowAnimations() {
196 return true;
197 }
198
199 /**
200 * Return the window animations.
201 */
202 public int onGetWindowAnimations() {
203 return mWindowAnimations;
204 }
205
Todd Kennedy434bd652015-05-04 12:29:50 -0700206 /**
207 * Called when a {@link Fragment} is being attached to this host, immediately
208 * after the call to its {@link Fragment#onAttach(Context)} method and before
209 * {@link Fragment#onCreate(Bundle)}.
210 */
211 public void onAttachFragment(Fragment fragment) {
212 }
213
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700214 @Nullable
215 @Override
Alan Viverette04fd4702017-04-13 16:37:06 -0400216 public <T extends View> T onFindViewById(int id) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700217 return null;
218 }
219
220 @Override
221 public boolean onHasView() {
222 return true;
223 }
224
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -0700225 boolean getRetainLoaders() {
226 return mRetainLoaders;
227 }
228
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700229 Activity getActivity() {
230 return mActivity;
231 }
232
233 Context getContext() {
234 return mContext;
235 }
236
237 Handler getHandler() {
238 return mHandler;
239 }
240
241 FragmentManagerImpl getFragmentManagerImpl() {
242 return mFragmentManager;
243 }
244
245 LoaderManagerImpl getLoaderManagerImpl() {
246 if (mLoaderManager != null) {
247 return mLoaderManager;
248 }
249 mCheckedForLoaderManager = true;
250 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
251 return mLoaderManager;
252 }
253
254 void inactivateFragment(String who) {
255 //Log.v(TAG, "invalidateSupportFragment: who=" + who);
256 if (mAllLoaderManagers != null) {
257 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
258 if (lm != null && !lm.mRetaining) {
259 lm.doDestroy();
260 mAllLoaderManagers.remove(who);
261 }
262 }
263 }
264
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700265 void doLoaderStart() {
266 if (mLoadersStarted) {
267 return;
268 }
269 mLoadersStarted = true;
270
271 if (mLoaderManager != null) {
272 mLoaderManager.doStart();
273 } else if (!mCheckedForLoaderManager) {
274 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
275 }
276 mCheckedForLoaderManager = true;
277 }
278
279 void doLoaderStop(boolean retain) {
Todd Kennedy2ee19c7f2015-10-19 15:31:51 -0700280 mRetainLoaders = retain;
281
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700282 if (mLoaderManager == null) {
283 return;
284 }
285
286 if (!mLoadersStarted) {
287 return;
288 }
289 mLoadersStarted = false;
290
291 if (retain) {
292 mLoaderManager.doRetain();
293 } else {
294 mLoaderManager.doStop();
295 }
296 }
297
298 void doLoaderRetain() {
299 if (mLoaderManager == null) {
300 return;
301 }
302 mLoaderManager.doRetain();
303 }
304
305 void doLoaderDestroy() {
306 if (mLoaderManager == null) {
307 return;
308 }
309 mLoaderManager.doDestroy();
310 }
311
312 void reportLoaderStart() {
313 if (mAllLoaderManagers != null) {
314 final int N = mAllLoaderManagers.size();
315 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
316 for (int i=N-1; i>=0; i--) {
317 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
318 }
319 for (int i=0; i<N; i++) {
320 LoaderManagerImpl lm = loaders[i];
321 lm.finishRetain();
322 lm.doReportStart();
323 }
324 }
325 }
326
327 LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
328 if (mAllLoaderManagers == null) {
329 mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
330 }
331 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
George Mounte6f7dae2017-03-02 13:22:18 -0800332 if (lm == null && create) {
333 lm = new LoaderManagerImpl(who, this, started);
334 mAllLoaderManagers.put(who, lm);
335 } else if (started && lm != null && !lm.mStarted){
336 lm.doStart();
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700337 }
338 return lm;
339 }
340
341 ArrayMap<String, LoaderManager> retainLoaderNonConfig() {
342 boolean retainLoaders = false;
343 if (mAllLoaderManagers != null) {
Adam Powellcbade7f2016-04-15 11:14:37 -0700344 // Restart any loader managers that were already stopped so that they
345 // will be ready to retain
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700346 final int N = mAllLoaderManagers.size();
347 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
348 for (int i=N-1; i>=0; i--) {
349 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
350 }
Adam Powellcbade7f2016-04-15 11:14:37 -0700351 final boolean doRetainLoaders = getRetainLoaders();
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700352 for (int i=0; i<N; i++) {
353 LoaderManagerImpl lm = loaders[i];
Adam Powellcbade7f2016-04-15 11:14:37 -0700354 if (!lm.mRetaining && doRetainLoaders) {
355 if (!lm.mStarted) {
356 lm.doStart();
357 }
358 lm.doRetain();
359 }
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700360 if (lm.mRetaining) {
361 retainLoaders = true;
362 } else {
363 lm.doDestroy();
364 mAllLoaderManagers.remove(lm.mWho);
365 }
366 }
367 }
368
369 if (retainLoaders) {
370 return mAllLoaderManagers;
371 }
372 return null;
373 }
374
375 void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
Adam Powell100ba762016-09-22 10:47:40 -0700376 if (loaderManagers != null) {
377 for (int i = 0, N = loaderManagers.size(); i < N; i++) {
378 ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
379 }
Adam Powell180202f2016-09-21 15:41:47 -0700380 }
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700381 mAllLoaderManagers = loaderManagers;
382 }
383
384 void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
385 writer.print(prefix); writer.print("mLoadersStarted=");
386 writer.println(mLoadersStarted);
387 if (mLoaderManager != null) {
388 writer.print(prefix); writer.print("Loader Manager ");
389 writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
390 writer.println(":");
391 mLoaderManager.dump(prefix + " ", fd, writer, args);
392 }
393 }
394}