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