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