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.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 
     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 
     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     /**
     79      * 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     /**
     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      */
    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     /**
    154      * @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     /**
    168      * 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     /**
    183      * 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     /**
    191      * 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 
    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      */
    209     public void onAttachFragment(Fragment fragment) {
    210     }
    211 
    212     @Nullable
    213     @Override
    214     public <T extends View> T onFindViewById(int id) {
    215         return null;
    216     }
    217 
    218     @Override
    219     public boolean onHasView() {
    220         return true;
    221     }
    222 
    223     boolean getRetainLoaders() {
    224         return mRetainLoaders;
    225     }
    226 
    227     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 
    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 
    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 
    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);
    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 
    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 
    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 
    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