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