Home | History | Annotate | Download | only in app
      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.annotation.UnsupportedAppUsage;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentSender;
     25 import android.os.Bundle;
     26 import android.os.Handler;
     27 import android.os.UserHandle;
     28 import android.util.ArrayMap;
     29 import android.view.LayoutInflater;
     30 import android.view.View;
     31 
     32 import java.io.FileDescriptor;
     33 import 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.
     41  *
     42  * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
     43  *      {@link android.support.v4.app.FragmentHostCallback}
     44  */
     45 @Deprecated
     46 public 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();
     52     /** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
     53     private ArrayMap<String, LoaderManager> mAllLoaderManagers;
     54     /** Whether or not fragment loaders should retain their state */
     55     private boolean mRetainLoaders;
     56     /** The loader manager for the fragment host [i.e. Activity#getLoaderManager()] */
     57     private LoaderManagerImpl mLoaderManager;
     58     private boolean mCheckedForLoaderManager;
     59     /** Whether or not the fragment host loader manager was started */
     60     @UnsupportedAppUsage
     61     private boolean mLoadersStarted;
     62 
     63     public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
     64         this((context instanceof Activity) ? (Activity)context : null, context,
     65                 chooseHandler(context, handler), windowAnimations);
     66     }
     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     /**
     81      * 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     /**
     94      * 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     /**
    156      * @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     /**
    170      * 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     /**
    185      * 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     /**
    193      * 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 
    206     /**
    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 
    214     @Nullable
    215     @Override
    216     public <T extends View> T onFindViewById(int id) {
    217         return null;
    218     }
    219 
    220     @Override
    221     public boolean onHasView() {
    222         return true;
    223     }
    224 
    225     boolean getRetainLoaders() {
    226         return mRetainLoaders;
    227     }
    228 
    229     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 
    265     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) {
    280         mRetainLoaders = retain;
    281 
    282         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);
    332         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();
    337         }
    338         return lm;
    339     }
    340 
    341     ArrayMap<String, LoaderManager> retainLoaderNonConfig() {
    342         boolean retainLoaders = false;
    343         if (mAllLoaderManagers != null) {
    344             // Restart any loader managers that were already stopped so that they
    345             // will be ready to retain
    346             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             }
    351             final boolean doRetainLoaders = getRetainLoaders();
    352             for (int i=0; i<N; i++) {
    353                 LoaderManagerImpl lm = loaders[i];
    354                 if (!lm.mRetaining && doRetainLoaders) {
    355                     if (!lm.mStarted) {
    356                         lm.doStart();
    357                     }
    358                     lm.doRetain();
    359                 }
    360                 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) {
    376         if (loaderManagers != null) {
    377             for (int i = 0, N = loaderManagers.size(); i < N; i++) {
    378                 ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
    379             }
    380         }
    381         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 }
    395