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.compat.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 FragmentHostCallback(Context context, Handler handler, int windowAnimations)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 FragmentHostCallback(Activity activity)68 FragmentHostCallback(Activity activity) { 69 this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/); 70 } 71 FragmentHostCallback(Activity activity, Context context, Handler handler, int windowAnimations)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 */ chooseHandler(Context context, Handler handler)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 */ onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)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 */ onShouldSaveFragmentState(Fragment fragment)108 public boolean onShouldSaveFragmentState(Fragment fragment) { 109 return true; 110 } 111 112 /** 113 * Return a {@link LayoutInflater}. 114 * See {@link Activity#getLayoutInflater()}. 115 */ onGetLayoutInflater()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 */ onUseFragmentManagerInflaterFactory()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 onGetHost()133 public abstract E onGetHost(); 134 135 /** 136 * Invalidates the activity's options menu. 137 * See {@link Activity#invalidateOptionsMenu()} 138 */ onInvalidateOptionsMenu()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 */ onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)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 */ onStartActivityAsUserFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options, UserHandle userHandle)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 */ onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)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 */ onRequestPermissionsFromFragment(@onNull Fragment fragment, @NonNull String[] permissions, int requestCode)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 */ onHasWindowAnimations()195 public boolean onHasWindowAnimations() { 196 return true; 197 } 198 199 /** 200 * Return the window animations. 201 */ onGetWindowAnimations()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 */ onAttachFragment(Fragment fragment)211 public void onAttachFragment(Fragment fragment) { 212 } 213 214 @Nullable 215 @Override onFindViewById(int id)216 public <T extends View> T onFindViewById(int id) { 217 return null; 218 } 219 220 @Override onHasView()221 public boolean onHasView() { 222 return true; 223 } 224 getRetainLoaders()225 boolean getRetainLoaders() { 226 return mRetainLoaders; 227 } 228 getActivity()229 Activity getActivity() { 230 return mActivity; 231 } 232 getContext()233 Context getContext() { 234 return mContext; 235 } 236 getHandler()237 Handler getHandler() { 238 return mHandler; 239 } 240 getFragmentManagerImpl()241 FragmentManagerImpl getFragmentManagerImpl() { 242 return mFragmentManager; 243 } 244 getLoaderManagerImpl()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 inactivateFragment(String who)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 doLoaderStart()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 doLoaderStop(boolean retain)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 doLoaderRetain()298 void doLoaderRetain() { 299 if (mLoaderManager == null) { 300 return; 301 } 302 mLoaderManager.doRetain(); 303 } 304 doLoaderDestroy()305 void doLoaderDestroy() { 306 if (mLoaderManager == null) { 307 return; 308 } 309 mLoaderManager.doDestroy(); 310 } 311 reportLoaderStart()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 getLoaderManager(String who, boolean started, boolean create)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 retainLoaderNonConfig()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 restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers)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 dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)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