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