FragmentHostCallback.java revision 4f08e623f23cbb89881f35d3472b78d388b76dc9
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
17package android.support.v4.app;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.os.Bundle;
23import android.os.Handler;
24import android.support.annotation.Nullable;
25import android.support.v4.util.SimpleArrayMap;
26import android.util.AttributeSet;
27import 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();
46    private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;
47    private LoaderManagerImpl mLoaderManager;
48    private boolean mCheckedForLoaderManager;
49    private boolean mLoadersStarted;
50
51    public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
52        this(null /*activity*/, context, handler, windowAnimations);
53    }
54
55    FragmentHostCallback(FragmentActivity activity) {
56        this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
57    }
58
59    FragmentHostCallback(Activity activity, Context context, Handler handler,
60            int windowAnimations) {
61        mActivity = activity;
62        mContext = context;
63        mHandler = handler;
64        mWindowAnimations = windowAnimations;
65    }
66
67    /**
68     * Print internal state into the given stream.
69     *
70     * @param prefix Desired prefix to prepend at each line of output.
71     * @param fd The raw file descriptor that the dump is being sent to.
72     * @param writer The PrintWriter to which you should dump your state. This will be closed
73     *                  for you after you return.
74     * @param args additional arguments to the dump request.
75     */
76    public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
77    }
78
79    /**
80     * Return {@code true} if the fragment's state needs to be saved.
81     */
82    public boolean onShouldSaveFragmentState(Fragment fragment) {
83        return true;
84    }
85
86    /**
87     * Return a {@link LayoutInflater}.
88     * See {@link Activity#getLayoutInflater()}.
89     */
90    public LayoutInflater onGetLayoutInflater() {
91        return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
92    }
93
94    /**
95     * Return the object that's currently hosting the fragment. If a {@link Fragment}
96     * is hosted by a {@link FragmentActivity}, the object returned here should be
97     * the same object returned from {@link Fragment#getActivity()}.
98     */
99    @Nullable
100    public abstract E onGetHost();
101
102    /**
103     * Invalidates the activity's options menu.
104     * See {@link FragmentActivity#supportInvalidateOptionsMenu()}
105     */
106    public void onSupportInvalidateOptionsMenu() {
107    }
108
109    /**
110     * Starts a new {@link Activity} from the given fragment.
111     * See {@link FragmentActivity#startActivityForResult(Intent, int)}.
112     */
113    public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
114        if (requestCode != -1) {
115            throw new IllegalStateException(
116                    "Starting activity with a requestCode requires a FragmentActivity host");
117        }
118        mContext.startActivity(intent);
119    }
120
121    /**
122     * Return {@code true} if there are window animations.
123     */
124    public boolean onHasWindowAnimations() {
125        return true;
126    }
127
128    /**
129     * Return the window animations.
130     */
131    public int onGetWindowAnimations() {
132        return mWindowAnimations;
133    }
134
135    @Nullable
136    @Override
137    public View onFindViewById(int id) {
138        return null;
139    }
140
141    @Override
142    public boolean onHasView() {
143        return true;
144    }
145
146    Activity getActivity() {
147        return mActivity;
148    }
149
150    Context getContext() {
151        return mContext;
152    }
153
154    Handler getHandler() {
155        return mHandler;
156    }
157
158    FragmentManagerImpl getFragmentManagerImpl() {
159        return mFragmentManager;
160    }
161
162    LoaderManagerImpl getLoaderManagerImpl() {
163        if (mLoaderManager != null) {
164            return mLoaderManager;
165        }
166        mCheckedForLoaderManager = true;
167        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
168        return mLoaderManager;
169    }
170
171    void inactivateFragment(String who) {
172        //Log.v(TAG, "invalidateSupportFragment: who=" + who);
173        if (mAllLoaderManagers != null) {
174            LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
175            if (lm != null && !lm.mRetaining) {
176                lm.doDestroy();
177                mAllLoaderManagers.remove(who);
178            }
179        }
180    }
181
182    void onAttachFragment(Fragment fragment) {
183    }
184
185    void doLoaderStart() {
186        if (mLoadersStarted) {
187            return;
188        }
189        mLoadersStarted = true;
190
191        if (mLoaderManager != null) {
192            mLoaderManager.doStart();
193        } else if (!mCheckedForLoaderManager) {
194            mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
195            // the returned loader manager may be a new one, so we have to start it
196            if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) {
197                mLoaderManager.doStart();
198            }
199        }
200        mCheckedForLoaderManager = true;
201    }
202
203    // retain -- whether to stop the loader or retain it
204    void doLoaderStop(boolean retain) {
205        if (mLoaderManager == null) {
206            return;
207        }
208
209        if (!mLoadersStarted) {
210            return;
211        }
212        mLoadersStarted = false;
213
214        if (retain) {
215            mLoaderManager.doRetain();
216        } else {
217            mLoaderManager.doStop();
218        }
219    }
220
221    void doLoaderRetain() {
222        if (mLoaderManager == null) {
223            return;
224        }
225        mLoaderManager.doRetain();
226    }
227
228    void doLoaderDestroy() {
229        if (mLoaderManager == null) {
230            return;
231        }
232        mLoaderManager.doDestroy();
233    }
234
235    void reportLoaderStart() {
236        if (mAllLoaderManagers != null) {
237            final int N = mAllLoaderManagers.size();
238            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
239            for (int i=N-1; i>=0; i--) {
240                loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
241            }
242            for (int i=0; i<N; i++) {
243                LoaderManagerImpl lm = loaders[i];
244                lm.finishRetain();
245                lm.doReportStart();
246            }
247        }
248    }
249
250    LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
251        if (mAllLoaderManagers == null) {
252            mAllLoaderManagers = new SimpleArrayMap<String, LoaderManager>();
253        }
254        LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
255        if (lm == null) {
256            if (create) {
257                lm = new LoaderManagerImpl(who, this, started);
258                mAllLoaderManagers.put(who, lm);
259            }
260        } else {
261            lm.updateHostController(this);
262        }
263        return lm;
264    }
265
266    SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() {
267        boolean retainLoaders = false;
268        if (mAllLoaderManagers != null) {
269            // prune out any loader managers that were already stopped and so
270            // have nothing useful to retain.
271            final int N = mAllLoaderManagers.size();
272            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
273            for (int i=N-1; i>=0; i--) {
274                loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
275            }
276            for (int i=0; i<N; i++) {
277                LoaderManagerImpl lm = loaders[i];
278                if (lm.mRetaining) {
279                    retainLoaders = true;
280                } else {
281                    lm.doDestroy();
282                    mAllLoaderManagers.remove(lm.mWho);
283                }
284            }
285        }
286
287        if (retainLoaders) {
288            return mAllLoaderManagers;
289        }
290        return null;
291    }
292
293    void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
294        mAllLoaderManagers = loaderManagers;
295    }
296
297    void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
298        writer.print(prefix); writer.print("mLoadersStarted=");
299        writer.println(mLoadersStarted);
300        if (mLoaderManager != null) {
301            writer.print(prefix); writer.print("Loader Manager ");
302            writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
303            writer.println(":");
304            mLoaderManager.dump(prefix + "  ", fd, writer, args);
305        }
306    }
307}
308