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