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.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentSender; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.os.UserHandle; 27 import android.util.ArrayMap; 28 import android.view.LayoutInflater; 29 import android.view.View; 30 31 import java.io.FileDescriptor; 32 import java.io.PrintWriter; 33 34 /** 35 * Integration points with the Fragment host. 36 * <p> 37 * Fragments may be hosted by any object; such as an {@link Activity}. In order to 38 * host fragments, implement {@link FragmentHostCallback}, overriding the methods 39 * applicable to the host. 40 * 41 * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> 42 * {@link android.support.v4.app.FragmentHostCallback} 43 */ 44 @Deprecated 45 public abstract class FragmentHostCallback<E> extends FragmentContainer { 46 private final Activity mActivity; 47 final Context mContext; 48 private final Handler mHandler; 49 final int mWindowAnimations; 50 final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl(); 51 /** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */ 52 private ArrayMap<String, LoaderManager> mAllLoaderManagers; 53 /** Whether or not fragment loaders should retain their state */ 54 private boolean mRetainLoaders; 55 /** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */ 56 private LoaderManagerImpl mLoaderManager; 57 private boolean mCheckedForLoaderManager; 58 /** Whether or not the fragment host loader manager was started */ 59 private boolean mLoadersStarted; 60 FragmentHostCallback(Context context, Handler handler, int windowAnimations)61 public FragmentHostCallback(Context context, Handler handler, int windowAnimations) { 62 this((context instanceof Activity) ? (Activity)context : null, context, 63 chooseHandler(context, handler), windowAnimations); 64 } 65 FragmentHostCallback(Activity activity)66 FragmentHostCallback(Activity activity) { 67 this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/); 68 } 69 FragmentHostCallback(Activity activity, Context context, Handler handler, int windowAnimations)70 FragmentHostCallback(Activity activity, Context context, Handler handler, 71 int windowAnimations) { 72 mActivity = activity; 73 mContext = context; 74 mHandler = handler; 75 mWindowAnimations = windowAnimations; 76 } 77 78 /** 79 * Used internally in {@link #FragmentHostCallback(Context, Handler, int)} to choose 80 * the Activity's handler or the provided handler. 81 */ chooseHandler(Context context, Handler handler)82 private static Handler chooseHandler(Context context, Handler handler) { 83 if (handler == null && context instanceof Activity) { 84 Activity activity = (Activity) context; 85 return activity.mHandler; 86 } else { 87 return handler; 88 } 89 } 90 91 /** 92 * Print internal state into the given stream. 93 * 94 * @param prefix Desired prefix to prepend at each line of output. 95 * @param fd The raw file descriptor that the dump is being sent to. 96 * @param writer The PrintWriter to which you should dump your state. This will be closed 97 * for you after you return. 98 * @param args additional arguments to the dump request. 99 */ onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)100 public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 101 } 102 103 /** 104 * Return {@code true} if the fragment's state needs to be saved. 105 */ onShouldSaveFragmentState(Fragment fragment)106 public boolean onShouldSaveFragmentState(Fragment fragment) { 107 return true; 108 } 109 110 /** 111 * Return a {@link LayoutInflater}. 112 * See {@link Activity#getLayoutInflater()}. 113 */ onGetLayoutInflater()114 public LayoutInflater onGetLayoutInflater() { 115 return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 116 } 117 118 /** 119 * Return {@code true} if the FragmentManager's LayoutInflaterFactory should be used. 120 */ onUseFragmentManagerInflaterFactory()121 public boolean onUseFragmentManagerInflaterFactory() { 122 return false; 123 } 124 125 /** 126 * Return the object that's currently hosting the fragment. If a {@link Fragment} 127 * is hosted by a {@link Activity}, the object returned here should be the same 128 * object returned from {@link Fragment#getActivity()}. 129 */ 130 @Nullable onGetHost()131 public abstract E onGetHost(); 132 133 /** 134 * Invalidates the activity's options menu. 135 * See {@link Activity#invalidateOptionsMenu()} 136 */ onInvalidateOptionsMenu()137 public void onInvalidateOptionsMenu() { 138 } 139 140 /** 141 * Starts a new {@link Activity} from the given fragment. 142 * See {@link Activity#startActivityForResult(Intent, int)}. 143 */ onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)144 public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, 145 Bundle options) { 146 if (requestCode != -1) { 147 throw new IllegalStateException( 148 "Starting activity with a requestCode requires a FragmentActivity host"); 149 } 150 mContext.startActivity(intent); 151 } 152 153 /** 154 * @hide 155 * Starts a new {@link Activity} from the given fragment. 156 * See {@link Activity#startActivityForResult(Intent, int)}. 157 */ onStartActivityAsUserFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options, UserHandle userHandle)158 public void onStartActivityAsUserFromFragment(Fragment fragment, Intent intent, int requestCode, 159 Bundle options, UserHandle userHandle) { 160 if (requestCode != -1) { 161 throw new IllegalStateException( 162 "Starting activity with a requestCode requires a FragmentActivity host"); 163 } 164 mContext.startActivityAsUser(intent, userHandle); 165 } 166 167 /** 168 * Starts a new {@link IntentSender} from the given fragment. 169 * See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}. 170 */ onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)171 public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent, 172 int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, 173 int extraFlags, Bundle options) throws IntentSender.SendIntentException { 174 if (requestCode != -1) { 175 throw new IllegalStateException( 176 "Starting intent sender with a requestCode requires a FragmentActivity host"); 177 } 178 mContext.startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags, 179 options); 180 } 181 182 /** 183 * Requests permissions from the given fragment. 184 * See {@link Activity#requestPermissions(String[], int)} 185 */ onRequestPermissionsFromFragment(@onNull Fragment fragment, @NonNull String[] permissions, int requestCode)186 public void onRequestPermissionsFromFragment(@NonNull Fragment fragment, 187 @NonNull String[] permissions, int requestCode) { 188 } 189 190 /** 191 * Return {@code true} if there are window animations. 192 */ onHasWindowAnimations()193 public boolean onHasWindowAnimations() { 194 return true; 195 } 196 197 /** 198 * Return the window animations. 199 */ onGetWindowAnimations()200 public int onGetWindowAnimations() { 201 return mWindowAnimations; 202 } 203 204 /** 205 * Called when a {@link Fragment} is being attached to this host, immediately 206 * after the call to its {@link Fragment#onAttach(Context)} method and before 207 * {@link Fragment#onCreate(Bundle)}. 208 */ onAttachFragment(Fragment fragment)209 public void onAttachFragment(Fragment fragment) { 210 } 211 212 @Nullable 213 @Override onFindViewById(int id)214 public <T extends View> T onFindViewById(int id) { 215 return null; 216 } 217 218 @Override onHasView()219 public boolean onHasView() { 220 return true; 221 } 222 getRetainLoaders()223 boolean getRetainLoaders() { 224 return mRetainLoaders; 225 } 226 getActivity()227 Activity getActivity() { 228 return mActivity; 229 } 230 getContext()231 Context getContext() { 232 return mContext; 233 } 234 getHandler()235 Handler getHandler() { 236 return mHandler; 237 } 238 getFragmentManagerImpl()239 FragmentManagerImpl getFragmentManagerImpl() { 240 return mFragmentManager; 241 } 242 getLoaderManagerImpl()243 LoaderManagerImpl getLoaderManagerImpl() { 244 if (mLoaderManager != null) { 245 return mLoaderManager; 246 } 247 mCheckedForLoaderManager = true; 248 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/); 249 return mLoaderManager; 250 } 251 inactivateFragment(String who)252 void inactivateFragment(String who) { 253 //Log.v(TAG, "invalidateSupportFragment: who=" + who); 254 if (mAllLoaderManagers != null) { 255 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who); 256 if (lm != null && !lm.mRetaining) { 257 lm.doDestroy(); 258 mAllLoaderManagers.remove(who); 259 } 260 } 261 } 262 doLoaderStart()263 void doLoaderStart() { 264 if (mLoadersStarted) { 265 return; 266 } 267 mLoadersStarted = true; 268 269 if (mLoaderManager != null) { 270 mLoaderManager.doStart(); 271 } else if (!mCheckedForLoaderManager) { 272 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); 273 } 274 mCheckedForLoaderManager = true; 275 } 276 doLoaderStop(boolean retain)277 void doLoaderStop(boolean retain) { 278 mRetainLoaders = retain; 279 280 if (mLoaderManager == null) { 281 return; 282 } 283 284 if (!mLoadersStarted) { 285 return; 286 } 287 mLoadersStarted = false; 288 289 if (retain) { 290 mLoaderManager.doRetain(); 291 } else { 292 mLoaderManager.doStop(); 293 } 294 } 295 doLoaderRetain()296 void doLoaderRetain() { 297 if (mLoaderManager == null) { 298 return; 299 } 300 mLoaderManager.doRetain(); 301 } 302 doLoaderDestroy()303 void doLoaderDestroy() { 304 if (mLoaderManager == null) { 305 return; 306 } 307 mLoaderManager.doDestroy(); 308 } 309 reportLoaderStart()310 void reportLoaderStart() { 311 if (mAllLoaderManagers != null) { 312 final int N = mAllLoaderManagers.size(); 313 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N]; 314 for (int i=N-1; i>=0; i--) { 315 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i); 316 } 317 for (int i=0; i<N; i++) { 318 LoaderManagerImpl lm = loaders[i]; 319 lm.finishRetain(); 320 lm.doReportStart(); 321 } 322 } 323 } 324 getLoaderManager(String who, boolean started, boolean create)325 LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) { 326 if (mAllLoaderManagers == null) { 327 mAllLoaderManagers = new ArrayMap<String, LoaderManager>(); 328 } 329 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who); 330 if (lm == null && create) { 331 lm = new LoaderManagerImpl(who, this, started); 332 mAllLoaderManagers.put(who, lm); 333 } else if (started && lm != null && !lm.mStarted){ 334 lm.doStart(); 335 } 336 return lm; 337 } 338 retainLoaderNonConfig()339 ArrayMap<String, LoaderManager> retainLoaderNonConfig() { 340 boolean retainLoaders = false; 341 if (mAllLoaderManagers != null) { 342 // Restart any loader managers that were already stopped so that they 343 // will be ready to retain 344 final int N = mAllLoaderManagers.size(); 345 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N]; 346 for (int i=N-1; i>=0; i--) { 347 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i); 348 } 349 final boolean doRetainLoaders = getRetainLoaders(); 350 for (int i=0; i<N; i++) { 351 LoaderManagerImpl lm = loaders[i]; 352 if (!lm.mRetaining && doRetainLoaders) { 353 if (!lm.mStarted) { 354 lm.doStart(); 355 } 356 lm.doRetain(); 357 } 358 if (lm.mRetaining) { 359 retainLoaders = true; 360 } else { 361 lm.doDestroy(); 362 mAllLoaderManagers.remove(lm.mWho); 363 } 364 } 365 } 366 367 if (retainLoaders) { 368 return mAllLoaderManagers; 369 } 370 return null; 371 } 372 restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers)373 void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) { 374 if (loaderManagers != null) { 375 for (int i = 0, N = loaderManagers.size(); i < N; i++) { 376 ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this); 377 } 378 } 379 mAllLoaderManagers = loaderManagers; 380 } 381 dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)382 void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 383 writer.print(prefix); writer.print("mLoadersStarted="); 384 writer.println(mLoadersStarted); 385 if (mLoaderManager != null) { 386 writer.print(prefix); writer.print("Loader Manager "); 387 writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager))); 388 writer.println(":"); 389 mLoaderManager.dump(prefix + " ", fd, writer, args); 390 } 391 } 392 } 393