1/* 2 * Copyright (C) 2011 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.support.v4.app; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.support.v4.util.LogWriter; 22import android.text.TextUtils; 23import android.util.Log; 24 25import java.io.FileDescriptor; 26import java.io.PrintWriter; 27import java.util.ArrayList; 28 29final class BackStackState implements Parcelable { 30 final int[] mOps; 31 final int mTransition; 32 final int mTransitionStyle; 33 final String mName; 34 final int mIndex; 35 final int mBreadCrumbTitleRes; 36 final CharSequence mBreadCrumbTitleText; 37 final int mBreadCrumbShortTitleRes; 38 final CharSequence mBreadCrumbShortTitleText; 39 40 public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) { 41 int numRemoved = 0; 42 BackStackRecord.Op op = bse.mHead; 43 while (op != null) { 44 if (op.removed != null) numRemoved += op.removed.size(); 45 op = op.next; 46 } 47 mOps = new int[bse.mNumOp*7 + numRemoved]; 48 49 if (!bse.mAddToBackStack) { 50 throw new IllegalStateException("Not on back stack"); 51 } 52 53 op = bse.mHead; 54 int pos = 0; 55 while (op != null) { 56 mOps[pos++] = op.cmd; 57 mOps[pos++] = op.fragment != null ? op.fragment.mIndex : -1; 58 mOps[pos++] = op.enterAnim; 59 mOps[pos++] = op.exitAnim; 60 mOps[pos++] = op.popEnterAnim; 61 mOps[pos++] = op.popExitAnim; 62 if (op.removed != null) { 63 final int N = op.removed.size(); 64 mOps[pos++] = N; 65 for (int i=0; i<N; i++) { 66 mOps[pos++] = op.removed.get(i).mIndex; 67 } 68 } else { 69 mOps[pos++] = 0; 70 } 71 op = op.next; 72 } 73 mTransition = bse.mTransition; 74 mTransitionStyle = bse.mTransitionStyle; 75 mName = bse.mName; 76 mIndex = bse.mIndex; 77 mBreadCrumbTitleRes = bse.mBreadCrumbTitleRes; 78 mBreadCrumbTitleText = bse.mBreadCrumbTitleText; 79 mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes; 80 mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText; 81 } 82 83 public BackStackState(Parcel in) { 84 mOps = in.createIntArray(); 85 mTransition = in.readInt(); 86 mTransitionStyle = in.readInt(); 87 mName = in.readString(); 88 mIndex = in.readInt(); 89 mBreadCrumbTitleRes = in.readInt(); 90 mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 91 mBreadCrumbShortTitleRes = in.readInt(); 92 mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 93 } 94 95 public BackStackRecord instantiate(FragmentManagerImpl fm) { 96 BackStackRecord bse = new BackStackRecord(fm); 97 int pos = 0; 98 int num = 0; 99 while (pos < mOps.length) { 100 BackStackRecord.Op op = new BackStackRecord.Op(); 101 op.cmd = mOps[pos++]; 102 if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG, 103 "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]); 104 int findex = mOps[pos++]; 105 if (findex >= 0) { 106 Fragment f = fm.mActive.get(findex); 107 op.fragment = f; 108 } else { 109 op.fragment = null; 110 } 111 op.enterAnim = mOps[pos++]; 112 op.exitAnim = mOps[pos++]; 113 op.popEnterAnim = mOps[pos++]; 114 op.popExitAnim = mOps[pos++]; 115 final int N = mOps[pos++]; 116 if (N > 0) { 117 op.removed = new ArrayList<Fragment>(N); 118 for (int i=0; i<N; i++) { 119 if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG, 120 "Instantiate " + bse + " set remove fragment #" + mOps[pos]); 121 Fragment r = fm.mActive.get(mOps[pos++]); 122 op.removed.add(r); 123 } 124 } 125 bse.addOp(op); 126 num++; 127 } 128 bse.mTransition = mTransition; 129 bse.mTransitionStyle = mTransitionStyle; 130 bse.mName = mName; 131 bse.mIndex = mIndex; 132 bse.mAddToBackStack = true; 133 bse.mBreadCrumbTitleRes = mBreadCrumbTitleRes; 134 bse.mBreadCrumbTitleText = mBreadCrumbTitleText; 135 bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes; 136 bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText; 137 bse.bumpBackStackNesting(1); 138 return bse; 139 } 140 141 public int describeContents() { 142 return 0; 143 } 144 145 public void writeToParcel(Parcel dest, int flags) { 146 dest.writeIntArray(mOps); 147 dest.writeInt(mTransition); 148 dest.writeInt(mTransitionStyle); 149 dest.writeString(mName); 150 dest.writeInt(mIndex); 151 dest.writeInt(mBreadCrumbTitleRes); 152 TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0); 153 dest.writeInt(mBreadCrumbShortTitleRes); 154 TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0); 155 } 156 157 public static final Parcelable.Creator<BackStackState> CREATOR 158 = new Parcelable.Creator<BackStackState>() { 159 public BackStackState createFromParcel(Parcel in) { 160 return new BackStackState(in); 161 } 162 163 public BackStackState[] newArray(int size) { 164 return new BackStackState[size]; 165 } 166 }; 167} 168 169/** 170 * @hide Entry of an operation on the fragment back stack. 171 */ 172final class BackStackRecord extends FragmentTransaction implements 173 FragmentManager.BackStackEntry, Runnable { 174 static final String TAG = FragmentManagerImpl.TAG; 175 176 final FragmentManagerImpl mManager; 177 178 static final int OP_NULL = 0; 179 static final int OP_ADD = 1; 180 static final int OP_REPLACE = 2; 181 static final int OP_REMOVE = 3; 182 static final int OP_HIDE = 4; 183 static final int OP_SHOW = 5; 184 static final int OP_DETACH = 6; 185 static final int OP_ATTACH = 7; 186 187 static final class Op { 188 Op next; 189 Op prev; 190 int cmd; 191 Fragment fragment; 192 int enterAnim; 193 int exitAnim; 194 int popEnterAnim; 195 int popExitAnim; 196 ArrayList<Fragment> removed; 197 } 198 199 Op mHead; 200 Op mTail; 201 int mNumOp; 202 int mEnterAnim; 203 int mExitAnim; 204 int mPopEnterAnim; 205 int mPopExitAnim; 206 int mTransition; 207 int mTransitionStyle; 208 boolean mAddToBackStack; 209 boolean mAllowAddToBackStack = true; 210 String mName; 211 boolean mCommitted; 212 int mIndex = -1; 213 214 int mBreadCrumbTitleRes; 215 CharSequence mBreadCrumbTitleText; 216 int mBreadCrumbShortTitleRes; 217 CharSequence mBreadCrumbShortTitleText; 218 219 @Override 220 public String toString() { 221 StringBuilder sb = new StringBuilder(128); 222 sb.append("BackStackEntry{"); 223 sb.append(Integer.toHexString(System.identityHashCode(this))); 224 if (mIndex >= 0) { 225 sb.append(" #"); 226 sb.append(mIndex); 227 } 228 if (mName != null) { 229 sb.append(" "); 230 sb.append(mName); 231 } 232 sb.append("}"); 233 return sb.toString(); 234 } 235 236 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 237 dump(prefix, writer, true); 238 } 239 240 public void dump(String prefix, PrintWriter writer, boolean full) { 241 if (full) { 242 writer.print(prefix); writer.print("mName="); writer.print(mName); 243 writer.print(" mIndex="); writer.print(mIndex); 244 writer.print(" mCommitted="); writer.println(mCommitted); 245 if (mTransition != FragmentTransaction.TRANSIT_NONE) { 246 writer.print(prefix); writer.print("mTransition=#"); 247 writer.print(Integer.toHexString(mTransition)); 248 writer.print(" mTransitionStyle=#"); 249 writer.println(Integer.toHexString(mTransitionStyle)); 250 } 251 if (mEnterAnim != 0 || mExitAnim !=0) { 252 writer.print(prefix); writer.print("mEnterAnim=#"); 253 writer.print(Integer.toHexString(mEnterAnim)); 254 writer.print(" mExitAnim=#"); 255 writer.println(Integer.toHexString(mExitAnim)); 256 } 257 if (mPopEnterAnim != 0 || mPopExitAnim !=0) { 258 writer.print(prefix); writer.print("mPopEnterAnim=#"); 259 writer.print(Integer.toHexString(mPopEnterAnim)); 260 writer.print(" mPopExitAnim=#"); 261 writer.println(Integer.toHexString(mPopExitAnim)); 262 } 263 if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) { 264 writer.print(prefix); writer.print("mBreadCrumbTitleRes=#"); 265 writer.print(Integer.toHexString(mBreadCrumbTitleRes)); 266 writer.print(" mBreadCrumbTitleText="); 267 writer.println(mBreadCrumbTitleText); 268 } 269 if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) { 270 writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#"); 271 writer.print(Integer.toHexString(mBreadCrumbShortTitleRes)); 272 writer.print(" mBreadCrumbShortTitleText="); 273 writer.println(mBreadCrumbShortTitleText); 274 } 275 } 276 277 if (mHead != null) { 278 writer.print(prefix); writer.println("Operations:"); 279 String innerPrefix = prefix + " "; 280 Op op = mHead; 281 int num = 0; 282 while (op != null) { 283 String cmdStr; 284 switch (op.cmd) { 285 case OP_NULL: cmdStr="NULL"; break; 286 case OP_ADD: cmdStr="ADD"; break; 287 case OP_REPLACE: cmdStr="REPLACE"; break; 288 case OP_REMOVE: cmdStr="REMOVE"; break; 289 case OP_HIDE: cmdStr="HIDE"; break; 290 case OP_SHOW: cmdStr="SHOW"; break; 291 case OP_DETACH: cmdStr="DETACH"; break; 292 case OP_ATTACH: cmdStr="ATTACH"; break; 293 default: cmdStr="cmd=" + op.cmd; break; 294 } 295 writer.print(prefix); writer.print(" Op #"); writer.print(num); 296 writer.print(": "); writer.print(cmdStr); 297 writer.print(" "); writer.println(op.fragment); 298 if (full) { 299 if (op.enterAnim != 0 || op.exitAnim != 0) { 300 writer.print(prefix); writer.print("enterAnim=#"); 301 writer.print(Integer.toHexString(op.enterAnim)); 302 writer.print(" exitAnim=#"); 303 writer.println(Integer.toHexString(op.exitAnim)); 304 } 305 if (op.popEnterAnim != 0 || op.popExitAnim != 0) { 306 writer.print(prefix); writer.print("popEnterAnim=#"); 307 writer.print(Integer.toHexString(op.popEnterAnim)); 308 writer.print(" popExitAnim=#"); 309 writer.println(Integer.toHexString(op.popExitAnim)); 310 } 311 } 312 if (op.removed != null && op.removed.size() > 0) { 313 for (int i=0; i<op.removed.size(); i++) { 314 writer.print(innerPrefix); 315 if (op.removed.size() == 1) { 316 writer.print("Removed: "); 317 } else { 318 if (i == 0) { 319 writer.println("Removed:"); 320 } 321 writer.print(innerPrefix); writer.print(" #"); writer.print(i); 322 writer.print(": "); 323 } 324 writer.println(op.removed.get(i)); 325 } 326 } 327 op = op.next; 328 num++; 329 } 330 } 331 } 332 333 public BackStackRecord(FragmentManagerImpl manager) { 334 mManager = manager; 335 } 336 337 public int getId() { 338 return mIndex; 339 } 340 341 public int getBreadCrumbTitleRes() { 342 return mBreadCrumbTitleRes; 343 } 344 345 public int getBreadCrumbShortTitleRes() { 346 return mBreadCrumbShortTitleRes; 347 } 348 349 public CharSequence getBreadCrumbTitle() { 350 if (mBreadCrumbTitleRes != 0) { 351 return mManager.mActivity.getText(mBreadCrumbTitleRes); 352 } 353 return mBreadCrumbTitleText; 354 } 355 356 public CharSequence getBreadCrumbShortTitle() { 357 if (mBreadCrumbShortTitleRes != 0) { 358 return mManager.mActivity.getText(mBreadCrumbShortTitleRes); 359 } 360 return mBreadCrumbShortTitleText; 361 } 362 363 void addOp(Op op) { 364 if (mHead == null) { 365 mHead = mTail = op; 366 } else { 367 op.prev = mTail; 368 mTail.next = op; 369 mTail = op; 370 } 371 op.enterAnim = mEnterAnim; 372 op.exitAnim = mExitAnim; 373 op.popEnterAnim = mPopEnterAnim; 374 op.popExitAnim = mPopExitAnim; 375 mNumOp++; 376 } 377 378 public FragmentTransaction add(Fragment fragment, String tag) { 379 doAddOp(0, fragment, tag, OP_ADD); 380 return this; 381 } 382 383 public FragmentTransaction add(int containerViewId, Fragment fragment) { 384 doAddOp(containerViewId, fragment, null, OP_ADD); 385 return this; 386 } 387 388 public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) { 389 doAddOp(containerViewId, fragment, tag, OP_ADD); 390 return this; 391 } 392 393 private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) { 394 fragment.mFragmentManager = mManager; 395 396 if (tag != null) { 397 if (fragment.mTag != null && !tag.equals(fragment.mTag)) { 398 throw new IllegalStateException("Can't change tag of fragment " 399 + fragment + ": was " + fragment.mTag 400 + " now " + tag); 401 } 402 fragment.mTag = tag; 403 } 404 405 if (containerViewId != 0) { 406 if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) { 407 throw new IllegalStateException("Can't change container ID of fragment " 408 + fragment + ": was " + fragment.mFragmentId 409 + " now " + containerViewId); 410 } 411 fragment.mContainerId = fragment.mFragmentId = containerViewId; 412 } 413 414 Op op = new Op(); 415 op.cmd = opcmd; 416 op.fragment = fragment; 417 addOp(op); 418 } 419 420 public FragmentTransaction replace(int containerViewId, Fragment fragment) { 421 return replace(containerViewId, fragment, null); 422 } 423 424 public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) { 425 if (containerViewId == 0) { 426 throw new IllegalArgumentException("Must use non-zero containerViewId"); 427 } 428 429 doAddOp(containerViewId, fragment, tag, OP_REPLACE); 430 return this; 431 } 432 433 public FragmentTransaction remove(Fragment fragment) { 434 Op op = new Op(); 435 op.cmd = OP_REMOVE; 436 op.fragment = fragment; 437 addOp(op); 438 439 return this; 440 } 441 442 public FragmentTransaction hide(Fragment fragment) { 443 Op op = new Op(); 444 op.cmd = OP_HIDE; 445 op.fragment = fragment; 446 addOp(op); 447 448 return this; 449 } 450 451 public FragmentTransaction show(Fragment fragment) { 452 Op op = new Op(); 453 op.cmd = OP_SHOW; 454 op.fragment = fragment; 455 addOp(op); 456 457 return this; 458 } 459 460 public FragmentTransaction detach(Fragment fragment) { 461 Op op = new Op(); 462 op.cmd = OP_DETACH; 463 op.fragment = fragment; 464 addOp(op); 465 466 return this; 467 } 468 469 public FragmentTransaction attach(Fragment fragment) { 470 Op op = new Op(); 471 op.cmd = OP_ATTACH; 472 op.fragment = fragment; 473 addOp(op); 474 475 return this; 476 } 477 478 public FragmentTransaction setCustomAnimations(int enter, int exit) { 479 return setCustomAnimations(enter, exit, 0, 0); 480 } 481 482 public FragmentTransaction setCustomAnimations(int enter, int exit, 483 int popEnter, int popExit) { 484 mEnterAnim = enter; 485 mExitAnim = exit; 486 mPopEnterAnim = popEnter; 487 mPopExitAnim = popExit; 488 return this; 489 } 490 491 public FragmentTransaction setTransition(int transition) { 492 mTransition = transition; 493 return this; 494 } 495 496 public FragmentTransaction setTransitionStyle(int styleRes) { 497 mTransitionStyle = styleRes; 498 return this; 499 } 500 501 public FragmentTransaction addToBackStack(String name) { 502 if (!mAllowAddToBackStack) { 503 throw new IllegalStateException( 504 "This FragmentTransaction is not allowed to be added to the back stack."); 505 } 506 mAddToBackStack = true; 507 mName = name; 508 return this; 509 } 510 511 public boolean isAddToBackStackAllowed() { 512 return mAllowAddToBackStack; 513 } 514 515 public FragmentTransaction disallowAddToBackStack() { 516 if (mAddToBackStack) { 517 throw new IllegalStateException( 518 "This transaction is already being added to the back stack"); 519 } 520 mAllowAddToBackStack = false; 521 return this; 522 } 523 524 public FragmentTransaction setBreadCrumbTitle(int res) { 525 mBreadCrumbTitleRes = res; 526 mBreadCrumbTitleText = null; 527 return this; 528 } 529 530 public FragmentTransaction setBreadCrumbTitle(CharSequence text) { 531 mBreadCrumbTitleRes = 0; 532 mBreadCrumbTitleText = text; 533 return this; 534 } 535 536 public FragmentTransaction setBreadCrumbShortTitle(int res) { 537 mBreadCrumbShortTitleRes = res; 538 mBreadCrumbShortTitleText = null; 539 return this; 540 } 541 542 public FragmentTransaction setBreadCrumbShortTitle(CharSequence text) { 543 mBreadCrumbShortTitleRes = 0; 544 mBreadCrumbShortTitleText = text; 545 return this; 546 } 547 548 void bumpBackStackNesting(int amt) { 549 if (!mAddToBackStack) { 550 return; 551 } 552 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting in " + this 553 + " by " + amt); 554 Op op = mHead; 555 while (op != null) { 556 if (op.fragment != null) { 557 op.fragment.mBackStackNesting += amt; 558 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " 559 + op.fragment + " to " + op.fragment.mBackStackNesting); 560 } 561 if (op.removed != null) { 562 for (int i=op.removed.size()-1; i>=0; i--) { 563 Fragment r = op.removed.get(i); 564 r.mBackStackNesting += amt; 565 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " 566 + r + " to " + r.mBackStackNesting); 567 } 568 } 569 op = op.next; 570 } 571 } 572 573 public int commit() { 574 return commitInternal(false); 575 } 576 577 public int commitAllowingStateLoss() { 578 return commitInternal(true); 579 } 580 581 int commitInternal(boolean allowStateLoss) { 582 if (mCommitted) throw new IllegalStateException("commit already called"); 583 if (FragmentManagerImpl.DEBUG) { 584 Log.v(TAG, "Commit: " + this); 585 LogWriter logw = new LogWriter(TAG); 586 PrintWriter pw = new PrintWriter(logw); 587 dump(" ", null, pw, null); 588 } 589 mCommitted = true; 590 if (mAddToBackStack) { 591 mIndex = mManager.allocBackStackIndex(this); 592 } else { 593 mIndex = -1; 594 } 595 mManager.enqueueAction(this, allowStateLoss); 596 return mIndex; 597 } 598 599 public void run() { 600 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this); 601 602 if (mAddToBackStack) { 603 if (mIndex < 0) { 604 throw new IllegalStateException("addToBackStack() called after commit()"); 605 } 606 } 607 608 bumpBackStackNesting(1); 609 610 Op op = mHead; 611 while (op != null) { 612 switch (op.cmd) { 613 case OP_ADD: { 614 Fragment f = op.fragment; 615 f.mNextAnim = op.enterAnim; 616 mManager.addFragment(f, false); 617 } break; 618 case OP_REPLACE: { 619 Fragment f = op.fragment; 620 if (mManager.mAdded != null) { 621 for (int i=0; i<mManager.mAdded.size(); i++) { 622 Fragment old = mManager.mAdded.get(i); 623 if (FragmentManagerImpl.DEBUG) Log.v(TAG, 624 "OP_REPLACE: adding=" + f + " old=" + old); 625 if (f == null || old.mContainerId == f.mContainerId) { 626 if (old == f) { 627 op.fragment = f = null; 628 } else { 629 if (op.removed == null) { 630 op.removed = new ArrayList<Fragment>(); 631 } 632 op.removed.add(old); 633 old.mNextAnim = op.exitAnim; 634 if (mAddToBackStack) { 635 old.mBackStackNesting += 1; 636 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " 637 + old + " to " + old.mBackStackNesting); 638 } 639 mManager.removeFragment(old, mTransition, mTransitionStyle); 640 } 641 } 642 } 643 } 644 if (f != null) { 645 f.mNextAnim = op.enterAnim; 646 mManager.addFragment(f, false); 647 } 648 } break; 649 case OP_REMOVE: { 650 Fragment f = op.fragment; 651 f.mNextAnim = op.exitAnim; 652 mManager.removeFragment(f, mTransition, mTransitionStyle); 653 } break; 654 case OP_HIDE: { 655 Fragment f = op.fragment; 656 f.mNextAnim = op.exitAnim; 657 mManager.hideFragment(f, mTransition, mTransitionStyle); 658 } break; 659 case OP_SHOW: { 660 Fragment f = op.fragment; 661 f.mNextAnim = op.enterAnim; 662 mManager.showFragment(f, mTransition, mTransitionStyle); 663 } break; 664 case OP_DETACH: { 665 Fragment f = op.fragment; 666 f.mNextAnim = op.exitAnim; 667 mManager.detachFragment(f, mTransition, mTransitionStyle); 668 } break; 669 case OP_ATTACH: { 670 Fragment f = op.fragment; 671 f.mNextAnim = op.enterAnim; 672 mManager.attachFragment(f, mTransition, mTransitionStyle); 673 } break; 674 default: { 675 throw new IllegalArgumentException("Unknown cmd: " + op.cmd); 676 } 677 } 678 679 op = op.next; 680 } 681 682 mManager.moveToState(mManager.mCurState, mTransition, 683 mTransitionStyle, true); 684 685 if (mAddToBackStack) { 686 mManager.addBackStackState(this); 687 } 688 } 689 690 public void popFromBackStack(boolean doStateMove) { 691 if (FragmentManagerImpl.DEBUG) { 692 Log.v(TAG, "popFromBackStack: " + this); 693 LogWriter logw = new LogWriter(TAG); 694 PrintWriter pw = new PrintWriter(logw); 695 dump(" ", null, pw, null); 696 } 697 698 bumpBackStackNesting(-1); 699 700 Op op = mTail; 701 while (op != null) { 702 switch (op.cmd) { 703 case OP_ADD: { 704 Fragment f = op.fragment; 705 f.mNextAnim = op.popExitAnim; 706 mManager.removeFragment(f, 707 FragmentManagerImpl.reverseTransit(mTransition), 708 mTransitionStyle); 709 } break; 710 case OP_REPLACE: { 711 Fragment f = op.fragment; 712 if (f != null) { 713 f.mNextAnim = op.popExitAnim; 714 mManager.removeFragment(f, 715 FragmentManagerImpl.reverseTransit(mTransition), 716 mTransitionStyle); 717 } 718 if (op.removed != null) { 719 for (int i=0; i<op.removed.size(); i++) { 720 Fragment old = op.removed.get(i); 721 old.mNextAnim = op.popEnterAnim; 722 mManager.addFragment(old, false); 723 } 724 } 725 } break; 726 case OP_REMOVE: { 727 Fragment f = op.fragment; 728 f.mNextAnim = op.popEnterAnim; 729 mManager.addFragment(f, false); 730 } break; 731 case OP_HIDE: { 732 Fragment f = op.fragment; 733 f.mNextAnim = op.popEnterAnim; 734 mManager.showFragment(f, 735 FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); 736 } break; 737 case OP_SHOW: { 738 Fragment f = op.fragment; 739 f.mNextAnim = op.popExitAnim; 740 mManager.hideFragment(f, 741 FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); 742 } break; 743 case OP_DETACH: { 744 Fragment f = op.fragment; 745 f.mNextAnim = op.popEnterAnim; 746 mManager.attachFragment(f, 747 FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); 748 } break; 749 case OP_ATTACH: { 750 Fragment f = op.fragment; 751 f.mNextAnim = op.popEnterAnim; 752 mManager.detachFragment(f, 753 FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); 754 } break; 755 default: { 756 throw new IllegalArgumentException("Unknown cmd: " + op.cmd); 757 } 758 } 759 760 op = op.prev; 761 } 762 763 if (doStateMove) { 764 mManager.moveToState(mManager.mCurState, 765 FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true); 766 } 767 768 if (mIndex >= 0) { 769 mManager.freeBackStackIndex(mIndex); 770 mIndex = -1; 771 } 772 } 773 774 public String getName() { 775 return mName; 776 } 777 778 public int getTransition() { 779 return mTransition; 780 } 781 782 public int getTransitionStyle() { 783 return mTransitionStyle; 784 } 785 786 public boolean isEmpty() { 787 return mNumOp == 0; 788 } 789} 790