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