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.support.v4.app; 18 19 import android.content.Context; 20 import android.content.res.Configuration; 21 import android.os.Parcelable; 22 import android.support.v4.util.SimpleArrayMap; 23 import android.util.AttributeSet; 24 import android.view.Menu; 25 import android.view.MenuInflater; 26 import android.view.MenuItem; 27 import android.view.View; 28 29 import java.io.FileDescriptor; 30 import java.io.PrintWriter; 31 import java.util.ArrayList; 32 import 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 */ 40 public class FragmentController { 41 private final FragmentHostCallback<?> mHost; 42 43 /** 44 * Returns a {@link FragmentController}. 45 */ createController(FragmentHostCallback<?> callbacks)46 public static final FragmentController createController(FragmentHostCallback<?> callbacks) { 47 return new FragmentController(callbacks); 48 } 49 FragmentController(FragmentHostCallback<?> callbacks)50 private FragmentController(FragmentHostCallback<?> callbacks) { 51 mHost = callbacks; 52 } 53 54 /** 55 * Returns a {@link FragmentManager} for this controller. 56 */ getSupportFragmentManager()57 public FragmentManager getSupportFragmentManager() { 58 return mHost.getFragmentManagerImpl(); 59 } 60 61 /** 62 * Returns a {@link LoaderManager}. 63 */ getSupportLoaderManager()64 public LoaderManager getSupportLoaderManager() { 65 return mHost.getLoaderManagerImpl(); 66 } 67 68 /** 69 * Returns the number of active fragments. 70 */ getActiveFragmentsCount()71 public int getActiveFragmentsCount() { 72 final List<Fragment> actives = mHost.mFragmentManager.mActive; 73 return actives == null ? 0 : actives.size(); 74 } 75 76 /** 77 * Returns the list of active fragments. 78 */ getActiveFragments(List<Fragment> actives)79 public List<Fragment> getActiveFragments(List<Fragment> actives) { 80 if (mHost.mFragmentManager.mActive == null) { 81 return null; 82 } 83 if (actives == null) { 84 actives = new ArrayList<Fragment>(getActiveFragmentsCount()); 85 } 86 actives.addAll(mHost.mFragmentManager.mActive); 87 return actives; 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 */ attachHost(Fragment parent)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 */ onCreateView(View parent, String name, Context context, AttributeSet attrs)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 */ noteStateNotSaved()117 public void noteStateNotSaved() { 118 mHost.mFragmentManager.noteStateNotSaved(); 119 } 120 121 /** 122 * Saves the state for all Fragments. 123 */ saveAllState()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 */ restoreAllState(Parcelable state, List<Fragment> nonConfigList)134 public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) { 135 mHost.mFragmentManager.restoreAllState(state, nonConfigList); 136 } 137 138 /** 139 * Returns a list of Fragments that have opted to retain their instance across 140 * configuration changes. 141 */ retainNonConfig()142 public List<Fragment> retainNonConfig() { 143 return mHost.mFragmentManager.retainNonConfig(); 144 } 145 146 /** 147 * Moves all Fragments managed by the controller's FragmentManager 148 * into the create state. 149 * <p>Call when Fragments should be created. 150 * 151 * @see Fragment#onCreate(Bundle) 152 */ dispatchCreate()153 public void dispatchCreate() { 154 mHost.mFragmentManager.dispatchCreate(); 155 } 156 157 /** 158 * Moves all Fragments managed by the controller's FragmentManager 159 * into the activity created state. 160 * <p>Call when Fragments should be informed their host has been created. 161 * 162 * @see Fragment#onActivityCreated(Bundle) 163 */ dispatchActivityCreated()164 public void dispatchActivityCreated() { 165 mHost.mFragmentManager.dispatchActivityCreated(); 166 } 167 168 /** 169 * Moves all Fragments managed by the controller's FragmentManager 170 * into the start state. 171 * <p>Call when Fragments should be started. 172 * 173 * @see Fragment#onStart() 174 */ dispatchStart()175 public void dispatchStart() { 176 mHost.mFragmentManager.dispatchStart(); 177 } 178 179 /** 180 * Moves all Fragments managed by the controller's FragmentManager 181 * into the resume state. 182 * <p>Call when Fragments should be resumed. 183 * 184 * @see Fragment#onResume() 185 */ dispatchResume()186 public void dispatchResume() { 187 mHost.mFragmentManager.dispatchResume(); 188 } 189 190 /** 191 * Moves all Fragments managed by the controller's FragmentManager 192 * into the pause state. 193 * <p>Call when Fragments should be paused. 194 * 195 * @see Fragment#onPause() 196 */ dispatchPause()197 public void dispatchPause() { 198 mHost.mFragmentManager.dispatchPause(); 199 } 200 201 /** 202 * Moves all Fragments managed by the controller's FragmentManager 203 * into the stop state. 204 * <p>Call when Fragments should be stopped. 205 * 206 * @see Fragment#onStop() 207 */ dispatchStop()208 public void dispatchStop() { 209 mHost.mFragmentManager.dispatchStop(); 210 } 211 dispatchReallyStop()212 public void dispatchReallyStop() { 213 mHost.mFragmentManager.dispatchReallyStop(); 214 } 215 216 /** 217 * Moves all Fragments managed by the controller's FragmentManager 218 * into the destroy view state. 219 * <p>Call when the Fragment's views should be destroyed. 220 * 221 * @see Fragment#onDestroyView() 222 */ dispatchDestroyView()223 public void dispatchDestroyView() { 224 mHost.mFragmentManager.dispatchDestroyView(); 225 } 226 227 /** 228 * Moves all Fragments managed by the controller's FragmentManager 229 * into the destroy state. 230 * <p>Call when Fragments should be destroyed. 231 * 232 * @see Fragment#onDestroy() 233 */ dispatchDestroy()234 public void dispatchDestroy() { 235 mHost.mFragmentManager.dispatchDestroy(); 236 } 237 238 /** 239 * Lets all Fragments managed by the controller's FragmentManager 240 * know a configuration change occurred. 241 * <p>Call when there is a configuration change. 242 * 243 * @see Fragment#onConfigurationChanged(Configuration) 244 */ dispatchConfigurationChanged(Configuration newConfig)245 public void dispatchConfigurationChanged(Configuration newConfig) { 246 mHost.mFragmentManager.dispatchConfigurationChanged(newConfig); 247 } 248 249 /** 250 * Lets all Fragments managed by the controller's FragmentManager 251 * know the device is in a low memory condition. 252 * <p>Call when the device is low on memory and Fragment's should trim 253 * their memory usage. 254 * 255 * @see Fragment#onLowMemory() 256 */ dispatchLowMemory()257 public void dispatchLowMemory() { 258 mHost.mFragmentManager.dispatchLowMemory(); 259 } 260 261 /** 262 * Lets all Fragments managed by the controller's FragmentManager 263 * know they should create an options menu. 264 * <p>Call when the Fragment should create an options menu. 265 * 266 * @return {@code true} if the options menu contains items to display 267 * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater) 268 */ dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater)269 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { 270 return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater); 271 } 272 273 /** 274 * Lets all Fragments managed by the controller's FragmentManager 275 * know they should prepare their options menu for display. 276 * <p>Call immediately before displaying the Fragment's options menu. 277 * 278 * @return {@code true} if the options menu contains items to display 279 * @see Fragment#onPrepareOptionsMenu(Menu) 280 */ dispatchPrepareOptionsMenu(Menu menu)281 public boolean dispatchPrepareOptionsMenu(Menu menu) { 282 return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu); 283 } 284 285 /** 286 * Sends an option item selection event to the Fragments managed by the 287 * controller's FragmentManager. Once the event has been consumed, 288 * no additional handling will be performed. 289 * <p>Call immediately after an options menu item has been selected 290 * 291 * @return {@code true} if the options menu selection event was consumed 292 * @see Fragment#onOptionsItemSelected(MenuItem) 293 */ dispatchOptionsItemSelected(MenuItem item)294 public boolean dispatchOptionsItemSelected(MenuItem item) { 295 return mHost.mFragmentManager.dispatchOptionsItemSelected(item); 296 } 297 298 /** 299 * Sends a context item selection event to the Fragments managed by the 300 * controller's FragmentManager. Once the event has been consumed, 301 * no additional handling will be performed. 302 * <p>Call immediately after an options menu item has been selected 303 * 304 * @return {@code true} if the context menu selection event was consumed 305 * @see Fragment#onContextItemSelected(MenuItem) 306 */ dispatchContextItemSelected(MenuItem item)307 public boolean dispatchContextItemSelected(MenuItem item) { 308 return mHost.mFragmentManager.dispatchContextItemSelected(item); 309 } 310 311 /** 312 * Lets all Fragments managed by the controller's FragmentManager 313 * know their options menu has closed. 314 * <p>Call immediately after closing the Fragment's options menu. 315 * 316 * @see Fragment#onOptionsMenuClosed(Menu) 317 */ dispatchOptionsMenuClosed(Menu menu)318 public void dispatchOptionsMenuClosed(Menu menu) { 319 mHost.mFragmentManager.dispatchOptionsMenuClosed(menu); 320 } 321 322 /** 323 * Execute any pending actions for the Fragments managed by the 324 * controller's FragmentManager. 325 * <p>Call when queued actions can be performed [eg when the 326 * Fragment moves into a start or resume state]. 327 * @return {@code true} if queued actions were performed 328 */ execPendingActions()329 public boolean execPendingActions() { 330 return mHost.mFragmentManager.execPendingActions(); 331 } 332 333 /** 334 * Starts the loaders. 335 */ doLoaderStart()336 public void doLoaderStart() { 337 mHost.doLoaderStart(); 338 } 339 340 /** 341 * Stops the loaders, optionally retaining their state. This is useful for keeping the 342 * loader state across configuration changes. 343 * 344 * @param retain When {@code true}, the loaders aren't stopped, but, their instances 345 * are retained in a started state 346 */ doLoaderStop(boolean retain)347 public void doLoaderStop(boolean retain) { 348 mHost.doLoaderStop(retain); 349 } 350 351 /** 352 * Retains the state of each of the loaders. 353 */ doLoaderRetain()354 public void doLoaderRetain() { 355 mHost.doLoaderRetain(); 356 } 357 358 /** 359 * Destroys the loaders and, if their state is not being retained, removes them. 360 */ doLoaderDestroy()361 public void doLoaderDestroy() { 362 mHost.doLoaderDestroy(); 363 } 364 365 /** 366 * Lets the loaders know the host is ready to receive notifications. 367 */ reportLoaderStart()368 public void reportLoaderStart() { 369 mHost.reportLoaderStart(); 370 } 371 372 /** 373 * Returns a list of LoaderManagers that have opted to retain their instance across 374 * configuration changes. 375 */ retainLoaderNonConfig()376 public SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() { 377 return mHost.retainLoaderNonConfig(); 378 } 379 380 /** 381 * Restores the saved state for all LoaderManagers. The given LoaderManager list are 382 * LoaderManager instances retained across configuration changes. 383 * 384 * @see #retainLoaderNonConfig() 385 */ restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers)386 public void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) { 387 mHost.restoreLoaderNonConfig(loaderManagers); 388 } 389 390 /** 391 * Dumps the current state of the loaders. 392 */ dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)393 public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 394 mHost.dumpLoaders(prefix, fd, writer, args); 395 } 396 } 397