FragmentManager.java revision 445646c52128a763b56ed7bb3bd009e2f33e3e4f
1/* 2 * Copyright (C) 2010 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.app; 18 19import android.content.res.TypedArray; 20import android.os.Bundle; 21import android.os.Handler; 22import android.os.Parcel; 23import android.os.Parcelable; 24import android.util.Log; 25import android.util.SparseArray; 26import android.view.Menu; 27import android.view.MenuInflater; 28import android.view.MenuItem; 29import android.view.View; 30import android.view.ViewGroup; 31import android.view.animation.Animation; 32import android.view.animation.AnimationUtils; 33 34import java.util.ArrayList; 35 36final class FragmentManagerState implements Parcelable { 37 FragmentState[] mActive; 38 int[] mAdded; 39 BackStackState[] mBackStack; 40 41 public FragmentManagerState() { 42 } 43 44 public FragmentManagerState(Parcel in) { 45 mActive = in.createTypedArray(FragmentState.CREATOR); 46 mAdded = in.createIntArray(); 47 mBackStack = in.createTypedArray(BackStackState.CREATOR); 48 } 49 50 public int describeContents() { 51 return 0; 52 } 53 54 public void writeToParcel(Parcel dest, int flags) { 55 dest.writeTypedArray(mActive, flags); 56 dest.writeIntArray(mAdded); 57 dest.writeTypedArray(mBackStack, flags); 58 } 59 60 public static final Parcelable.Creator<FragmentManagerState> CREATOR 61 = new Parcelable.Creator<FragmentManagerState>() { 62 public FragmentManagerState createFromParcel(Parcel in) { 63 return new FragmentManagerState(in); 64 } 65 66 public FragmentManagerState[] newArray(int size) { 67 return new FragmentManagerState[size]; 68 } 69 }; 70} 71 72/** 73 * @hide 74 * Container for fragments associated with an activity. 75 */ 76public class FragmentManager { 77 static final boolean DEBUG = true; 78 static final String TAG = "FragmentManager"; 79 80 ArrayList<Runnable> mPendingActions; 81 Runnable[] mTmpActions; 82 boolean mExecutingActions; 83 84 ArrayList<Fragment> mActive; 85 ArrayList<Fragment> mAdded; 86 ArrayList<Integer> mAvailIndices; 87 ArrayList<BackStackEntry> mBackStack; 88 89 int mCurState = Fragment.INITIALIZING; 90 Activity mActivity; 91 92 boolean mNeedMenuInvalidate; 93 94 // Temporary vars for state save and restore. 95 Bundle mStateBundle = null; 96 SparseArray<Parcelable> mStateArray = null; 97 98 Runnable mExecCommit = new Runnable() { 99 @Override 100 public void run() { 101 execPendingActions(); 102 } 103 }; 104 105 Animation loadAnimation(Fragment fragment, int transit, boolean enter, 106 int transitionStyle) { 107 Animation animObj = fragment.onCreateAnimation(transitionStyle, enter, 108 fragment.mNextAnim); 109 if (animObj != null) { 110 return animObj; 111 } 112 113 if (fragment.mNextAnim != 0) { 114 Animation anim = AnimationUtils.loadAnimation(mActivity, fragment.mNextAnim); 115 if (anim != null) { 116 return anim; 117 } 118 } 119 120 if (transit == 0) { 121 return null; 122 } 123 124 int styleIndex = transitToStyleIndex(transit, enter); 125 if (styleIndex < 0) { 126 return null; 127 } 128 129 if (transitionStyle == 0 && mActivity.getWindow() != null) { 130 transitionStyle = mActivity.getWindow().getAttributes().windowAnimations; 131 } 132 if (transitionStyle == 0) { 133 return null; 134 } 135 136 TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle, 137 com.android.internal.R.styleable.WindowAnimation); 138 int anim = attrs.getResourceId(styleIndex, 0); 139 attrs.recycle(); 140 141 if (anim == 0) { 142 return null; 143 } 144 145 return AnimationUtils.loadAnimation(mActivity, anim); 146 } 147 148 void moveToState(Fragment f, int newState, int transit, int transitionStyle) { 149 // Fragments that are not currently added will sit in the onCreate() state. 150 if (!f.mAdded && newState > Fragment.CREATED) { 151 newState = Fragment.CREATED; 152 } 153 154 if (f.mState < newState) { 155 switch (f.mState) { 156 case Fragment.INITIALIZING: 157 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f); 158 f.mActivity = mActivity; 159 f.mCalled = false; 160 f.onAttach(mActivity); 161 if (!f.mCalled) { 162 throw new SuperNotCalledException("Fragment " + f 163 + " did not call through to super.onAttach()"); 164 } 165 166 if (!f.mRetaining) { 167 f.mCalled = false; 168 f.onCreate(f.mSavedFragmentState); 169 if (!f.mCalled) { 170 throw new SuperNotCalledException("Fragment " + f 171 + " did not call through to super.onCreate()"); 172 } 173 } 174 f.mRetaining = false; 175 if (f.mFromLayout) { 176 // For fragments that are part of the content view 177 // layout, we need to instantiate the view immediately 178 // and the inflater will take care of adding it. 179 f.mView = f.onCreateView(mActivity.getLayoutInflater(), 180 null, f.mSavedFragmentState); 181 if (f.mView != null) { 182 f.mView.setSaveFromParentEnabled(false); 183 f.restoreViewState(); 184 if (f.mHidden) f.mView.setVisibility(View.GONE); 185 } 186 } 187 case Fragment.CREATED: 188 if (newState > Fragment.CREATED) { 189 if (DEBUG) Log.v(TAG, "moveto CONTENT: " + f); 190 if (!f.mFromLayout) { 191 ViewGroup container = null; 192 if (f.mContainerId != 0) { 193 container = (ViewGroup)mActivity.findViewById(f.mContainerId); 194 if (container == null) { 195 throw new IllegalArgumentException("New view found for id 0x" 196 + Integer.toHexString(f.mContainerId) 197 + " for fragment " + f); 198 } 199 } 200 f.mContainer = container; 201 f.mView = f.onCreateView(mActivity.getLayoutInflater(), 202 container, f.mSavedFragmentState); 203 if (f.mView != null) { 204 f.mView.setSaveFromParentEnabled(false); 205 if (container != null) { 206 Animation anim = loadAnimation(f, transit, true, 207 transitionStyle); 208 if (anim != null) { 209 f.mView.setAnimation(anim); 210 } 211 container.addView(f.mView); 212 f.restoreViewState(); 213 } 214 if (f.mHidden) f.mView.setVisibility(View.GONE); 215 } 216 } 217 218 f.mCalled = false; 219 f.onReady(f.mSavedFragmentState); 220 if (!f.mCalled) { 221 throw new SuperNotCalledException("Fragment " + f 222 + " did not call through to super.onReady()"); 223 } 224 f.mSavedFragmentState = null; 225 } 226 case Fragment.CONTENT: 227 if (newState > Fragment.CONTENT) { 228 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); 229 f.mCalled = false; 230 f.onStart(); 231 if (!f.mCalled) { 232 throw new SuperNotCalledException("Fragment " + f 233 + " did not call through to super.onStart()"); 234 } 235 } 236 case Fragment.STARTED: 237 if (newState > Fragment.STARTED) { 238 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f); 239 f.mCalled = false; 240 f.onResume(); 241 if (!f.mCalled) { 242 throw new SuperNotCalledException("Fragment " + f 243 + " did not call through to super.onResume()"); 244 } 245 } 246 } 247 } else if (f.mState > newState) { 248 switch (f.mState) { 249 case Fragment.RESUMED: 250 if (newState < Fragment.RESUMED) { 251 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f); 252 f.mCalled = false; 253 f.onPause(); 254 if (!f.mCalled) { 255 throw new SuperNotCalledException("Fragment " + f 256 + " did not call through to super.onPause()"); 257 } 258 } 259 case Fragment.STARTED: 260 if (newState < Fragment.STARTED) { 261 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f); 262 f.mCalled = false; 263 f.onStop(); 264 if (!f.mCalled) { 265 throw new SuperNotCalledException("Fragment " + f 266 + " did not call through to super.onStop()"); 267 } 268 } 269 case Fragment.CONTENT: 270 if (newState < Fragment.CONTENT) { 271 if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f); 272 if (f.mView != null) { 273 f.mCalled = false; 274 f.onDestroyView(); 275 if (!f.mCalled) { 276 throw new SuperNotCalledException("Fragment " + f 277 + " did not call through to super.onDestroyedView()"); 278 } 279 // Need to save the current view state if not 280 // done already. 281 if (!mActivity.isFinishing() && f.mSavedFragmentState == null) { 282 saveFragmentViewState(f); 283 } 284 if (f.mContainer != null) { 285 if (mCurState > Fragment.INITIALIZING) { 286 Animation anim = loadAnimation(f, transit, false, 287 transitionStyle); 288 if (anim != null) { 289 f.mView.setAnimation(anim); 290 } 291 } 292 f.mContainer.removeView(f.mView); 293 } 294 } 295 f.mContainer = null; 296 f.mView = null; 297 } 298 case Fragment.CREATED: 299 if (newState < Fragment.CREATED) { 300 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f); 301 if (!f.mRetaining) { 302 f.mCalled = false; 303 f.onDestroy(); 304 if (!f.mCalled) { 305 throw new SuperNotCalledException("Fragment " + f 306 + " did not call through to super.onDestroy()"); 307 } 308 } 309 310 f.mCalled = false; 311 f.onDetach(); 312 if (!f.mCalled) { 313 throw new SuperNotCalledException("Fragment " + f 314 + " did not call through to super.onDetach()"); 315 } 316 f.mActivity = null; 317 } 318 } 319 } 320 321 f.mState = newState; 322 } 323 324 void moveToState(int newState, boolean always) { 325 moveToState(newState, 0, 0, always); 326 } 327 328 void moveToState(int newState, int transit, int transitStyle, boolean always) { 329 if (mActivity == null && newState != Fragment.INITIALIZING) { 330 throw new IllegalStateException("No activity"); 331 } 332 333 if (!always && mCurState == newState) { 334 return; 335 } 336 337 mCurState = newState; 338 if (mActive != null) { 339 for (int i=0; i<mActive.size(); i++) { 340 Fragment f = mActive.get(i); 341 if (f != null) { 342 moveToState(f, newState, transit, transitStyle); 343 } 344 } 345 } 346 } 347 348 void makeActive(Fragment f) { 349 if (f.mIndex >= 0) { 350 return; 351 } 352 353 if (mAvailIndices == null || mAvailIndices.size() <= 0) { 354 if (mActive == null) { 355 mActive = new ArrayList<Fragment>(); 356 } 357 f.setIndex(mActive.size()); 358 mActive.add(f); 359 360 } else { 361 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1)); 362 mActive.set(f.mIndex, f); 363 } 364 } 365 366 void makeInactive(Fragment f) { 367 if (f.mIndex < 0) { 368 return; 369 } 370 371 mActive.set(f.mIndex, null); 372 if (mAvailIndices == null) { 373 mAvailIndices = new ArrayList<Integer>(); 374 } 375 mAvailIndices.add(f.mIndex); 376 f.clearIndex(); 377 } 378 379 public void addFragment(Fragment fragment, boolean moveToStateNow) { 380 if (DEBUG) Log.v(TAG, "add: " + fragment); 381 if (mAdded == null) { 382 mAdded = new ArrayList<Fragment>(); 383 } 384 mAdded.add(fragment); 385 makeActive(fragment); 386 fragment.mAdded = true; 387 if (fragment.mHasMenu) { 388 mNeedMenuInvalidate = true; 389 } 390 if (moveToStateNow) { 391 moveToState(fragment, mCurState, 0, 0); 392 } 393 } 394 395 public void removeFragment(Fragment fragment, int transition, int transitionStyle) { 396 if (DEBUG) Log.v(TAG, "remove: " + fragment); 397 mAdded.remove(fragment); 398 final boolean inactive = fragment.mBackStackNesting <= 0; 399 if (inactive) { 400 makeInactive(fragment); 401 } 402 if (fragment.mHasMenu) { 403 mNeedMenuInvalidate = true; 404 } 405 fragment.mAdded = false; 406 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED, 407 transition, transitionStyle); 408 } 409 410 public void hideFragment(Fragment fragment, int transition, int transitionStyle) { 411 if (DEBUG) Log.v(TAG, "hide: " + fragment); 412 if (!fragment.mHidden) { 413 fragment.mHidden = true; 414 if (fragment.mView != null) { 415 Animation anim = loadAnimation(fragment, transition, false, 416 transitionStyle); 417 if (anim != null) { 418 fragment.mView.setAnimation(anim); 419 } 420 fragment.mView.setVisibility(View.GONE); 421 } 422 if (fragment.mAdded && fragment.mHasMenu) { 423 mNeedMenuInvalidate = true; 424 } 425 fragment.onHiddenChanged(true); 426 } 427 } 428 429 public void showFragment(Fragment fragment, int transition, int transitionStyle) { 430 if (DEBUG) Log.v(TAG, "show: " + fragment); 431 if (fragment.mHidden) { 432 fragment.mHidden = false; 433 if (fragment.mView != null) { 434 Animation anim = loadAnimation(fragment, transition, true, 435 transitionStyle); 436 if (anim != null) { 437 fragment.mView.setAnimation(anim); 438 } 439 fragment.mView.setVisibility(View.VISIBLE); 440 } 441 if (fragment.mAdded && fragment.mHasMenu) { 442 mNeedMenuInvalidate = true; 443 } 444 fragment.onHiddenChanged(false); 445 } 446 } 447 448 public Fragment findFragmentById(int id) { 449 if (mActive != null) { 450 // First look through added fragments. 451 for (int i=mAdded.size()-1; i>=0; i--) { 452 Fragment f = mAdded.get(i); 453 if (f != null && f.mFragmentId == id) { 454 return f; 455 } 456 } 457 // Now for any known fragment. 458 for (int i=mActive.size()-1; i>=0; i--) { 459 Fragment f = mActive.get(i); 460 if (f != null && f.mFragmentId == id) { 461 return f; 462 } 463 } 464 } 465 return null; 466 } 467 468 public Fragment findFragmentByTag(String tag) { 469 if (mActive != null && tag != null) { 470 // First look through added fragments. 471 for (int i=mAdded.size()-1; i>=0; i--) { 472 Fragment f = mAdded.get(i); 473 if (f != null && tag.equals(f.mTag)) { 474 return f; 475 } 476 } 477 // Now for any known fragment. 478 for (int i=mActive.size()-1; i>=0; i--) { 479 Fragment f = mActive.get(i); 480 if (f != null && tag.equals(f.mTag)) { 481 return f; 482 } 483 } 484 } 485 return null; 486 } 487 488 public Fragment findFragmentByWho(String who) { 489 if (mActive != null && who != null) { 490 for (int i=mActive.size()-1; i>=0; i--) { 491 Fragment f = mActive.get(i); 492 if (f != null && who.equals(f.mWho)) { 493 return f; 494 } 495 } 496 } 497 return null; 498 } 499 500 public void enqueueAction(Runnable action) { 501 synchronized (this) { 502 if (mPendingActions == null) { 503 mPendingActions = new ArrayList<Runnable>(); 504 } 505 mPendingActions.add(action); 506 if (mPendingActions.size() == 1) { 507 mActivity.mHandler.removeCallbacks(mExecCommit); 508 mActivity.mHandler.post(mExecCommit); 509 } 510 } 511 } 512 513 /** 514 * Only call from main thread! 515 */ 516 public void execPendingActions() { 517 if (mExecutingActions) { 518 throw new IllegalStateException("Recursive entry to execPendingActions"); 519 } 520 521 while (true) { 522 int numActions; 523 524 synchronized (this) { 525 if (mPendingActions == null || mPendingActions.size() == 0) { 526 return; 527 } 528 529 numActions = mPendingActions.size(); 530 if (mTmpActions == null || mTmpActions.length < numActions) { 531 mTmpActions = new Runnable[numActions]; 532 } 533 mPendingActions.toArray(mTmpActions); 534 mPendingActions.clear(); 535 mActivity.mHandler.removeCallbacks(mExecCommit); 536 } 537 538 mExecutingActions = true; 539 for (int i=0; i<numActions; i++) { 540 mTmpActions[i].run(); 541 } 542 mExecutingActions = false; 543 } 544 } 545 546 public void addBackStackState(BackStackEntry state) { 547 if (mBackStack == null) { 548 mBackStack = new ArrayList<BackStackEntry>(); 549 } 550 mBackStack.add(state); 551 } 552 553 public boolean popBackStackState(Handler handler, String name) { 554 if (mBackStack == null) { 555 return false; 556 } 557 if (name == null) { 558 int last = mBackStack.size()-1; 559 if (last < 0) { 560 return false; 561 } 562 final BackStackEntry bss = mBackStack.remove(last); 563 enqueueAction(new Runnable() { 564 public void run() { 565 if (DEBUG) Log.v(TAG, "Popping back stack state: " + bss); 566 bss.popFromBackStack(); 567 moveToState(mCurState, reverseTransit(bss.getTransition()), 568 bss.getTransitionStyle(), true); 569 } 570 }); 571 } else { 572 int index = mBackStack.size()-1; 573 while (index >= 0) { 574 BackStackEntry bss = mBackStack.get(index); 575 if (name.equals(bss.getName())) { 576 break; 577 } 578 } 579 if (index < 0 || index == mBackStack.size()-1) { 580 return false; 581 } 582 final ArrayList<BackStackEntry> states 583 = new ArrayList<BackStackEntry>(); 584 for (int i=mBackStack.size()-1; i>index; i--) { 585 states.add(mBackStack.remove(i)); 586 } 587 enqueueAction(new Runnable() { 588 public void run() { 589 for (int i=0; i<states.size(); i++) { 590 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); 591 states.get(i).popFromBackStack(); 592 } 593 moveToState(mCurState, true); 594 } 595 }); 596 } 597 return true; 598 } 599 600 ArrayList<Fragment> retainNonConfig() { 601 ArrayList<Fragment> fragments = null; 602 if (mActive != null) { 603 for (int i=0; i<mActive.size(); i++) { 604 Fragment f = mActive.get(i); 605 if (f != null && f.mRetainInstance) { 606 if (fragments == null) { 607 fragments = new ArrayList<Fragment>(); 608 } 609 fragments.add(f); 610 f.mRetaining = true; 611 } 612 } 613 } 614 return fragments; 615 } 616 617 void saveFragmentViewState(Fragment f) { 618 if (f.mView == null) { 619 return; 620 } 621 if (mStateArray == null) { 622 mStateArray = new SparseArray<Parcelable>(); 623 } 624 f.mView.saveHierarchyState(mStateArray); 625 if (mStateArray.size() > 0) { 626 f.mSavedViewState = mStateArray; 627 mStateArray = null; 628 } 629 } 630 631 Parcelable saveAllState() { 632 if (mActive == null || mActive.size() <= 0) { 633 return null; 634 } 635 636 // First collect all active fragments. 637 int N = mActive.size(); 638 FragmentState[] active = new FragmentState[N]; 639 boolean haveFragments = false; 640 for (int i=0; i<N; i++) { 641 Fragment f = mActive.get(i); 642 if (f != null) { 643 haveFragments = true; 644 645 FragmentState fs = new FragmentState(f); 646 active[i] = fs; 647 648 if (mStateBundle == null) { 649 mStateBundle = new Bundle(); 650 } 651 f.onSaveInstanceState(mStateBundle); 652 if (!mStateBundle.isEmpty()) { 653 fs.mSavedFragmentState = mStateBundle; 654 mStateBundle = null; 655 } 656 657 if (f.mView != null) { 658 saveFragmentViewState(f); 659 if (f.mSavedViewState != null) { 660 if (fs.mSavedFragmentState == null) { 661 fs.mSavedFragmentState = new Bundle(); 662 } 663 fs.mSavedFragmentState.putSparseParcelableArray( 664 FragmentState.VIEW_STATE_TAG, f.mSavedViewState); 665 } 666 } 667 668 } 669 } 670 671 if (!haveFragments) { 672 return null; 673 } 674 675 int[] added = null; 676 BackStackState[] backStack = null; 677 678 // Build list of currently added fragments. 679 N = mAdded.size(); 680 if (N > 0) { 681 added = new int[N]; 682 for (int i=0; i<N; i++) { 683 added[i] = mAdded.get(i).mIndex; 684 } 685 } 686 687 // Now save back stack. 688 if (mBackStack != null) { 689 N = mBackStack.size(); 690 if (N > 0) { 691 backStack = new BackStackState[N]; 692 for (int i=0; i<N; i++) { 693 backStack[i] = new BackStackState(this, mBackStack.get(i)); 694 } 695 } 696 } 697 698 FragmentManagerState fms = new FragmentManagerState(); 699 fms.mActive = active; 700 fms.mAdded = added; 701 fms.mBackStack = backStack; 702 return fms; 703 } 704 705 void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) { 706 // If there is no saved state at all, then there can not be 707 // any nonConfig fragments either, so that is that. 708 if (state == null) return; 709 FragmentManagerState fms = (FragmentManagerState)state; 710 if (fms.mActive == null) return; 711 712 // First re-attach any non-config instances we are retaining back 713 // to their saved state, so we don't try to instantiate them again. 714 if (nonConfig != null) { 715 for (int i=0; i<nonConfig.size(); i++) { 716 Fragment f = nonConfig.get(i); 717 FragmentState fs = fms.mActive[f.mIndex]; 718 fs.mInstance = f; 719 f.mSavedViewState = null; 720 f.mBackStackNesting = 0; 721 f.mAdded = false; 722 if (fs.mSavedFragmentState != null) { 723 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray( 724 FragmentState.VIEW_STATE_TAG); 725 } 726 } 727 } 728 729 // Build the full list of active fragments, instantiating them from 730 // their saved state. 731 mActive = new ArrayList<Fragment>(fms.mActive.length); 732 if (mAvailIndices != null) { 733 mAvailIndices.clear(); 734 } 735 for (int i=0; i<fms.mActive.length; i++) { 736 FragmentState fs = fms.mActive[i]; 737 if (fs != null) { 738 mActive.add(fs.instantiate(mActivity)); 739 } else { 740 mActive.add(null); 741 if (mAvailIndices == null) { 742 mAvailIndices = new ArrayList<Integer>(); 743 } 744 mAvailIndices.add(i); 745 } 746 } 747 748 // Build the list of currently added fragments. 749 if (fms.mAdded != null) { 750 mAdded = new ArrayList<Fragment>(fms.mAdded.length); 751 for (int i=0; i<fms.mAdded.length; i++) { 752 Fragment f = mActive.get(fms.mAdded[i]); 753 if (f == null) { 754 throw new IllegalStateException( 755 "No instantiated fragment for index #" + fms.mAdded[i]); 756 } 757 f.mAdded = true; 758 f.mImmediateActivity = mActivity; 759 mAdded.add(f); 760 } 761 } else { 762 mAdded = null; 763 } 764 765 // Build the back stack. 766 if (fms.mBackStack != null) { 767 mBackStack = new ArrayList<BackStackEntry>(fms.mBackStack.length); 768 for (int i=0; i<fms.mBackStack.length; i++) { 769 BackStackEntry bse = fms.mBackStack[i].instantiate(this); 770 mBackStack.add(bse); 771 } 772 } else { 773 mBackStack = null; 774 } 775 } 776 777 public void attachActivity(Activity activity) { 778 if (mActivity != null) throw new IllegalStateException(); 779 mActivity = activity; 780 } 781 782 public void dispatchCreate() { 783 moveToState(Fragment.CREATED, false); 784 } 785 786 public void dispatchStart() { 787 moveToState(Fragment.STARTED, false); 788 } 789 790 public void dispatchResume() { 791 moveToState(Fragment.RESUMED, false); 792 } 793 794 public void dispatchPause() { 795 moveToState(Fragment.STARTED, false); 796 } 797 798 public void dispatchStop() { 799 moveToState(Fragment.CONTENT, false); 800 } 801 802 public void dispatchDestroy() { 803 moveToState(Fragment.INITIALIZING, false); 804 mActivity = null; 805 } 806 807 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { 808 boolean show = false; 809 if (mActive != null) { 810 for (int i=0; i<mAdded.size(); i++) { 811 Fragment f = mAdded.get(i); 812 if (f != null && !f.mHidden && f.mHasMenu) { 813 show = true; 814 f.onCreateOptionsMenu(menu, inflater); 815 } 816 } 817 } 818 return show; 819 } 820 821 public boolean dispatchPrepareOptionsMenu(Menu menu) { 822 boolean show = false; 823 if (mActive != null) { 824 for (int i=0; i<mAdded.size(); i++) { 825 Fragment f = mAdded.get(i); 826 if (f != null && !f.mHidden && f.mHasMenu) { 827 show = true; 828 f.onPrepareOptionsMenu(menu); 829 } 830 } 831 } 832 return show; 833 } 834 835 public boolean dispatchOptionsItemSelected(MenuItem item) { 836 if (mActive != null) { 837 for (int i=0; i<mAdded.size(); i++) { 838 Fragment f = mAdded.get(i); 839 if (f != null && !f.mHidden && f.mHasMenu) { 840 if (f.onOptionsItemSelected(item)) { 841 return true; 842 } 843 } 844 } 845 } 846 return false; 847 } 848 849 public boolean dispatchContextItemSelected(MenuItem item) { 850 if (mActive != null) { 851 for (int i=0; i<mAdded.size(); i++) { 852 Fragment f = mAdded.get(i); 853 if (f != null && !f.mHidden) { 854 if (f.onContextItemSelected(item)) { 855 return true; 856 } 857 } 858 } 859 } 860 return false; 861 } 862 863 public void dispatchOptionsMenuClosed(Menu menu) { 864 if (mActive != null) { 865 for (int i=0; i<mAdded.size(); i++) { 866 Fragment f = mAdded.get(i); 867 if (f != null && !f.mHidden && f.mHasMenu) { 868 f.onOptionsMenuClosed(menu); 869 } 870 } 871 } 872 } 873 874 public static int reverseTransit(int transit) { 875 int rev = 0; 876 switch (transit) { 877 case FragmentTransaction.TRANSIT_ENTER: 878 rev = FragmentTransaction.TRANSIT_EXIT; 879 break; 880 case FragmentTransaction.TRANSIT_EXIT: 881 rev = FragmentTransaction.TRANSIT_ENTER; 882 break; 883 case FragmentTransaction.TRANSIT_SHOW: 884 rev = FragmentTransaction.TRANSIT_HIDE; 885 break; 886 case FragmentTransaction.TRANSIT_HIDE: 887 rev = FragmentTransaction.TRANSIT_SHOW; 888 break; 889 case FragmentTransaction.TRANSIT_ACTIVITY_OPEN: 890 rev = FragmentTransaction.TRANSIT_ACTIVITY_CLOSE; 891 break; 892 case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE: 893 rev = FragmentTransaction.TRANSIT_ACTIVITY_OPEN; 894 break; 895 case FragmentTransaction.TRANSIT_TASK_OPEN: 896 rev = FragmentTransaction.TRANSIT_TASK_CLOSE; 897 break; 898 case FragmentTransaction.TRANSIT_TASK_CLOSE: 899 rev = FragmentTransaction.TRANSIT_TASK_OPEN; 900 break; 901 case FragmentTransaction.TRANSIT_TASK_TO_FRONT: 902 rev = FragmentTransaction.TRANSIT_TASK_TO_BACK; 903 break; 904 case FragmentTransaction.TRANSIT_TASK_TO_BACK: 905 rev = FragmentTransaction.TRANSIT_TASK_TO_FRONT; 906 break; 907 case FragmentTransaction.TRANSIT_WALLPAPER_OPEN: 908 rev = FragmentTransaction.TRANSIT_WALLPAPER_CLOSE; 909 break; 910 case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE: 911 rev = FragmentTransaction.TRANSIT_WALLPAPER_OPEN; 912 break; 913 case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN: 914 rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE; 915 break; 916 case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE: 917 rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN; 918 break; 919 } 920 return rev; 921 922 } 923 924 public static int transitToStyleIndex(int transit, boolean enter) { 925 int animAttr = -1; 926 switch (transit) { 927 case FragmentTransaction.TRANSIT_ENTER: 928 animAttr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation; 929 break; 930 case FragmentTransaction.TRANSIT_EXIT: 931 animAttr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation; 932 break; 933 case FragmentTransaction.TRANSIT_SHOW: 934 animAttr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation; 935 break; 936 case FragmentTransaction.TRANSIT_HIDE: 937 animAttr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation; 938 break; 939 case FragmentTransaction.TRANSIT_ACTIVITY_OPEN: 940 animAttr = enter 941 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation 942 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 943 break; 944 case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE: 945 animAttr = enter 946 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation 947 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 948 break; 949 case FragmentTransaction.TRANSIT_TASK_OPEN: 950 animAttr = enter 951 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation 952 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 953 break; 954 case FragmentTransaction.TRANSIT_TASK_CLOSE: 955 animAttr = enter 956 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation 957 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 958 break; 959 case FragmentTransaction.TRANSIT_TASK_TO_FRONT: 960 animAttr = enter 961 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation 962 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 963 break; 964 case FragmentTransaction.TRANSIT_TASK_TO_BACK: 965 animAttr = enter 966 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation 967 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 968 break; 969 case FragmentTransaction.TRANSIT_WALLPAPER_OPEN: 970 animAttr = enter 971 ? com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation 972 : com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; 973 break; 974 case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE: 975 animAttr = enter 976 ? com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation 977 : com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 978 break; 979 case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN: 980 animAttr = enter 981 ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation 982 : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 983 break; 984 case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE: 985 animAttr = enter 986 ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation 987 : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 988 break; 989 } 990 return animAttr; 991 } 992} 993