1 /*
2  * Copyright 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 
17 package com.example.android.tabcompat.lib;
18 
19 import android.content.Context;
20 import android.os.Bundle;
21 import android.support.v4.app.Fragment;
22 import android.support.v4.app.FragmentActivity;
23 import android.support.v4.app.FragmentTransaction;
24 import android.view.View;
25 import android.widget.TabHost;
26 import android.widget.TabHost.TabSpec;
27 
28 import java.util.HashMap;
29 
30 /**
31  * This is a helper class to build tabs on pre-Honeycomb. Call {@link
32  * TabCompatActivity#getTabHelper()} to get the generic instance for
33  * compatibility with other versions.
34  *
35  * It implements a generic mechanism for associating fragments with the tabs in a tab host.  It
36  * relies on a trick:  Normally a tab host has a simple API for supplying a View or Intent that each
37  * tab will show.  This is not sufficient for switching between fragments.  So instead we make the
38  * content part of the tab host 0dp high (it is not shown) and this supplies its own placeholder view to
39  * show as the tab content.  It listens to changes in tabs, then passes the event back to the tab's
40  * callback interface so the activity can take care of switching to the correct fragment.
41  */
42 public class TabHelperEclair extends TabHelper implements TabHost.OnTabChangeListener {
43 
44     private final HashMap<String, CompatTab> mTabs = new HashMap<String, CompatTab>();
45     private TabHost mTabHost;
46     CompatTabListener mCallback;
47     CompatTab mLastTab;
48 
TabHelperEclair(FragmentActivity activity)49     protected TabHelperEclair(FragmentActivity activity) {
50         super(activity);
51         mActivity = activity;
52     }
53 
54     @Override
setUp()55     protected void setUp() {
56         if (mTabHost == null) {
57             mTabHost = (TabHost) mActivity.findViewById(android.R.id.tabhost);
58             mTabHost.setup();
59             mTabHost.setOnTabChangedListener(this);
60         }
61     }
62 
63     @Override
addTab(CompatTab tab)64     public void addTab(CompatTab tab) {
65         String tag = tab.getTag();
66         TabSpec spec;
67 
68         if (tab.getIcon() != null) {
69             spec = mTabHost.newTabSpec(tag).setIndicator(tab.getText(), tab.getIcon());
70         } else {
71             spec = mTabHost.newTabSpec(tag).setIndicator(tab.getText());
72         }
73 
74         spec.setContent(new DummyTabFactory(mActivity));
75 
76         // Check to see if we already have a fragment for this tab, probably
77         // from a previously saved state.  If so, deactivate it, because our
78         // initial state is that a tab isn't shown.
79 
80         Fragment fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);
81         tab.setFragment(fragment);
82 
83         if (fragment != null && !fragment.isDetached()) {
84             FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
85             ft.detach(fragment);
86             ft.commit();
87         }
88 
89         mTabs.put(tag, tab);
90         mTabHost.addTab(spec);
91     }
92 
93     /**
94      * Converts the basic "tab changed" event for TabWidget into the three possible events for
95      * CompatTabListener: selected, unselected, reselected.
96      */
97     @Override
onTabChanged(String tabId)98     public void onTabChanged(String tabId) {
99         CompatTab newTab = mTabs.get(tabId);
100         FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
101 
102         if (mLastTab != newTab) {
103             if (mLastTab != null) {
104                 if (mLastTab.getFragment() != null) {
105                     // Pass the unselected event back to the tab's CompatTabListener
106                     mLastTab.getCallback().onTabUnselected(mLastTab, ft);
107                 }
108             }
109             if (newTab != null) {
110                 // Pass the selected event back to the tab's CompatTabListener
111                 newTab.getCallback().onTabSelected(newTab, ft);
112             }
113 
114             mLastTab = newTab;
115         } else {
116             // Pass the re-selected event back to the tab's CompatTabListener
117             newTab.getCallback().onTabReselected(newTab, ft);
118         }
119 
120         ft.commit();
121         mActivity.getSupportFragmentManager().executePendingTransactions();
122     }
123 
124     @Override
onSaveInstanceState(Bundle outState)125     protected void onSaveInstanceState(Bundle outState) {
126         // Save and restore the selected tab for rotations/restarts.
127         outState.putString("tab", mTabHost.getCurrentTabTag());
128     }
129 
130     @Override
onRestoreInstanceState(Bundle savedInstanceState)131     protected void onRestoreInstanceState(Bundle savedInstanceState) {
132         if (savedInstanceState != null) {
133             mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
134         }
135     }
136 
137     /**
138      * Backwards-compatibility mumbo jumbo
139      */
140     static class DummyTabFactory implements TabHost.TabContentFactory {
141 
142         private final Context mContext;
143 
DummyTabFactory(Context context)144         public DummyTabFactory(Context context) {
145             mContext = context;
146         }
147 
148         @Override
createTabContent(String tag)149         public View createTabContent(String tag) {
150             View v = new View(mContext);
151             v.setMinimumWidth(0);
152             v.setMinimumHeight(0);
153             return v;
154         }
155     }
156 }
157