FragmentTabHost.java revision 74c671b3b67000bf16b4865a8d361344310dccbe
127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich/*
227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * Copyright (C) 2012 The Android Open Source Project
327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *
427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * Licensed under the Apache License, Version 2.0 (the "License");
524ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * you may not use this file except in compliance with the License.
624ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * You may obtain a copy of the License at
724ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes *
827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *      http://www.apache.org/licenses/LICENSE-2.0
924ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes *
1027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * Unless required by applicable law or agreed to in writing, software
1124ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1224ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * See the License for the specific language governing permissions and
1424ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes * limitations under the License.
1527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich */
1627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
1727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichpackage android.support.v4.app;
1827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
1927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichimport java.util.ArrayList;
2024ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes
2124ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughesimport android.content.Context;
2227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichimport android.content.res.TypedArray;
2327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichimport android.os.Bundle;
2427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichimport android.os.Parcel;
2527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichimport android.os.Parcelable;
2627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichimport android.util.AttributeSet;
27be509c9c7de5929d014dfe6d45e71cc8454ede0fJack Palevichimport android.view.View;
2827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevichimport android.view.ViewGroup;
29be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevichimport android.widget.FrameLayout;
30be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevichimport android.widget.LinearLayout;
31be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevichimport android.widget.TabHost;
32be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevichimport android.widget.TabWidget;
33be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich
34be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich/**
35be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich * Special TabHost that allows the use of {@link Fragment} objects for
3627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * its tab content.  When placing this in a view hierarchy, after inflating
3727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * the hierarchy you must call {@link #setup(Context, FragmentManager, int)}
3827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * to complete the initialization of the tab host.
3927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *
4027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * <p>Here is a simple example of using a FragmentTabHost in an Activity:
4127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *
4227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java
4327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *      complete}
4427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *
4527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * <p>This can also be used inside of a fragment through fragment nesting:
4627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *
4727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsFragmentSupport.java
4827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich *      complete}
4927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich */
5024ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughespublic class FragmentTabHost extends TabHost
5127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        implements TabHost.OnTabChangeListener {
5227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
5327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private FrameLayout mRealTabContent;
5427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private Context mContext;
5527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private FragmentManager mFragmentManager;
5627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private int mContainerId;
5727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private TabHost.OnTabChangeListener mOnTabChangeListener;
5827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private TabInfo mLastTab;
5927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private boolean mAttached;
6027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
6127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    static final class TabInfo {
6227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        private final String tag;
6327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        private final Class<?> clss;
6427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        private final Bundle args;
6527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        private Fragment fragment;
6627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
6727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        TabInfo(String _tag, Class<?> _class, Bundle _args) {
6827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            tag = _tag;
6927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            clss = _class;
7027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            args = _args;
7127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
7227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
7317045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer
7427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    static class DummyTabFactory implements TabHost.TabContentFactory {
7527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        private final Context mContext;
7627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
7727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        public DummyTabFactory(Context context) {
7827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            mContext = context;
7927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
8027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
8127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        @Override
8227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        public View createTabContent(String tag) {
8327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            View v = new View(mContext);
8427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            v.setMinimumWidth(0);
8527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            v.setMinimumHeight(0);
8627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            return v;
8727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
8827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
8927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
9024ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes    static class SavedState extends BaseSavedState {
9127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        String curTab;
9227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
9317045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        SavedState(Parcelable superState) {
9427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            super(superState);
9524ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes        }
9617045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer
9727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        private SavedState(Parcel in) {
9827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            super(in);
9927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            curTab = in.readString();
10027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
10127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
10227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        @Override
10327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        public void writeToParcel(Parcel out, int flags) {
10427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            super.writeToParcel(out, flags);
10527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            out.writeString(curTab);
10627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
107be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich
108be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich        @Override
109be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich        public String toString() {
110be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich            return "FragmentTabHost.SavedState{"
111be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich                    + Integer.toHexString(System.identityHashCode(this))
112be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich                    + " curTab=" + curTab + "}";
113be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich        }
114be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich
11524ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes        public static final Parcelable.Creator<SavedState> CREATOR
11624ce5fb2cc09d0a14406e7b935f8648c5720d27eElliott Hughes                = new Parcelable.Creator<SavedState>() {
117be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich            public SavedState createFromParcel(Parcel in) {
118be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich                return new SavedState(in);
119be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich            }
120be6eac828f5af8b608c3fa6749330f1dcd6b6206Jack Palevich
12127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            public SavedState[] newArray(int size) {
12227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                return new SavedState[size];
12327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            }
12427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        };
12527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
12627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
12727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    public FragmentTabHost(Context context) {
12827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        // Note that we call through to the version that takes an AttributeSet,
12927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        // because the simple Context construct can result in a broken object!
13027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        super(context, null);
13127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        initFragmentTabHost(context, null);
13227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
13327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
13427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    public FragmentTabHost(Context context, AttributeSet attrs) {
13527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        super(context, attrs);
1362545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        initFragmentTabHost(context, attrs);
1372545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    }
1382545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer
13927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private void initFragmentTabHost(Context context, AttributeSet attrs) {
14017045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        TypedArray a = context.obtainStyledAttributes(attrs,
14127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                new int[] { android.R.attr.inflatedId }, 0, 0);
14227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        mContainerId = a.getResourceId(0, 0);
14327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        a.recycle();
14427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
14517045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        super.setOnTabChangedListener(this);
146c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich
1472545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        // If owner hasn't made its own view hierarchy, then as a convenience
1482545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        // we will construct a standard one here.
1492545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        if (findViewById(android.R.id.tabs) == null) {
150c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich            LinearLayout ll = new LinearLayout(context);
151c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich            ll.setOrientation(LinearLayout.VERTICAL);
15227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            addView(ll, new FrameLayout.LayoutParams(
15337c9b49ab5eb5a676370fd7081db0967c38e97a6Thomas Tafertshofer                    ViewGroup.LayoutParams.FILL_PARENT,
15417045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                    ViewGroup.LayoutParams.FILL_PARENT));
15517045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer
15617045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer            TabWidget tw = new TabWidget(context);
15727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            tw.setId(android.R.id.tabs);
15827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            tw.setOrientation(TabWidget.HORIZONTAL);
15927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            ll.addView(tw, new LinearLayout.LayoutParams(
16027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                    ViewGroup.LayoutParams.FILL_PARENT,
16127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                    ViewGroup.LayoutParams.WRAP_CONTENT, 0));
16227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
163c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich            FrameLayout fl = new FrameLayout(context);
164c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich            fl.setId(android.R.id.tabcontent);
16527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            ll.addView(fl, new LinearLayout.LayoutParams(0, 0, 0));
16627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
16727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            mRealTabContent = fl = new FrameLayout(context);
1682545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            mRealTabContent.setId(mContainerId);
1692545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            ll.addView(fl, new LinearLayout.LayoutParams(
1702545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer                    LinearLayout.LayoutParams.FILL_PARENT, 0, 1));
17127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
17227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
17327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
17427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    /**
17527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich     * @deprecated Don't call the original TabHost setup, you must instead
17627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich     * call {@link #setup(Context, FragmentManager)} or
1772545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer     * {@link #setup(Context, FragmentManager, int)}.
1782545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer     */
1792545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    @Override @Deprecated
18027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    public void setup() {
18117045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        throw new IllegalStateException(
18227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                "Must call setup() that takes a Context and FragmentManager");
18327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
18427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
18517045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer    public void setup(Context context, FragmentManager manager) {
186c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich        super.setup();
1872545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        mContext = context;
1882545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        mFragmentManager = manager;
1892545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        ensureContent();
190c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich    }
191c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich
19217045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer    public void setup(Context context, FragmentManager manager, int containerId) {
19317045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        super.setup();
19417045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        mContext = context;
19517045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        mFragmentManager = manager;
19627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        mContainerId = containerId;
19727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        ensureContent();
19827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        mRealTabContent.setId(containerId);
19927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
20027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        // We must have an ID to be able to save/restore our state.  If
20127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        // the owner hasn't set one at this point, we will set it ourself.
202c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich        if (getId() == View.NO_ID) {
203c620a52b69a5f29563e06497e30877809f5d67a5Jack Palevich            setId(android.R.id.tabhost);
20427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
20527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
20627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
2072545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    private void ensureContent() {
2082545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        if (mRealTabContent == null) {
2092545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            mRealTabContent = (FrameLayout)findViewById(mContainerId);
21027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            if (mRealTabContent == null) {
21127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                throw new IllegalStateException(
21227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                        "No tab content FrameLayout found for id " + mContainerId);
21327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            }
21427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
21527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
2162545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer
2172545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    @Override
2182545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    public void setOnTabChangedListener(OnTabChangeListener l) {
21927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        mOnTabChangeListener = l;
22027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
22127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
22227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
22327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        tabSpec.setContent(new DummyTabFactory(mContext));
2242545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        String tag = tabSpec.getTag();
2252545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer
2262545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        TabInfo info = new TabInfo(tag, clss, args);
22727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
22827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        if (mAttached) {
22927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            // If we are already attached to the window, then check to make
2302545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            // sure this tab's fragment is inactive if it exists.  This shouldn't
2312545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            // normally happen.
2322545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            info.fragment = mFragmentManager.findFragmentByTag(tag);
23327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            if (info.fragment != null && !info.fragment.isDetached()) {
23427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                FragmentTransaction ft = mFragmentManager.beginTransaction();
23527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                ft.detach(info.fragment);
23627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                ft.commit();
23727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            }
23827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
23927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
24027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        mTabs.add(info);
24127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        addTab(tabSpec);
24227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
24327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
24427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    @Override
24527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    protected void onAttachedToWindow() {
24627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        super.onAttachedToWindow();
24727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
24827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        String currentTab = getCurrentTabTag();
24927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
2502545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        // Go through all tabs and make sure their fragments match
2512545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        // the correct state.
2522545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        FragmentTransaction ft = null;
25327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        for (int i=0; i<mTabs.size(); i++) {
25427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            TabInfo tab = mTabs.get(i);
25527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);
25627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            if (tab.fragment != null && !tab.fragment.isDetached()) {
25727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                if (tab.tag.equals(currentTab)) {
25827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                    // The fragment for this tab is already there and
2592545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer                    // active, and it is what we really want to have
2602545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer                    // as the current tab.  Nothing to do.
2612545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer                    mLastTab = tab;
26227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                } else {
26317045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                    // This fragment was restored in the active state,
26427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                    // but is not the current tab.  Deactivate it.
26527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                    if (ft == null) {
26627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                        ft = mFragmentManager.beginTransaction();
26717045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                    }
26817045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                    ft.detach(tab.fragment);
26917045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                }
27017045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer            }
27117045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer        }
27227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
27327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        // We are now ready to go.  Make sure we are switched to the
27427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        // correct tab.
27527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        mAttached = true;
27627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        ft = doTabChanged(currentTab, ft);
27727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        if (ft != null) {
27827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            ft.commit();
2792545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            mFragmentManager.executePendingTransactions();
2802545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        }
2812545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    }
28227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
28327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    @Override
28427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    protected void onDetachedFromWindow() {
28527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        super.onDetachedFromWindow();
28627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        mAttached = false;
28727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
2882545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer
2892545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    @Override
2902545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    protected Parcelable onSaveInstanceState() {
29127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        Parcelable superState = super.onSaveInstanceState();
29227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        SavedState ss = new SavedState(superState);
29327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        ss.curTab = getCurrentTabTag();
29427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        return ss;
29527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
2962545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer
2972545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    @Override
2982545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    protected void onRestoreInstanceState(Parcelable state) {
29927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        SavedState ss = (SavedState)state;
30027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        super.onRestoreInstanceState(ss.getSuperState());
30127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        setCurrentTabByTag(ss.curTab);
3022545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    }
3032545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer
3042545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer    @Override
30527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    public void onTabChanged(String tabId) {
30627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        if (mAttached) {
30727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            FragmentTransaction ft = doTabChanged(tabId, null);
30827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            if (ft != null) {
30927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                ft.commit();
31027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            }
31127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
31227f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        if (mOnTabChangeListener != null) {
31327f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            mOnTabChangeListener.onTabChanged(tabId);
31427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
31527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
31627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
31727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
31827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        TabInfo newTab = null;
31927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        for (int i=0; i<mTabs.size(); i++) {
32027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            TabInfo tab = mTabs.get(i);
32127f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            if (tab.tag.equals(tabId)) {
3222545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer                newTab = tab;
3232545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            }
3242545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer        }
32527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        if (newTab == null) {
32627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            throw new IllegalStateException("No tab known for tag " + tabId);
32727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
32827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        if (mLastTab != newTab) {
32927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            if (ft == null) {
33027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                ft = mFragmentManager.beginTransaction();
3312545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            }
3322545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer            if (mLastTab != null) {
3332545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer                if (mLastTab.fragment != null) {
33427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                    ft.detach(mLastTab.fragment);
33517045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                }
33627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            }
33727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            if (newTab != null) {
33827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                if (newTab.fragment == null) {
33917045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                    newTab.fragment = Fragment.instantiate(mContext,
34017045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                            newTab.clss.getName(), newTab.args);
34117045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                    ft.add(mContainerId, newTab.fragment, newTab.tag);
34217045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                } else {
34317045a16575ece34cfadb63da4791f115625df78Thomas Tafertshofer                    ft.attach(newTab.fragment);
34427f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich                }
34527f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            }
34627f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich
34727f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich            mLastTab = newTab;
34827f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        }
34927f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich        return ft;
35027f8002e591b5c579f75b2580183b5d1c4219cd4Jack Palevich    }
3512545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer}
3522545b32ced69100fe70685b95315c6adf411083bThomas Tafertshofer