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 
17 package android.app;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentSender;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.UserHandle;
27 import android.util.ArrayMap;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 
31 import java.io.FileDescriptor;
32 import 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.
40  *
41  * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
42  *      {@link android.support.v4.app.FragmentHostCallback}
43  */
44 @Deprecated
45 public 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();
51     /** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
52     private ArrayMap<String, LoaderManager> mAllLoaderManagers;
53     /** Whether or not fragment loaders should retain their state */
54     private boolean mRetainLoaders;
55     /** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */
56     private LoaderManagerImpl mLoaderManager;
57     private boolean mCheckedForLoaderManager;
58     /** Whether or not the fragment host loader manager was started */
59     private boolean mLoadersStarted;
60 
FragmentHostCallback(Context context, Handler handler, int windowAnimations)61     public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
62         this((context instanceof Activity) ? (Activity)context : null, context,
63                 chooseHandler(context, handler), windowAnimations);
64     }
65 
FragmentHostCallback(Activity activity)66     FragmentHostCallback(Activity activity) {
67         this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
68     }
69 
FragmentHostCallback(Activity activity, Context context, Handler handler, int windowAnimations)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     /**
79      * Used internally in {@link #FragmentHostCallback(Context, Handler, int)} to choose
80      * the Activity's handler or the provided handler.
81      */
chooseHandler(Context context, Handler handler)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     /**
92      * 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      */
onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)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      */
onShouldSaveFragmentState(Fragment fragment)106     public boolean onShouldSaveFragmentState(Fragment fragment) {
107         return true;
108     }
109 
110     /**
111      * Return a {@link LayoutInflater}.
112      * See {@link Activity#getLayoutInflater()}.
113      */
onGetLayoutInflater()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      */
onUseFragmentManagerInflaterFactory()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
onGetHost()131     public abstract E onGetHost();
132 
133     /**
134      * Invalidates the activity's options menu.
135      * See {@link Activity#invalidateOptionsMenu()}
136      */
onInvalidateOptionsMenu()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      */
onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)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     /**
154      * @hide
155      * Starts a new {@link Activity} from the given fragment.
156      * See {@link Activity#startActivityForResult(Intent, int)}.
157      */
onStartActivityAsUserFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options, UserHandle userHandle)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     /**
168      * Starts a new {@link IntentSender} from the given fragment.
169      * See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}.
170      */
onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)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     /**
183      * Requests permissions from the given fragment.
184      * See {@link Activity#requestPermissions(String[], int)}
185      */
onRequestPermissionsFromFragment(@onNull Fragment fragment, @NonNull String[] permissions, int requestCode)186     public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
187             @NonNull String[] permissions, int requestCode) {
188     }
189 
190     /**
191      * Return {@code true} if there are window animations.
192      */
onHasWindowAnimations()193     public boolean onHasWindowAnimations() {
194         return true;
195     }
196 
197     /**
198      * Return the window animations.
199      */
onGetWindowAnimations()200     public int onGetWindowAnimations() {
201         return mWindowAnimations;
202     }
203 
204     /**
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      */
onAttachFragment(Fragment fragment)209     public void onAttachFragment(Fragment fragment) {
210     }
211 
212     @Nullable
213     @Override
onFindViewById(int id)214     public <T extends View> T onFindViewById(int id) {
215         return null;
216     }
217 
218     @Override
onHasView()219     public boolean onHasView() {
220         return true;
221     }
222 
getRetainLoaders()223     boolean getRetainLoaders() {
224         return mRetainLoaders;
225     }
226 
getActivity()227     Activity getActivity() {
228         return mActivity;
229     }
230 
getContext()231     Context getContext() {
232         return mContext;
233     }
234 
getHandler()235     Handler getHandler() {
236         return mHandler;
237     }
238 
getFragmentManagerImpl()239     FragmentManagerImpl getFragmentManagerImpl() {
240         return mFragmentManager;
241     }
242 
getLoaderManagerImpl()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 
inactivateFragment(String who)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 
doLoaderStart()263     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 
doLoaderStop(boolean retain)277     void doLoaderStop(boolean retain) {
278         mRetainLoaders = retain;
279 
280         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 
doLoaderRetain()296     void doLoaderRetain() {
297         if (mLoaderManager == null) {
298             return;
299         }
300         mLoaderManager.doRetain();
301     }
302 
doLoaderDestroy()303     void doLoaderDestroy() {
304         if (mLoaderManager == null) {
305             return;
306         }
307         mLoaderManager.doDestroy();
308     }
309 
reportLoaderStart()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 
getLoaderManager(String who, boolean started, boolean create)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);
330         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();
335         }
336         return lm;
337     }
338 
retainLoaderNonConfig()339     ArrayMap<String, LoaderManager> retainLoaderNonConfig() {
340         boolean retainLoaders = false;
341         if (mAllLoaderManagers != null) {
342             // Restart any loader managers that were already stopped so that they
343             // will be ready to retain
344             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             }
349             final boolean doRetainLoaders = getRetainLoaders();
350             for (int i=0; i<N; i++) {
351                 LoaderManagerImpl lm = loaders[i];
352                 if (!lm.mRetaining && doRetainLoaders) {
353                     if (!lm.mStarted) {
354                         lm.doStart();
355                     }
356                     lm.doRetain();
357                 }
358                 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 
restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers)373     void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
374         if (loaderManagers != null) {
375             for (int i = 0, N = loaderManagers.size(); i < N; i++) {
376                 ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
377             }
378         }
379         mAllLoaderManagers = loaderManagers;
380     }
381 
dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)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 }
393