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