10adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn/* 20adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * Copyright (C) 2012 The Android Open Source Project 30adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * 40adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 50adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * you may not use this file except in compliance with the License. 60adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * You may obtain a copy of the License at 70adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * 80adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 90adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * 100adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 110adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 120adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * See the License for the specific language governing permissions and 140adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * limitations under the License. 150adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn */ 160adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 170adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornpackage android.support.v4.app; 180adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackbornimport java.util.ArrayList; 200adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 210adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.content.Context; 220adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.content.res.TypedArray; 230adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.os.Bundle; 2474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackbornimport android.os.Parcel; 2574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackbornimport android.os.Parcelable; 260adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.util.AttributeSet; 270adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.view.View; 280adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.view.ViewGroup; 290adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.widget.FrameLayout; 300adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.widget.LinearLayout; 310adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.widget.TabHost; 320adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornimport android.widget.TabWidget; 330adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 340adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn/** 350adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * Special TabHost that allows the use of {@link Fragment} objects for 360adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * its tab content. When placing this in a view hierarchy, after inflating 370adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * the hierarchy you must call {@link #setup(Context, FragmentManager, int)} 380adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * to complete the initialization of the tab host. 3974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * 4074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * <p>Here is a simple example of using a FragmentTabHost in an Activity: 4174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * 4274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java 4374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * complete} 4474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * 4574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * <p>This can also be used inside of a fragment through fragment nesting: 4674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * 4774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsFragmentSupport.java 4874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn * complete} 490adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn */ 500adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackbornpublic class FragmentTabHost extends TabHost 510adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn implements TabHost.OnTabChangeListener { 5274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); 530adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private FrameLayout mRealTabContent; 540adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private Context mContext; 550adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private FragmentManager mFragmentManager; 560adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private int mContainerId; 570adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private TabHost.OnTabChangeListener mOnTabChangeListener; 580adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private TabInfo mLastTab; 5974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn private boolean mAttached; 600adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 610adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn static final class TabInfo { 620adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private final String tag; 630adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private final Class<?> clss; 640adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private final Bundle args; 650adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private Fragment fragment; 660adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 670adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn TabInfo(String _tag, Class<?> _class, Bundle _args) { 680adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn tag = _tag; 690adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn clss = _class; 700adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn args = _args; 710adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 720adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 730adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 740adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn static class DummyTabFactory implements TabHost.TabContentFactory { 750adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private final Context mContext; 760adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 770adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public DummyTabFactory(Context context) { 780adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mContext = context; 790adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 800adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 810adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn @Override 820adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public View createTabContent(String tag) { 830adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn View v = new View(mContext); 840adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn v.setMinimumWidth(0); 850adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn v.setMinimumHeight(0); 860adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn return v; 870adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 880adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 890adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 9074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn static class SavedState extends BaseSavedState { 9174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn String curTab; 9274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 9374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn SavedState(Parcelable superState) { 9474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn super(superState); 9574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 9674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 9774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn private SavedState(Parcel in) { 9874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn super(in); 9974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn curTab = in.readString(); 10074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 10174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 10274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn @Override 10374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn public void writeToParcel(Parcel out, int flags) { 10474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn super.writeToParcel(out, flags); 10574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn out.writeString(curTab); 10674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 10774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 10874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn @Override 10974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn public String toString() { 11074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn return "FragmentTabHost.SavedState{" 11174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn + Integer.toHexString(System.identityHashCode(this)) 11274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn + " curTab=" + curTab + "}"; 11374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 11474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 11574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn public static final Parcelable.Creator<SavedState> CREATOR 11674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn = new Parcelable.Creator<SavedState>() { 11774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn public SavedState createFromParcel(Parcel in) { 11874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn return new SavedState(in); 11974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 12074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 12174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn public SavedState[] newArray(int size) { 12274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn return new SavedState[size]; 12374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 12474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn }; 12574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 12674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 1270adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public FragmentTabHost(Context context) { 1280adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn // Note that we call through to the version that takes an AttributeSet, 1290adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn // because the simple Context construct can result in a broken object! 1300adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn super(context, null); 1310adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn initFragmentTabHost(context, null); 1320adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 1330adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1340adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public FragmentTabHost(Context context, AttributeSet attrs) { 1350adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn super(context, attrs); 1360adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn initFragmentTabHost(context, attrs); 1370adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 1380adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1390adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private void initFragmentTabHost(Context context, AttributeSet attrs) { 1400adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn TypedArray a = context.obtainStyledAttributes(attrs, 1410adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn new int[] { android.R.attr.inflatedId }, 0, 0); 1420adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mContainerId = a.getResourceId(0, 0); 1430adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn a.recycle(); 1440adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1450adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn super.setOnTabChangedListener(this); 1465424d16916b2fb65ff009051e4f9d02584d07b53Piet Delport } 1470adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1485424d16916b2fb65ff009051e4f9d02584d07b53Piet Delport private void ensureHierarchy(Context context) { 1490adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn // If owner hasn't made its own view hierarchy, then as a convenience 1500adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn // we will construct a standard one here. 1510adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (findViewById(android.R.id.tabs) == null) { 1520adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn LinearLayout ll = new LinearLayout(context); 1530adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ll.setOrientation(LinearLayout.VERTICAL); 1540adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn addView(ll, new FrameLayout.LayoutParams( 1550adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ViewGroup.LayoutParams.FILL_PARENT, 1560adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ViewGroup.LayoutParams.FILL_PARENT)); 1570adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1580adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn TabWidget tw = new TabWidget(context); 1590adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn tw.setId(android.R.id.tabs); 1600adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn tw.setOrientation(TabWidget.HORIZONTAL); 1610adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ll.addView(tw, new LinearLayout.LayoutParams( 1620adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ViewGroup.LayoutParams.FILL_PARENT, 1630adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ViewGroup.LayoutParams.WRAP_CONTENT, 0)); 1640adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1650adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn FrameLayout fl = new FrameLayout(context); 1660adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn fl.setId(android.R.id.tabcontent); 1670adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ll.addView(fl, new LinearLayout.LayoutParams(0, 0, 0)); 1680adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1690adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mRealTabContent = fl = new FrameLayout(context); 1700adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mRealTabContent.setId(mContainerId); 1710adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ll.addView(fl, new LinearLayout.LayoutParams( 1720adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn LinearLayout.LayoutParams.FILL_PARENT, 0, 1)); 1730adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 1740adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 1750adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1760adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn /** 1770adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * @deprecated Don't call the original TabHost setup, you must instead 1780adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * call {@link #setup(Context, FragmentManager)} or 1790adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn * {@link #setup(Context, FragmentManager, int)}. 1800adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn */ 1810adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn @Override @Deprecated 1820adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public void setup() { 1830adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn throw new IllegalStateException( 1840adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn "Must call setup() that takes a Context and FragmentManager"); 1850adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 1860adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1870adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public void setup(Context context, FragmentManager manager) { 1885424d16916b2fb65ff009051e4f9d02584d07b53Piet Delport ensureHierarchy(context); // Ensure views required by super.setup() 1890adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn super.setup(); 1900adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mContext = context; 1910adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mFragmentManager = manager; 1920adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ensureContent(); 1930adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 1940adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 1950adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public void setup(Context context, FragmentManager manager, int containerId) { 1965424d16916b2fb65ff009051e4f9d02584d07b53Piet Delport ensureHierarchy(context); // Ensure views required by super.setup() 1970adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn super.setup(); 1980adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mContext = context; 1990adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mFragmentManager = manager; 2000adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mContainerId = containerId; 2010adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ensureContent(); 2020adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mRealTabContent.setId(containerId); 20374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 20474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // We must have an ID to be able to save/restore our state. If 20574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // the owner hasn't set one at this point, we will set it ourself. 20674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (getId() == View.NO_ID) { 20774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn setId(android.R.id.tabhost); 20874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 2090adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 2100adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 2110adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn private void ensureContent() { 2120adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (mRealTabContent == null) { 2130adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mRealTabContent = (FrameLayout)findViewById(mContainerId); 2140adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (mRealTabContent == null) { 2150adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn throw new IllegalStateException( 2160adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn "No tab content FrameLayout found for id " + mContainerId); 2170adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 2180adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 2190adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 2200adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 2210adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn @Override 2220adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public void setOnTabChangedListener(OnTabChangeListener l) { 2230adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mOnTabChangeListener = l; 2240adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 2250adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 2260adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) { 2270adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn tabSpec.setContent(new DummyTabFactory(mContext)); 2280adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn String tag = tabSpec.getTag(); 2290adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 2300adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn TabInfo info = new TabInfo(tag, clss, args); 2310adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 23274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (mAttached) { 23374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // If we are already attached to the window, then check to make 23474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // sure this tab's fragment is inactive if it exists. This shouldn't 23574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // normally happen. 23674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn info.fragment = mFragmentManager.findFragmentByTag(tag); 23774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (info.fragment != null && !info.fragment.isDetached()) { 23874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn FragmentTransaction ft = mFragmentManager.beginTransaction(); 23974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft.detach(info.fragment); 24074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft.commit(); 24174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 2420adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 2430adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 24474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn mTabs.add(info); 2450adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn addTab(tabSpec); 2460adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 2470adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 2480adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn @Override 24974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn protected void onAttachedToWindow() { 25074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn super.onAttachedToWindow(); 25174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 25274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn String currentTab = getCurrentTabTag(); 25374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 25474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // Go through all tabs and make sure their fragments match 25574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // the correct state. 25674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn FragmentTransaction ft = null; 25774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn for (int i=0; i<mTabs.size(); i++) { 25874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn TabInfo tab = mTabs.get(i); 25974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn tab.fragment = mFragmentManager.findFragmentByTag(tab.tag); 26074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (tab.fragment != null && !tab.fragment.isDetached()) { 26174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (tab.tag.equals(currentTab)) { 26274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // The fragment for this tab is already there and 26374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // active, and it is what we really want to have 26474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // as the current tab. Nothing to do. 26574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn mLastTab = tab; 26674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } else { 26774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // This fragment was restored in the active state, 26874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // but is not the current tab. Deactivate it. 26974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (ft == null) { 27074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft = mFragmentManager.beginTransaction(); 27174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 27274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft.detach(tab.fragment); 27374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 27474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 27574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 27674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 27774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // We are now ready to go. Make sure we are switched to the 27874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn // correct tab. 27974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn mAttached = true; 28074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft = doTabChanged(currentTab, ft); 28174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (ft != null) { 28274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft.commit(); 28374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn mFragmentManager.executePendingTransactions(); 28474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 28574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 28674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 28774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn @Override 28874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn protected void onDetachedFromWindow() { 28974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn super.onDetachedFromWindow(); 29074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn mAttached = false; 29174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 29274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 29374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn @Override 29474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn protected Parcelable onSaveInstanceState() { 29574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn Parcelable superState = super.onSaveInstanceState(); 29674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn SavedState ss = new SavedState(superState); 29774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ss.curTab = getCurrentTabTag(); 29874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn return ss; 29974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 30074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 30174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn @Override 30274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn protected void onRestoreInstanceState(Parcelable state) { 30374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn SavedState ss = (SavedState)state; 30474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn super.onRestoreInstanceState(ss.getSuperState()); 30574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn setCurrentTabByTag(ss.curTab); 30674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 30774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 30874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn @Override 3090adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn public void onTabChanged(String tabId) { 31074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (mAttached) { 31174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn FragmentTransaction ft = doTabChanged(tabId, null); 31274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (ft != null) { 31374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft.commit(); 31474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 31574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 31674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (mOnTabChangeListener != null) { 31774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn mOnTabChangeListener.onTabChanged(tabId); 31874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 31974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 32074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn 32174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) { 32274c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn TabInfo newTab = null; 32374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn for (int i=0; i<mTabs.size(); i++) { 32474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn TabInfo tab = mTabs.get(i); 32574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (tab.tag.equals(tabId)) { 32674c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn newTab = tab; 32774c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 32874c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 32974c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (newTab == null) { 33074c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn throw new IllegalStateException("No tab known for tag " + tabId); 33174c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 3320adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (mLastTab != newTab) { 33374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn if (ft == null) { 33474c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn ft = mFragmentManager.beginTransaction(); 33574c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn } 3360adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (mLastTab != null) { 3370adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (mLastTab.fragment != null) { 3380adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ft.detach(mLastTab.fragment); 3390adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 3400adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 3410adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (newTab != null) { 3420adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn if (newTab.fragment == null) { 3430adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn newTab.fragment = Fragment.instantiate(mContext, 3440adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn newTab.clss.getName(), newTab.args); 3450adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ft.add(mContainerId, newTab.fragment, newTab.tag); 3460adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } else { 3470adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn ft.attach(newTab.fragment); 3480adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 3490adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 3500adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn 3510adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn mLastTab = newTab; 3520adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 35374c671b3b67000bf16b4865a8d361344310dccbeDianne Hackborn return ft; 3540adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn } 3550adacc1aa313d757ae1c517152cef838e0f35c13Dianne Hackborn} 356