1/* 2 * Copyright 2018 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 androidx.fragment.app; 18 19import android.content.Context; 20import android.content.res.Configuration; 21import android.os.Parcelable; 22import android.util.AttributeSet; 23import android.view.Menu; 24import android.view.MenuInflater; 25import android.view.MenuItem; 26import android.view.View; 27 28import androidx.annotation.Nullable; 29import androidx.collection.SimpleArrayMap; 30import androidx.loader.app.LoaderManager; 31 32import java.io.FileDescriptor; 33import java.io.PrintWriter; 34import java.util.List; 35 36/** 37 * Provides integration points with a {@link FragmentManager} for a fragment host. 38 * <p> 39 * It is the responsibility of the host to take care of the Fragment's lifecycle. 40 * The methods provided by {@link FragmentController} are for that purpose. 41 */ 42public class FragmentController { 43 private final FragmentHostCallback<?> mHost; 44 45 /** 46 * Returns a {@link FragmentController}. 47 */ 48 public static FragmentController createController(FragmentHostCallback<?> callbacks) { 49 return new FragmentController(callbacks); 50 } 51 52 private FragmentController(FragmentHostCallback<?> callbacks) { 53 mHost = callbacks; 54 } 55 56 /** 57 * Returns a {@link FragmentManager} for this controller. 58 */ 59 public FragmentManager getSupportFragmentManager() { 60 return mHost.getFragmentManagerImpl(); 61 } 62 63 /** 64 * Returns a {@link LoaderManager}. 65 * 66 * @deprecated Loaders are managed separately from FragmentController and this now throws an 67 * {@link UnsupportedOperationException}. Use {@link LoaderManager#getInstance} to obtain a 68 * LoaderManager. 69 * @see LoaderManager#getInstance 70 */ 71 @Deprecated 72 public LoaderManager getSupportLoaderManager() { 73 throw new UnsupportedOperationException("Loaders are managed separately from " 74 + "FragmentController, use LoaderManager.getInstance() to obtain a LoaderManager."); 75 } 76 77 /** 78 * Returns a fragment with the given identifier. 79 */ 80 @Nullable 81 public Fragment findFragmentByWho(String who) { 82 return mHost.mFragmentManager.findFragmentByWho(who); 83 } 84 85 /** 86 * Returns the number of active fragments. 87 */ 88 public int getActiveFragmentsCount() { 89 return mHost.mFragmentManager.getActiveFragmentCount(); 90 } 91 92 /** 93 * Returns the list of active fragments. 94 */ 95 public List<Fragment> getActiveFragments(List<Fragment> actives) { 96 return mHost.mFragmentManager.getActiveFragments(); 97 } 98 99 /** 100 * Attaches the host to the FragmentManager for this controller. The host must be 101 * attached before the FragmentManager can be used to manage Fragments. 102 */ 103 public void attachHost(Fragment parent) { 104 mHost.mFragmentManager.attachController( 105 mHost, mHost /*container*/, parent); 106 } 107 108 /** 109 * Instantiates a Fragment's view. 110 * 111 * @param parent The parent that the created view will be placed 112 * in; <em>note that this may be null</em>. 113 * @param name Tag name to be inflated. 114 * @param context The context the view is being created in. 115 * @param attrs Inflation attributes as specified in XML file. 116 * 117 * @return view the newly created view 118 */ 119 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { 120 return mHost.mFragmentManager.onCreateView(parent, name, context, attrs); 121 } 122 123 /** 124 * Marks the fragment state as unsaved. This allows for "state loss" detection. 125 */ 126 public void noteStateNotSaved() { 127 mHost.mFragmentManager.noteStateNotSaved(); 128 } 129 130 /** 131 * Saves the state for all Fragments. 132 */ 133 public Parcelable saveAllState() { 134 return mHost.mFragmentManager.saveAllState(); 135 } 136 137 /** 138 * Restores the saved state for all Fragments. The given Fragment list are Fragment 139 * instances retained across configuration changes. 140 * 141 * @see #retainNonConfig() 142 * 143 * @deprecated use {@link #restoreAllState(Parcelable, FragmentManagerNonConfig)} 144 */ 145 @Deprecated 146 public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) { 147 mHost.mFragmentManager.restoreAllState(state, 148 new FragmentManagerNonConfig(nonConfigList, null, null)); 149 } 150 151 /** 152 * Restores the saved state for all Fragments. The given FragmentManagerNonConfig are Fragment 153 * instances retained across configuration changes, including nested fragments 154 * 155 * @see #retainNestedNonConfig() 156 */ 157 public void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) { 158 mHost.mFragmentManager.restoreAllState(state, nonConfig); 159 } 160 161 /** 162 * Returns a list of Fragments that have opted to retain their instance across 163 * configuration changes. 164 * 165 * @deprecated use {@link #retainNestedNonConfig()} to also track retained 166 * nested child fragments 167 */ 168 @Deprecated 169 public List<Fragment> retainNonConfig() { 170 FragmentManagerNonConfig nonconf = mHost.mFragmentManager.retainNonConfig(); 171 return nonconf != null ? nonconf.getFragments() : null; 172 } 173 174 /** 175 * Returns a nested tree of Fragments that have opted to retain their instance across 176 * configuration changes. 177 */ 178 public FragmentManagerNonConfig retainNestedNonConfig() { 179 return mHost.mFragmentManager.retainNonConfig(); 180 } 181 182 /** 183 * Moves all Fragments managed by the controller's FragmentManager 184 * into the create state. 185 * <p>Call when Fragments should be created. 186 * 187 * @see Fragment#onCreate(Bundle) 188 */ 189 public void dispatchCreate() { 190 mHost.mFragmentManager.dispatchCreate(); 191 } 192 193 /** 194 * Moves all Fragments managed by the controller's FragmentManager 195 * into the activity created state. 196 * <p>Call when Fragments should be informed their host has been created. 197 * 198 * @see Fragment#onActivityCreated(Bundle) 199 */ 200 public void dispatchActivityCreated() { 201 mHost.mFragmentManager.dispatchActivityCreated(); 202 } 203 204 /** 205 * Moves all Fragments managed by the controller's FragmentManager 206 * into the start state. 207 * <p>Call when Fragments should be started. 208 * 209 * @see Fragment#onStart() 210 */ 211 public void dispatchStart() { 212 mHost.mFragmentManager.dispatchStart(); 213 } 214 215 /** 216 * Moves all Fragments managed by the controller's FragmentManager 217 * into the resume state. 218 * <p>Call when Fragments should be resumed. 219 * 220 * @see Fragment#onResume() 221 */ 222 public void dispatchResume() { 223 mHost.mFragmentManager.dispatchResume(); 224 } 225 226 /** 227 * Moves all Fragments managed by the controller's FragmentManager 228 * into the pause state. 229 * <p>Call when Fragments should be paused. 230 * 231 * @see Fragment#onPause() 232 */ 233 public void dispatchPause() { 234 mHost.mFragmentManager.dispatchPause(); 235 } 236 237 /** 238 * Moves all Fragments managed by the controller's FragmentManager 239 * into the stop state. 240 * <p>Call when Fragments should be stopped. 241 * 242 * @see Fragment#onStop() 243 */ 244 public void dispatchStop() { 245 mHost.mFragmentManager.dispatchStop(); 246 } 247 248 /** 249 * @deprecated This functionality has been rolled into {@link #dispatchStop()}. 250 */ 251 @Deprecated 252 public void dispatchReallyStop() { 253 } 254 255 /** 256 * Moves all Fragments managed by the controller's FragmentManager 257 * into the destroy view state. 258 * <p>Call when the Fragment's views should be destroyed. 259 * 260 * @see Fragment#onDestroyView() 261 */ 262 public void dispatchDestroyView() { 263 mHost.mFragmentManager.dispatchDestroyView(); 264 } 265 266 /** 267 * Moves all Fragments managed by the controller's FragmentManager 268 * into the destroy state. 269 * <p>Call when Fragments should be destroyed. 270 * 271 * @see Fragment#onDestroy() 272 */ 273 public void dispatchDestroy() { 274 mHost.mFragmentManager.dispatchDestroy(); 275 } 276 277 /** 278 * Lets all Fragments managed by the controller's FragmentManager know the multi-window mode of 279 * the activity changed. 280 * <p>Call when the multi-window mode of the activity changed. 281 * 282 * @see Fragment#onMultiWindowModeChanged 283 */ 284 public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) { 285 mHost.mFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode); 286 } 287 288 /** 289 * Lets all Fragments managed by the controller's FragmentManager know the picture-in-picture 290 * mode of the activity changed. 291 * <p>Call when the picture-in-picture mode of the activity changed. 292 * 293 * @see Fragment#onPictureInPictureModeChanged 294 */ 295 public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) { 296 mHost.mFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode); 297 } 298 299 /** 300 * Lets all Fragments managed by the controller's FragmentManager 301 * know a configuration change occurred. 302 * <p>Call when there is a configuration change. 303 * 304 * @see Fragment#onConfigurationChanged(Configuration) 305 */ 306 public void dispatchConfigurationChanged(Configuration newConfig) { 307 mHost.mFragmentManager.dispatchConfigurationChanged(newConfig); 308 } 309 310 /** 311 * Lets all Fragments managed by the controller's FragmentManager 312 * know the device is in a low memory condition. 313 * <p>Call when the device is low on memory and Fragment's should trim 314 * their memory usage. 315 * 316 * @see Fragment#onLowMemory() 317 */ 318 public void dispatchLowMemory() { 319 mHost.mFragmentManager.dispatchLowMemory(); 320 } 321 322 /** 323 * Lets all Fragments managed by the controller's FragmentManager 324 * know they should create an options menu. 325 * <p>Call when the Fragment should create an options menu. 326 * 327 * @return {@code true} if the options menu contains items to display 328 * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater) 329 */ 330 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { 331 return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater); 332 } 333 334 /** 335 * Lets all Fragments managed by the controller's FragmentManager 336 * know they should prepare their options menu for display. 337 * <p>Call immediately before displaying the Fragment's options menu. 338 * 339 * @return {@code true} if the options menu contains items to display 340 * @see Fragment#onPrepareOptionsMenu(Menu) 341 */ 342 public boolean dispatchPrepareOptionsMenu(Menu menu) { 343 return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu); 344 } 345 346 /** 347 * Sends an option item selection event to the Fragments managed by the 348 * controller's FragmentManager. Once the event has been consumed, 349 * no additional handling will be performed. 350 * <p>Call immediately after an options menu item has been selected 351 * 352 * @return {@code true} if the options menu selection event was consumed 353 * @see Fragment#onOptionsItemSelected(MenuItem) 354 */ 355 public boolean dispatchOptionsItemSelected(MenuItem item) { 356 return mHost.mFragmentManager.dispatchOptionsItemSelected(item); 357 } 358 359 /** 360 * Sends a context item selection event to the Fragments managed by the 361 * controller's FragmentManager. Once the event has been consumed, 362 * no additional handling will be performed. 363 * <p>Call immediately after an options menu item has been selected 364 * 365 * @return {@code true} if the context menu selection event was consumed 366 * @see Fragment#onContextItemSelected(MenuItem) 367 */ 368 public boolean dispatchContextItemSelected(MenuItem item) { 369 return mHost.mFragmentManager.dispatchContextItemSelected(item); 370 } 371 372 /** 373 * Lets all Fragments managed by the controller's FragmentManager 374 * know their options menu has closed. 375 * <p>Call immediately after closing the Fragment's options menu. 376 * 377 * @see Fragment#onOptionsMenuClosed(Menu) 378 */ 379 public void dispatchOptionsMenuClosed(Menu menu) { 380 mHost.mFragmentManager.dispatchOptionsMenuClosed(menu); 381 } 382 383 /** 384 * Execute any pending actions for the Fragments managed by the 385 * controller's FragmentManager. 386 * <p>Call when queued actions can be performed [eg when the 387 * Fragment moves into a start or resume state]. 388 * @return {@code true} if queued actions were performed 389 */ 390 public boolean execPendingActions() { 391 return mHost.mFragmentManager.execPendingActions(); 392 } 393 394 /** 395 * Starts the loaders. 396 * 397 * @deprecated Loaders are managed separately from FragmentController 398 */ 399 @Deprecated 400 public void doLoaderStart() { 401 } 402 403 /** 404 * Stops the loaders, optionally retaining their state. This is useful for keeping the 405 * loader state across configuration changes. 406 * 407 * @param retain When {@code true}, the loaders aren't stopped, but, their instances 408 * are retained in a started state 409 * 410 * @deprecated Loaders are managed separately from FragmentController 411 */ 412 @Deprecated 413 public void doLoaderStop(boolean retain) { 414 } 415 416 /** 417 * Retains the state of each of the loaders. 418 * 419 * @deprecated Loaders are managed separately from FragmentController 420 */ 421 @Deprecated 422 public void doLoaderRetain() { 423 } 424 425 /** 426 * Destroys the loaders and, if their state is not being retained, removes them. 427 * 428 * @deprecated Loaders are managed separately from FragmentController 429 */ 430 @Deprecated 431 public void doLoaderDestroy() { 432 } 433 434 /** 435 * Lets the loaders know the host is ready to receive notifications. 436 * 437 * @deprecated Loaders are managed separately from FragmentController 438 */ 439 @Deprecated 440 public void reportLoaderStart() { 441 } 442 443 /** 444 * Returns a list of LoaderManagers that have opted to retain their instance across 445 * configuration changes. 446 * 447 * @deprecated Loaders are managed separately from FragmentController 448 */ 449 @Deprecated 450 public SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() { 451 return null; 452 } 453 454 /** 455 * Restores the saved state for all LoaderManagers. The given LoaderManager list are 456 * LoaderManager instances retained across configuration changes. 457 * 458 * @see #retainLoaderNonConfig() 459 * 460 * @deprecated Loaders are managed separately from FragmentController 461 */ 462 @Deprecated 463 public void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) { 464 } 465 466 /** 467 * Dumps the current state of the loaders. 468 * 469 * @deprecated Loaders are managed separately from FragmentController 470 */ 471 @Deprecated 472 public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 473 } 474} 475