1 /*
2  * Copyright (C) 2012 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 package com.example.android.apis.app;
17 
18 import java.util.ArrayList;
19 
20 import com.example.android.apis.R;
21 
22 import android.app.Fragment;
23 import android.app.FragmentManager;
24 import android.app.FragmentTransaction;
25 import android.content.Context;
26 import android.os.Bundle;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.widget.TabHost;
31 
32 /**
33  * Sample fragment that contains tabs of other fragments.
34  */
35 public class FragmentTabsFragment extends Fragment {
36     TabManager mTabManager;
37 
38     @Override
onCreate(Bundle savedInstanceState)39     public void onCreate(Bundle savedInstanceState) {
40         super.onCreate(savedInstanceState);
41         mTabManager = new TabManager(getActivity(), getChildFragmentManager(),
42                 R.id.realtabcontent);
43     }
44 
45     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)46     public View onCreateView(LayoutInflater inflater, ViewGroup container,
47             Bundle savedInstanceState) {
48         View v = inflater.inflate(R.layout.fragment_tabs_fragment, container, false);
49         TabHost host = mTabManager.handleCreateView(v);
50 
51         mTabManager.addTab(host.newTabSpec("result").setIndicator("Result"),
52                 FragmentReceiveResult.ReceiveResultFragment.class, null);
53         mTabManager.addTab(host.newTabSpec("contacts").setIndicator("Contacts"),
54                 LoaderCursor.CursorLoaderListFragment.class, null);
55         mTabManager.addTab(host.newTabSpec("apps").setIndicator("Apps"),
56                 LoaderCustom.AppListFragment.class, null);
57         mTabManager.addTab(host.newTabSpec("throttle").setIndicator("Throttle"),
58                 LoaderThrottle.ThrottledLoaderListFragment.class, null);
59 
60         return v;
61     }
62 
63     @Override
onViewStateRestored(Bundle savedInstanceState)64     public void onViewStateRestored(Bundle savedInstanceState) {
65         super.onViewStateRestored(savedInstanceState);
66         mTabManager.handleViewStateRestored(savedInstanceState);
67     }
68 
69     @Override
onDestroyView()70     public void onDestroyView() {
71         super.onDestroyView();
72         mTabManager.handleDestroyView();
73     }
74 
75     @Override
onSaveInstanceState(Bundle outState)76     public void onSaveInstanceState(Bundle outState) {
77         super.onSaveInstanceState(outState);
78         mTabManager.handleSaveInstanceState(outState);
79     }
80 
81     /**
82      * This is a helper class that implements a generic mechanism for
83      * associating fragments with the tabs in a tab host.  DO NOT USE THIS.
84      * If you want tabs in a fragment, use the support v13 library's
85      * FragmentTabHost class, which takes care of all of this for you (in
86      * a simpler way even).
87      */
88     public static class TabManager implements TabHost.OnTabChangeListener {
89         private final Context mContext;
90         private final FragmentManager mManager;
91         private final int mContainerId;
92         private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
93         private TabHost mTabHost;
94         private TabInfo mLastTab;
95         private boolean mInitialized;
96         private String mCurrentTabTag;
97 
98         static final class TabInfo {
99             private final String tag;
100             private final Class<?> clss;
101             private final Bundle args;
102             private Fragment fragment;
103 
TabInfo(String _tag, Class<?> _class, Bundle _args)104             TabInfo(String _tag, Class<?> _class, Bundle _args) {
105                 tag = _tag;
106                 clss = _class;
107                 args = _args;
108             }
109         }
110 
111         static class DummyTabFactory implements TabHost.TabContentFactory {
112             private final Context mContext;
113 
DummyTabFactory(Context context)114             public DummyTabFactory(Context context) {
115                 mContext = context;
116             }
117 
118             @Override
createTabContent(String tag)119             public View createTabContent(String tag) {
120                 View v = new View(mContext);
121                 v.setMinimumWidth(0);
122                 v.setMinimumHeight(0);
123                 return v;
124             }
125         }
126 
TabManager(Context context, FragmentManager manager, int containerId)127         public TabManager(Context context, FragmentManager manager, int containerId) {
128             mContext = context;
129             mManager = manager;
130             mContainerId = containerId;
131         }
132 
handleCreateView(View root)133         public TabHost handleCreateView(View root) {
134             if (mTabHost != null) {
135                 throw new IllegalStateException("TabHost already set");
136             }
137             mTabHost = (TabHost)root.findViewById(android.R.id.tabhost);
138             mTabHost.setup();
139             mTabHost.setOnTabChangedListener(this);
140             return mTabHost;
141         }
142 
addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args)143         public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
144             tabSpec.setContent(new DummyTabFactory(mContext));
145             String tag = tabSpec.getTag();
146             TabInfo info = new TabInfo(tag, clss, args);
147             mTabs.add(info);
148             mTabHost.addTab(tabSpec);
149         }
150 
handleViewStateRestored(Bundle savedInstanceState)151         public void handleViewStateRestored(Bundle savedInstanceState) {
152             if (savedInstanceState != null) {
153                 mCurrentTabTag = savedInstanceState.getString("tab");
154             }
155             mTabHost.setCurrentTabByTag(mCurrentTabTag);
156 
157             String currentTab = mTabHost.getCurrentTabTag();
158 
159             // Go through all tabs and make sure their fragments match
160             // the correct state.
161             FragmentTransaction ft = null;
162             for (int i=0; i<mTabs.size(); i++) {
163                 TabInfo tab = mTabs.get(i);
164                 tab.fragment = mManager.findFragmentByTag(tab.tag);
165                 if (tab.fragment != null && !tab.fragment.isDetached()) {
166                     if (tab.tag.equals(currentTab)) {
167                         // The fragment for this tab is already there and
168                         // active, and it is what we really want to have
169                         // as the current tab.  Nothing to do.
170                         mLastTab = tab;
171                     } else {
172                         // This fragment was restored in the active state,
173                         // but is not the current tab.  Deactivate it.
174                         if (ft == null) {
175                             ft = mManager.beginTransaction();
176                         }
177                         ft.detach(tab.fragment);
178                     }
179                 }
180             }
181 
182             // We are now ready to go.  Make sure we are switched to the
183             // correct tab.
184             mInitialized = true;
185             ft = doTabChanged(currentTab, ft);
186             if (ft != null) {
187                 ft.commit();
188                 mManager.executePendingTransactions();
189             }
190         }
191 
handleDestroyView()192         public void handleDestroyView() {
193             mCurrentTabTag = mTabHost.getCurrentTabTag();
194             mTabHost = null;
195             mTabs.clear();
196             mInitialized = false;
197         }
198 
handleSaveInstanceState(Bundle outState)199         public void handleSaveInstanceState(Bundle outState) {
200             outState.putString("tab", mTabHost != null
201                     ? mTabHost.getCurrentTabTag() : mCurrentTabTag);
202         }
203 
204         @Override
onTabChanged(String tabId)205         public void onTabChanged(String tabId) {
206             if (!mInitialized) {
207                 return;
208             }
209             FragmentTransaction ft = doTabChanged(tabId, null);
210             if (ft != null) {
211                 ft.commit();
212             }
213         }
214 
doTabChanged(String tabId, FragmentTransaction ft)215         private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
216             TabInfo newTab = null;
217             for (int i=0; i<mTabs.size(); i++) {
218                 TabInfo tab = mTabs.get(i);
219                 if (tab.tag.equals(tabId)) {
220                     newTab = tab;
221                 }
222             }
223             if (newTab == null) {
224                 throw new IllegalStateException("No tab known for tag " + tabId);
225             }
226             if (mLastTab != newTab) {
227                 if (ft == null) {
228                     ft = mManager.beginTransaction();
229                 }
230                 if (mLastTab != null) {
231                     if (mLastTab.fragment != null) {
232                         ft.detach(mLastTab.fragment);
233                     }
234                 }
235                 if (newTab != null) {
236                     if (newTab.fragment == null) {
237                         newTab.fragment = Fragment.instantiate(mContext,
238                                 newTab.clss.getName(), newTab.args);
239                         ft.add(mContainerId, newTab.fragment, newTab.tag);
240                     } else {
241                         ft.attach(newTab.fragment);
242                     }
243                 }
244 
245                 mLastTab = newTab;
246             }
247             return ft;
248         }
249     }
250 }
251 //END_INCLUDE(complete)
252