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.ArrayList; 33import 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 */ 41public class FragmentController { 42 private final FragmentHostCallback<?> mHost; 43 44 /** 45 * Returns a {@link FragmentController}. 46 */ 47 public static final FragmentController createController(FragmentHostCallback<?> callbacks) { 48 return new FragmentController(callbacks); 49 } 50 51 private FragmentController(FragmentHostCallback<?> callbacks) { 52 mHost = callbacks; 53 } 54 55 /** 56 * Returns a {@link FragmentManager} for this controller. 57 */ 58 public FragmentManager getSupportFragmentManager() { 59 return mHost.getFragmentManagerImpl(); 60 } 61 62 /** 63 * Returns a {@link LoaderManager}. 64 */ 65 public LoaderManager getSupportLoaderManager() { 66 return mHost.getLoaderManagerImpl(); 67 } 68 69 /** 70 * Returns a fragment with the given identifier. 71 */ 72 @Nullable 73 public Fragment findFragmentByWho(String who) { 74 return mHost.mFragmentManager.findFragmentByWho(who); 75 } 76 77 /** 78 * Returns the number of active fragments. 79 */ 80 public int getActiveFragmentsCount() { 81 final List<Fragment> actives = mHost.mFragmentManager.mActive; 82 return actives == null ? 0 : actives.size(); 83 } 84 85 /** 86 * Returns the list of active fragments. 87 */ 88 public List<Fragment> getActiveFragments(List<Fragment> actives) { 89 if (mHost.mFragmentManager.mActive == null) { 90 return null; 91 } 92 if (actives == null) { 93 actives = new ArrayList<Fragment>(getActiveFragmentsCount()); 94 } 95 actives.addAll(mHost.mFragmentManager.mActive); 96 return actives; 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)); 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 public void dispatchReallyStop() { 249 mHost.mFragmentManager.dispatchReallyStop(); 250 } 251 252 /** 253 * Moves all Fragments managed by the controller's FragmentManager 254 * into the destroy view state. 255 * <p>Call when the Fragment's views should be destroyed. 256 * 257 * @see Fragment#onDestroyView() 258 */ 259 public void dispatchDestroyView() { 260 mHost.mFragmentManager.dispatchDestroyView(); 261 } 262 263 /** 264 * Moves all Fragments managed by the controller's FragmentManager 265 * into the destroy state. 266 * <p>Call when Fragments should be destroyed. 267 * 268 * @see Fragment#onDestroy() 269 */ 270 public void dispatchDestroy() { 271 mHost.mFragmentManager.dispatchDestroy(); 272 } 273 274 /** 275 * Lets all Fragments managed by the controller's FragmentManager know the multi-window mode of 276 * the activity changed. 277 * <p>Call when the multi-window mode of the activity changed. 278 * 279 * @see Fragment#onMultiWindowModeChanged 280 */ 281 public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) { 282 mHost.mFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode); 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 */ 292 public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) { 293 mHost.mFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode); 294 } 295 296 /** 297 * Lets all Fragments managed by the controller's FragmentManager 298 * know a configuration change occurred. 299 * <p>Call when there is a configuration change. 300 * 301 * @see Fragment#onConfigurationChanged(Configuration) 302 */ 303 public void dispatchConfigurationChanged(Configuration newConfig) { 304 mHost.mFragmentManager.dispatchConfigurationChanged(newConfig); 305 } 306 307 /** 308 * Lets all Fragments managed by the controller's FragmentManager 309 * know the device is in a low memory condition. 310 * <p>Call when the device is low on memory and Fragment's should trim 311 * their memory usage. 312 * 313 * @see Fragment#onLowMemory() 314 */ 315 public void dispatchLowMemory() { 316 mHost.mFragmentManager.dispatchLowMemory(); 317 } 318 319 /** 320 * Lets all Fragments managed by the controller's FragmentManager 321 * know they should create an options menu. 322 * <p>Call when the Fragment should create an options menu. 323 * 324 * @return {@code true} if the options menu contains items to display 325 * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater) 326 */ 327 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { 328 return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater); 329 } 330 331 /** 332 * Lets all Fragments managed by the controller's FragmentManager 333 * know they should prepare their options menu for display. 334 * <p>Call immediately before displaying the Fragment's options menu. 335 * 336 * @return {@code true} if the options menu contains items to display 337 * @see Fragment#onPrepareOptionsMenu(Menu) 338 */ 339 public boolean dispatchPrepareOptionsMenu(Menu menu) { 340 return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu); 341 } 342 343 /** 344 * Sends an option item selection event to the Fragments managed by the 345 * controller's FragmentManager. Once the event has been consumed, 346 * no additional handling will be performed. 347 * <p>Call immediately after an options menu item has been selected 348 * 349 * @return {@code true} if the options menu selection event was consumed 350 * @see Fragment#onOptionsItemSelected(MenuItem) 351 */ 352 public boolean dispatchOptionsItemSelected(MenuItem item) { 353 return mHost.mFragmentManager.dispatchOptionsItemSelected(item); 354 } 355 356 /** 357 * Sends a context item selection event to the Fragments managed by the 358 * controller's FragmentManager. Once the event has been consumed, 359 * no additional handling will be performed. 360 * <p>Call immediately after an options menu item has been selected 361 * 362 * @return {@code true} if the context menu selection event was consumed 363 * @see Fragment#onContextItemSelected(MenuItem) 364 */ 365 public boolean dispatchContextItemSelected(MenuItem item) { 366 return mHost.mFragmentManager.dispatchContextItemSelected(item); 367 } 368 369 /** 370 * Lets all Fragments managed by the controller's FragmentManager 371 * know their options menu has closed. 372 * <p>Call immediately after closing the Fragment's options menu. 373 * 374 * @see Fragment#onOptionsMenuClosed(Menu) 375 */ 376 public void dispatchOptionsMenuClosed(Menu menu) { 377 mHost.mFragmentManager.dispatchOptionsMenuClosed(menu); 378 } 379 380 /** 381 * Execute any pending actions for the Fragments managed by the 382 * controller's FragmentManager. 383 * <p>Call when queued actions can be performed [eg when the 384 * Fragment moves into a start or resume state]. 385 * @return {@code true} if queued actions were performed 386 */ 387 public boolean execPendingActions() { 388 return mHost.mFragmentManager.execPendingActions(); 389 } 390 391 /** 392 * Starts the loaders. 393 */ 394 public void doLoaderStart() { 395 mHost.doLoaderStart(); 396 } 397 398 /** 399 * Stops the loaders, optionally retaining their state. This is useful for keeping the 400 * loader state across configuration changes. 401 * 402 * @param retain When {@code true}, the loaders aren't stopped, but, their instances 403 * are retained in a started state 404 */ 405 public void doLoaderStop(boolean retain) { 406 mHost.doLoaderStop(retain); 407 } 408 409 /** 410 * Retains the state of each of the loaders. 411 */ 412 public void doLoaderRetain() { 413 mHost.doLoaderRetain(); 414 } 415 416 /** 417 * Destroys the loaders and, if their state is not being retained, removes them. 418 */ 419 public void doLoaderDestroy() { 420 mHost.doLoaderDestroy(); 421 } 422 423 /** 424 * Lets the loaders know the host is ready to receive notifications. 425 */ 426 public void reportLoaderStart() { 427 mHost.reportLoaderStart(); 428 } 429 430 /** 431 * Returns a list of LoaderManagers that have opted to retain their instance across 432 * configuration changes. 433 */ 434 public SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() { 435 return mHost.retainLoaderNonConfig(); 436 } 437 438 /** 439 * Restores the saved state for all LoaderManagers. The given LoaderManager list are 440 * LoaderManager instances retained across configuration changes. 441 * 442 * @see #retainLoaderNonConfig() 443 */ 444 public void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) { 445 mHost.restoreLoaderNonConfig(loaderManagers); 446 } 447 448 /** 449 * Dumps the current state of the loaders. 450 */ 451 public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 452 mHost.dumpLoaders(prefix, fd, writer, args); 453 } 454} 455