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 */ restoreAllState(Parcelable state, List<Fragment> nonConfigList)123 public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) { 124 mHost.mFragmentManager.restoreAllState(state, 125 new FragmentManagerNonConfig(nonConfigList, null)); 126 } 127 128 /** 129 * Restores the saved state for all Fragments. The given FragmentManagerNonConfig are Fragment 130 * instances retained across configuration changes, including nested fragments 131 * 132 * @see #retainNestedNonConfig() 133 */ restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig)134 public void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) { 135 mHost.mFragmentManager.restoreAllState(state, nonConfig); 136 } 137 138 /** 139 * Returns a list of Fragments that have opted to retain their instance across 140 * configuration changes. 141 * 142 * @deprecated use {@link #retainNestedNonConfig()} to also track retained 143 * nested child fragments 144 */ retainNonConfig()145 public List<Fragment> retainNonConfig() { 146 return mHost.mFragmentManager.retainNonConfig().getFragments(); 147 } 148 149 /** 150 * Returns a nested tree of Fragments that have opted to retain their instance across 151 * configuration changes. 152 */ retainNestedNonConfig()153 public FragmentManagerNonConfig retainNestedNonConfig() { 154 return mHost.mFragmentManager.retainNonConfig(); 155 } 156 157 /** 158 * Moves all Fragments managed by the controller's FragmentManager 159 * into the create state. 160 * <p>Call when Fragments should be created. 161 * 162 * @see Fragment#onCreate(Bundle) 163 */ dispatchCreate()164 public void dispatchCreate() { 165 mHost.mFragmentManager.dispatchCreate(); 166 } 167 168 /** 169 * Moves all Fragments managed by the controller's FragmentManager 170 * into the activity created state. 171 * <p>Call when Fragments should be informed their host has been created. 172 * 173 * @see Fragment#onActivityCreated(Bundle) 174 */ dispatchActivityCreated()175 public void dispatchActivityCreated() { 176 mHost.mFragmentManager.dispatchActivityCreated(); 177 } 178 179 /** 180 * Moves all Fragments managed by the controller's FragmentManager 181 * into the start state. 182 * <p>Call when Fragments should be started. 183 * 184 * @see Fragment#onStart() 185 */ dispatchStart()186 public void dispatchStart() { 187 mHost.mFragmentManager.dispatchStart(); 188 } 189 190 /** 191 * Moves all Fragments managed by the controller's FragmentManager 192 * into the resume state. 193 * <p>Call when Fragments should be resumed. 194 * 195 * @see Fragment#onResume() 196 */ dispatchResume()197 public void dispatchResume() { 198 mHost.mFragmentManager.dispatchResume(); 199 } 200 201 /** 202 * Moves all Fragments managed by the controller's FragmentManager 203 * into the pause state. 204 * <p>Call when Fragments should be paused. 205 * 206 * @see Fragment#onPause() 207 */ dispatchPause()208 public void dispatchPause() { 209 mHost.mFragmentManager.dispatchPause(); 210 } 211 212 /** 213 * Moves all Fragments managed by the controller's FragmentManager 214 * into the stop state. 215 * <p>Call when Fragments should be stopped. 216 * 217 * @see Fragment#onStop() 218 */ dispatchStop()219 public void dispatchStop() { 220 mHost.mFragmentManager.dispatchStop(); 221 } 222 223 /** 224 * Moves all Fragments managed by the controller's FragmentManager 225 * into the destroy view state. 226 * <p>Call when the Fragment's views should be destroyed. 227 * 228 * @see Fragment#onDestroyView() 229 */ dispatchDestroyView()230 public void dispatchDestroyView() { 231 mHost.mFragmentManager.dispatchDestroyView(); 232 } 233 234 /** 235 * Moves all Fragments managed by the controller's FragmentManager 236 * into the destroy state. 237 * <p>Call when Fragments should be destroyed. 238 * 239 * @see Fragment#onDestroy() 240 */ dispatchDestroy()241 public void dispatchDestroy() { 242 mHost.mFragmentManager.dispatchDestroy(); 243 } 244 245 /** 246 * Lets all Fragments managed by the controller's FragmentManager know the multi-window mode of 247 * the activity changed. 248 * <p>Call when the multi-window mode of the activity changed. 249 * 250 * @see Fragment#onMultiWindowModeChanged 251 */ dispatchMultiWindowModeChanged(boolean isInMultiWindowMode)252 public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) { 253 mHost.mFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode); 254 } 255 256 /** 257 * Lets all Fragments managed by the controller's FragmentManager know the picture-in-picture 258 * mode of the activity changed. 259 * <p>Call when the picture-in-picture mode of the activity changed. 260 * 261 * @see Fragment#onPictureInPictureModeChanged 262 */ dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode)263 public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) { 264 mHost.mFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode); 265 } 266 267 /** 268 * Lets all Fragments managed by the controller's FragmentManager 269 * know a configuration change occurred. 270 * <p>Call when there is a configuration change. 271 * 272 * @see Fragment#onConfigurationChanged(Configuration) 273 */ dispatchConfigurationChanged(Configuration newConfig)274 public void dispatchConfigurationChanged(Configuration newConfig) { 275 mHost.mFragmentManager.dispatchConfigurationChanged(newConfig); 276 } 277 278 /** 279 * Lets all Fragments managed by the controller's FragmentManager 280 * know the device is in a low memory condition. 281 * <p>Call when the device is low on memory and Fragment's should trim 282 * their memory usage. 283 * 284 * @see Fragment#onLowMemory() 285 */ dispatchLowMemory()286 public void dispatchLowMemory() { 287 mHost.mFragmentManager.dispatchLowMemory(); 288 } 289 290 /** 291 * Lets all Fragments managed by the controller's FragmentManager 292 * know they should trim their memory usage. 293 * <p>Call when the Fragment can release allocated memory [such as if 294 * the Fragment is in the background]. 295 * 296 * @see Fragment#onTrimMemory(int) 297 */ dispatchTrimMemory(int level)298 public void dispatchTrimMemory(int level) { 299 mHost.mFragmentManager.dispatchTrimMemory(level); 300 } 301 302 /** 303 * Lets all Fragments managed by the controller's FragmentManager 304 * know they should create an options menu. 305 * <p>Call when the Fragment should create an options menu. 306 * 307 * @return {@code true} if the options menu contains items to display 308 * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater) 309 */ dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater)310 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { 311 return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater); 312 } 313 314 /** 315 * Lets all Fragments managed by the controller's FragmentManager 316 * know they should prepare their options menu for display. 317 * <p>Call immediately before displaying the Fragment's options menu. 318 * 319 * @return {@code true} if the options menu contains items to display 320 * @see Fragment#onPrepareOptionsMenu(Menu) 321 */ dispatchPrepareOptionsMenu(Menu menu)322 public boolean dispatchPrepareOptionsMenu(Menu menu) { 323 return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu); 324 } 325 326 /** 327 * Sends an option item selection event to the Fragments managed by the 328 * controller's FragmentManager. Once the event has been consumed, 329 * no additional handling will be performed. 330 * <p>Call immediately after an options menu item has been selected 331 * 332 * @return {@code true} if the options menu selection event was consumed 333 * @see Fragment#onOptionsItemSelected(MenuItem) 334 */ dispatchOptionsItemSelected(MenuItem item)335 public boolean dispatchOptionsItemSelected(MenuItem item) { 336 return mHost.mFragmentManager.dispatchOptionsItemSelected(item); 337 } 338 339 /** 340 * Sends a context item selection event to the Fragments managed by the 341 * controller's FragmentManager. Once the event has been consumed, 342 * no additional handling will be performed. 343 * <p>Call immediately after an options menu item has been selected 344 * 345 * @return {@code true} if the context menu selection event was consumed 346 * @see Fragment#onContextItemSelected(MenuItem) 347 */ dispatchContextItemSelected(MenuItem item)348 public boolean dispatchContextItemSelected(MenuItem item) { 349 return mHost.mFragmentManager.dispatchContextItemSelected(item); 350 } 351 352 /** 353 * Lets all Fragments managed by the controller's FragmentManager 354 * know their options menu has closed. 355 * <p>Call immediately after closing the Fragment's options menu. 356 * 357 * @see Fragment#onOptionsMenuClosed(Menu) 358 */ dispatchOptionsMenuClosed(Menu menu)359 public void dispatchOptionsMenuClosed(Menu menu) { 360 mHost.mFragmentManager.dispatchOptionsMenuClosed(menu); 361 } 362 363 /** 364 * Execute any pending actions for the Fragments managed by the 365 * controller's FragmentManager. 366 * <p>Call when queued actions can be performed [eg when the 367 * Fragment moves into a start or resume state]. 368 * @return {@code true} if queued actions were performed 369 */ execPendingActions()370 public boolean execPendingActions() { 371 return mHost.mFragmentManager.execPendingActions(); 372 } 373 374 /** 375 * Starts the loaders. 376 */ doLoaderStart()377 public void doLoaderStart() { 378 mHost.doLoaderStart(); 379 } 380 381 /** 382 * Stops the loaders, optionally retaining their state. This is useful for keeping the 383 * loader state across configuration changes. 384 * 385 * @param retain When {@code true}, the loaders aren't stopped, but, their instances 386 * are retained in a started state 387 */ doLoaderStop(boolean retain)388 public void doLoaderStop(boolean retain) { 389 mHost.doLoaderStop(retain); 390 } 391 392 /** 393 * Destroys the loaders and, if their state is not being retained, removes them. 394 */ doLoaderDestroy()395 public void doLoaderDestroy() { 396 mHost.doLoaderDestroy(); 397 } 398 399 /** 400 * Lets the loaders know the host is ready to receive notifications. 401 */ reportLoaderStart()402 public void reportLoaderStart() { 403 mHost.reportLoaderStart(); 404 } 405 406 /** 407 * Returns a list of LoaderManagers that have opted to retain their instance across 408 * configuration changes. 409 */ retainLoaderNonConfig()410 public ArrayMap<String, LoaderManager> retainLoaderNonConfig() { 411 return mHost.retainLoaderNonConfig(); 412 } 413 414 /** 415 * Restores the saved state for all LoaderManagers. The given LoaderManager list are 416 * LoaderManager instances retained across configuration changes. 417 * 418 * @see #retainLoaderNonConfig() 419 */ restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers)420 public void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) { 421 mHost.restoreLoaderNonConfig(loaderManagers); 422 } 423 424 /** 425 * Dumps the current state of the loaders. 426 */ dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)427 public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 428 mHost.dumpLoaders(prefix, fd, writer, args); 429 } 430 } 431