• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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 android.widget;
18 
19 import com.android.internal.R;
20 
21 import android.app.LocalActivityManager;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.res.TypedArray;
25 import android.graphics.drawable.Drawable;
26 import android.os.Build;
27 import android.text.TextUtils;
28 import android.util.AttributeSet;
29 import android.view.KeyEvent;
30 import android.view.LayoutInflater;
31 import android.view.SoundEffectConstants;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.view.ViewTreeObserver;
35 import android.view.Window;
36 import java.util.ArrayList;
37 import java.util.List;
38 
39 /**
40  * Container for a tabbed window view. This object holds two children: a set of tab labels that the
41  * user clicks to select a specific tab, and a FrameLayout object that displays the contents of that
42  * page. The individual elements are typically controlled using this container object, rather than
43  * setting values on the child elements themselves.
44  *
45  */
46 public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener {
47 
48     private static final int TABWIDGET_LOCATION_LEFT = 0;
49     private static final int TABWIDGET_LOCATION_TOP = 1;
50     private static final int TABWIDGET_LOCATION_RIGHT = 2;
51     private static final int TABWIDGET_LOCATION_BOTTOM = 3;
52     private TabWidget mTabWidget;
53     private FrameLayout mTabContent;
54     private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
55     /**
56      * This field should be made private, so it is hidden from the SDK.
57      * {@hide}
58      */
59     protected int mCurrentTab = -1;
60     private View mCurrentView = null;
61     /**
62      * This field should be made private, so it is hidden from the SDK.
63      * {@hide}
64      */
65     protected LocalActivityManager mLocalActivityManager = null;
66     private OnTabChangeListener mOnTabChangeListener;
67     private OnKeyListener mTabKeyListener;
68 
69     private int mTabLayoutId;
70 
TabHost(Context context)71     public TabHost(Context context) {
72         super(context);
73         initTabHost();
74     }
75 
TabHost(Context context, AttributeSet attrs)76     public TabHost(Context context, AttributeSet attrs) {
77         this(context, attrs, com.android.internal.R.attr.tabWidgetStyle);
78     }
79 
TabHost(Context context, AttributeSet attrs, int defStyleAttr)80     public TabHost(Context context, AttributeSet attrs, int defStyleAttr) {
81         this(context, attrs, defStyleAttr, 0);
82     }
83 
TabHost(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)84     public TabHost(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
85         super(context, attrs);
86 
87         final TypedArray a = context.obtainStyledAttributes(
88                 attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes);
89 
90         mTabLayoutId = a.getResourceId(R.styleable.TabWidget_tabLayout, 0);
91         a.recycle();
92 
93         if (mTabLayoutId == 0) {
94             // In case the tabWidgetStyle does not inherit from Widget.TabWidget and tabLayout is
95             // not defined.
96             mTabLayoutId = R.layout.tab_indicator_holo;
97         }
98 
99         initTabHost();
100     }
101 
initTabHost()102     private void initTabHost() {
103         setFocusableInTouchMode(true);
104         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
105 
106         mCurrentTab = -1;
107         mCurrentView = null;
108     }
109 
110     /**
111      * Get a new {@link TabSpec} associated with this tab host.
112      * @param tag required tag of tab.
113      */
newTabSpec(String tag)114     public TabSpec newTabSpec(String tag) {
115         return new TabSpec(tag);
116     }
117 
118 
119 
120     /**
121       * <p>Call setup() before adding tabs if loading TabHost using findViewById().
122       * <i><b>However</i></b>: You do not need to call setup() after getTabHost()
123       * in {@link android.app.TabActivity TabActivity}.
124       * Example:</p>
125 <pre>mTabHost = (TabHost)findViewById(R.id.tabhost);
126 mTabHost.setup();
127 mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
128       */
setup()129     public void setup() {
130         mTabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
131         if (mTabWidget == null) {
132             throw new RuntimeException(
133                     "Your TabHost must have a TabWidget whose id attribute is 'android.R.id.tabs'");
134         }
135 
136         // KeyListener to attach to all tabs. Detects non-navigation keys
137         // and relays them to the tab content.
138         mTabKeyListener = new OnKeyListener() {
139             public boolean onKey(View v, int keyCode, KeyEvent event) {
140                 switch (keyCode) {
141                     case KeyEvent.KEYCODE_DPAD_CENTER:
142                     case KeyEvent.KEYCODE_DPAD_LEFT:
143                     case KeyEvent.KEYCODE_DPAD_RIGHT:
144                     case KeyEvent.KEYCODE_DPAD_UP:
145                     case KeyEvent.KEYCODE_DPAD_DOWN:
146                     case KeyEvent.KEYCODE_ENTER:
147                         return false;
148 
149                 }
150                 mTabContent.requestFocus(View.FOCUS_FORWARD);
151                 return mTabContent.dispatchKeyEvent(event);
152             }
153 
154         };
155 
156         mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged() {
157             public void onTabSelectionChanged(int tabIndex, boolean clicked) {
158                 setCurrentTab(tabIndex);
159                 if (clicked) {
160                     mTabContent.requestFocus(View.FOCUS_FORWARD);
161                 }
162             }
163         });
164 
165         mTabContent = (FrameLayout) findViewById(com.android.internal.R.id.tabcontent);
166         if (mTabContent == null) {
167             throw new RuntimeException(
168                     "Your TabHost must have a FrameLayout whose id attribute is "
169                             + "'android.R.id.tabcontent'");
170         }
171     }
172 
173     /** @hide */
174     @Override
sendAccessibilityEventInternal(int eventType)175     public void sendAccessibilityEventInternal(int eventType) {
176         /* avoid super class behavior - TabWidget sends the right events */
177     }
178 
179     /**
180      * If you are using {@link TabSpec#setContent(android.content.Intent)}, this
181      * must be called since the activityGroup is needed to launch the local activity.
182      *
183      * This is done for you if you extend {@link android.app.TabActivity}.
184      * @param activityGroup Used to launch activities for tab content.
185      */
setup(LocalActivityManager activityGroup)186     public void setup(LocalActivityManager activityGroup) {
187         setup();
188         mLocalActivityManager = activityGroup;
189     }
190 
191     @Override
onTouchModeChanged(boolean isInTouchMode)192     public void onTouchModeChanged(boolean isInTouchMode) {
193         // No longer used, but kept to maintain API compatibility.
194     }
195 
196     /**
197      * Add a tab.
198      * @param tabSpec Specifies how to create the indicator and content.
199      */
addTab(TabSpec tabSpec)200     public void addTab(TabSpec tabSpec) {
201 
202         if (tabSpec.mIndicatorStrategy == null) {
203             throw new IllegalArgumentException("you must specify a way to create the tab indicator.");
204         }
205 
206         if (tabSpec.mContentStrategy == null) {
207             throw new IllegalArgumentException("you must specify a way to create the tab content");
208         }
209         View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();
210         tabIndicator.setOnKeyListener(mTabKeyListener);
211 
212         // If this is a custom view, then do not draw the bottom strips for
213         // the tab indicators.
214         if (tabSpec.mIndicatorStrategy instanceof ViewIndicatorStrategy) {
215             mTabWidget.setStripEnabled(false);
216         }
217 
218         mTabWidget.addView(tabIndicator);
219         mTabSpecs.add(tabSpec);
220 
221         if (mCurrentTab == -1) {
222             setCurrentTab(0);
223         }
224     }
225 
226 
227     /**
228      * Removes all tabs from the tab widget associated with this tab host.
229      */
clearAllTabs()230     public void clearAllTabs() {
231         mTabWidget.removeAllViews();
232         initTabHost();
233         mTabContent.removeAllViews();
234         mTabSpecs.clear();
235         requestLayout();
236         invalidate();
237     }
238 
getTabWidget()239     public TabWidget getTabWidget() {
240         return mTabWidget;
241     }
242 
getCurrentTab()243     public int getCurrentTab() {
244         return mCurrentTab;
245     }
246 
getCurrentTabTag()247     public String getCurrentTabTag() {
248         if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
249             return mTabSpecs.get(mCurrentTab).getTag();
250         }
251         return null;
252     }
253 
getCurrentTabView()254     public View getCurrentTabView() {
255         if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
256             return mTabWidget.getChildTabViewAt(mCurrentTab);
257         }
258         return null;
259     }
260 
getCurrentView()261     public View getCurrentView() {
262         return mCurrentView;
263     }
264 
setCurrentTabByTag(String tag)265     public void setCurrentTabByTag(String tag) {
266         int i;
267         for (i = 0; i < mTabSpecs.size(); i++) {
268             if (mTabSpecs.get(i).getTag().equals(tag)) {
269                 setCurrentTab(i);
270                 break;
271             }
272         }
273     }
274 
275     /**
276      * Get the FrameLayout which holds tab content
277      */
getTabContentView()278     public FrameLayout getTabContentView() {
279         return mTabContent;
280     }
281 
282     /**
283      * Get the location of the TabWidget.
284      *
285      * @return The TabWidget location.
286      */
getTabWidgetLocation()287     private int getTabWidgetLocation() {
288         int location = TABWIDGET_LOCATION_TOP;
289 
290         switch (mTabWidget.getOrientation()) {
291             case LinearLayout.VERTICAL:
292                 location = (mTabContent.getLeft() < mTabWidget.getLeft()) ? TABWIDGET_LOCATION_RIGHT
293                         : TABWIDGET_LOCATION_LEFT;
294                 break;
295             case LinearLayout.HORIZONTAL:
296             default:
297                 location = (mTabContent.getTop() < mTabWidget.getTop()) ? TABWIDGET_LOCATION_BOTTOM
298                         : TABWIDGET_LOCATION_TOP;
299                 break;
300         }
301         return location;
302     }
303 
304     @Override
dispatchKeyEvent(KeyEvent event)305     public boolean dispatchKeyEvent(KeyEvent event) {
306         final boolean handled = super.dispatchKeyEvent(event);
307 
308         // unhandled key events change focus to tab indicator for embedded
309         // activities when there is nothing that will take focus from default
310         // focus searching
311         if (!handled
312                 && (event.getAction() == KeyEvent.ACTION_DOWN)
313                 && (mCurrentView != null)
314                 && (mCurrentView.isRootNamespace())
315                 && (mCurrentView.hasFocus())) {
316             int keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_UP;
317             int directionShouldChangeFocus = View.FOCUS_UP;
318             int soundEffect = SoundEffectConstants.NAVIGATION_UP;
319 
320             switch (getTabWidgetLocation()) {
321                 case TABWIDGET_LOCATION_LEFT:
322                     keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_LEFT;
323                     directionShouldChangeFocus = View.FOCUS_LEFT;
324                     soundEffect = SoundEffectConstants.NAVIGATION_LEFT;
325                     break;
326                 case TABWIDGET_LOCATION_RIGHT:
327                     keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_RIGHT;
328                     directionShouldChangeFocus = View.FOCUS_RIGHT;
329                     soundEffect = SoundEffectConstants.NAVIGATION_RIGHT;
330                     break;
331                 case TABWIDGET_LOCATION_BOTTOM:
332                     keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_DOWN;
333                     directionShouldChangeFocus = View.FOCUS_DOWN;
334                     soundEffect = SoundEffectConstants.NAVIGATION_DOWN;
335                     break;
336                 case TABWIDGET_LOCATION_TOP:
337                 default:
338                     keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_UP;
339                     directionShouldChangeFocus = View.FOCUS_UP;
340                     soundEffect = SoundEffectConstants.NAVIGATION_UP;
341                     break;
342             }
343             if (event.getKeyCode() == keyCodeShouldChangeFocus
344                     && mCurrentView.findFocus().focusSearch(directionShouldChangeFocus) == null) {
345                 mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
346                 playSoundEffect(soundEffect);
347                 return true;
348             }
349         }
350         return handled;
351     }
352 
353 
354     @Override
dispatchWindowFocusChanged(boolean hasFocus)355     public void dispatchWindowFocusChanged(boolean hasFocus) {
356         if (mCurrentView != null){
357             mCurrentView.dispatchWindowFocusChanged(hasFocus);
358         }
359     }
360 
361     @Override
getAccessibilityClassName()362     public CharSequence getAccessibilityClassName() {
363         return TabHost.class.getName();
364     }
365 
setCurrentTab(int index)366     public void setCurrentTab(int index) {
367         if (index < 0 || index >= mTabSpecs.size()) {
368             return;
369         }
370 
371         if (index == mCurrentTab) {
372             return;
373         }
374 
375         // notify old tab content
376         if (mCurrentTab != -1) {
377             mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed();
378         }
379 
380         mCurrentTab = index;
381         final TabHost.TabSpec spec = mTabSpecs.get(index);
382 
383         // Call the tab widget's focusCurrentTab(), instead of just
384         // selecting the tab.
385         mTabWidget.focusCurrentTab(mCurrentTab);
386 
387         // tab content
388         mCurrentView = spec.mContentStrategy.getContentView();
389 
390         if (mCurrentView.getParent() == null) {
391             mTabContent
392                     .addView(
393                             mCurrentView,
394                             new ViewGroup.LayoutParams(
395                                     ViewGroup.LayoutParams.MATCH_PARENT,
396                                     ViewGroup.LayoutParams.MATCH_PARENT));
397         }
398 
399         if (!mTabWidget.hasFocus()) {
400             // if the tab widget didn't take focus (likely because we're in touch mode)
401             // give the current tab content view a shot
402             mCurrentView.requestFocus();
403         }
404 
405         //mTabContent.requestFocus(View.FOCUS_FORWARD);
406         invokeOnTabChangeListener();
407     }
408 
409     /**
410      * Register a callback to be invoked when the selected state of any of the items
411      * in this list changes
412      * @param l
413      * The callback that will run
414      */
setOnTabChangedListener(OnTabChangeListener l)415     public void setOnTabChangedListener(OnTabChangeListener l) {
416         mOnTabChangeListener = l;
417     }
418 
invokeOnTabChangeListener()419     private void invokeOnTabChangeListener() {
420         if (mOnTabChangeListener != null) {
421             mOnTabChangeListener.onTabChanged(getCurrentTabTag());
422         }
423     }
424 
425     /**
426      * Interface definition for a callback to be invoked when tab changed
427      */
428     public interface OnTabChangeListener {
onTabChanged(String tabId)429         void onTabChanged(String tabId);
430     }
431 
432 
433     /**
434      * Makes the content of a tab when it is selected. Use this if your tab
435      * content needs to be created on demand, i.e. you are not showing an
436      * existing view or starting an activity.
437      */
438     public interface TabContentFactory {
439         /**
440          * Callback to make the tab contents
441          *
442          * @param tag
443          *            Which tab was selected.
444          * @return The view to display the contents of the selected tab.
445          */
createTabContent(String tag)446         View createTabContent(String tag);
447     }
448 
449 
450     /**
451      * A tab has a tab indicator, content, and a tag that is used to keep
452      * track of it.  This builder helps choose among these options.
453      *
454      * For the tab indicator, your choices are:
455      * 1) set a label
456      * 2) set a label and an icon
457      *
458      * For the tab content, your choices are:
459      * 1) the id of a {@link View}
460      * 2) a {@link TabContentFactory} that creates the {@link View} content.
461      * 3) an {@link Intent} that launches an {@link android.app.Activity}.
462      */
463     public class TabSpec {
464 
465         private String mTag;
466 
467         private IndicatorStrategy mIndicatorStrategy;
468         private ContentStrategy mContentStrategy;
469 
TabSpec(String tag)470         private TabSpec(String tag) {
471             mTag = tag;
472         }
473 
474         /**
475          * Specify a label as the tab indicator.
476          */
setIndicator(CharSequence label)477         public TabSpec setIndicator(CharSequence label) {
478             mIndicatorStrategy = new LabelIndicatorStrategy(label);
479             return this;
480         }
481 
482         /**
483          * Specify a label and icon as the tab indicator.
484          */
setIndicator(CharSequence label, Drawable icon)485         public TabSpec setIndicator(CharSequence label, Drawable icon) {
486             mIndicatorStrategy = new LabelAndIconIndicatorStrategy(label, icon);
487             return this;
488         }
489 
490         /**
491          * Specify a view as the tab indicator.
492          */
setIndicator(View view)493         public TabSpec setIndicator(View view) {
494             mIndicatorStrategy = new ViewIndicatorStrategy(view);
495             return this;
496         }
497 
498         /**
499          * Specify the id of the view that should be used as the content
500          * of the tab.
501          */
setContent(int viewId)502         public TabSpec setContent(int viewId) {
503             mContentStrategy = new ViewIdContentStrategy(viewId);
504             return this;
505         }
506 
507         /**
508          * Specify a {@link android.widget.TabHost.TabContentFactory} to use to
509          * create the content of the tab.
510          */
setContent(TabContentFactory contentFactory)511         public TabSpec setContent(TabContentFactory contentFactory) {
512             mContentStrategy = new FactoryContentStrategy(mTag, contentFactory);
513             return this;
514         }
515 
516         /**
517          * Specify an intent to use to launch an activity as the tab content.
518          */
setContent(Intent intent)519         public TabSpec setContent(Intent intent) {
520             mContentStrategy = new IntentContentStrategy(mTag, intent);
521             return this;
522         }
523 
524 
getTag()525         public String getTag() {
526             return mTag;
527         }
528     }
529 
530     /**
531      * Specifies what you do to create a tab indicator.
532      */
533     private static interface IndicatorStrategy {
534 
535         /**
536          * Return the view for the indicator.
537          */
createIndicatorView()538         View createIndicatorView();
539     }
540 
541     /**
542      * Specifies what you do to manage the tab content.
543      */
544     private static interface ContentStrategy {
545 
546         /**
547          * Return the content view.  The view should may be cached locally.
548          */
getContentView()549         View getContentView();
550 
551         /**
552          * Perhaps do something when the tab associated with this content has
553          * been closed (i.e make it invisible, or remove it).
554          */
tabClosed()555         void tabClosed();
556     }
557 
558     /**
559      * How to create a tab indicator that just has a label.
560      */
561     private class LabelIndicatorStrategy implements IndicatorStrategy {
562 
563         private final CharSequence mLabel;
564 
LabelIndicatorStrategy(CharSequence label)565         private LabelIndicatorStrategy(CharSequence label) {
566             mLabel = label;
567         }
568 
createIndicatorView()569         public View createIndicatorView() {
570             final Context context = getContext();
571             LayoutInflater inflater =
572                     (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
573             View tabIndicator = inflater.inflate(mTabLayoutId,
574                     mTabWidget, // tab widget is the parent
575                     false); // no inflate params
576 
577             final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
578             tv.setText(mLabel);
579 
580             if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
581                 // Donut apps get old color scheme
582                 tabIndicator.setBackgroundResource(R.drawable.tab_indicator_v4);
583                 tv.setTextColor(context.getColorStateList(R.color.tab_indicator_text_v4));
584             }
585 
586             return tabIndicator;
587         }
588     }
589 
590     /**
591      * How we create a tab indicator that has a label and an icon
592      */
593     private class LabelAndIconIndicatorStrategy implements IndicatorStrategy {
594 
595         private final CharSequence mLabel;
596         private final Drawable mIcon;
597 
LabelAndIconIndicatorStrategy(CharSequence label, Drawable icon)598         private LabelAndIconIndicatorStrategy(CharSequence label, Drawable icon) {
599             mLabel = label;
600             mIcon = icon;
601         }
602 
createIndicatorView()603         public View createIndicatorView() {
604             final Context context = getContext();
605             LayoutInflater inflater =
606                     (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
607             View tabIndicator = inflater.inflate(mTabLayoutId,
608                     mTabWidget, // tab widget is the parent
609                     false); // no inflate params
610 
611             final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
612             final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
613 
614             // when icon is gone by default, we're in exclusive mode
615             final boolean exclusive = iconView.getVisibility() == View.GONE;
616             final boolean bindIcon = !exclusive || TextUtils.isEmpty(mLabel);
617 
618             tv.setText(mLabel);
619 
620             if (bindIcon && mIcon != null) {
621                 iconView.setImageDrawable(mIcon);
622                 iconView.setVisibility(VISIBLE);
623             }
624 
625             if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
626                 // Donut apps get old color scheme
627                 tabIndicator.setBackgroundResource(R.drawable.tab_indicator_v4);
628                 tv.setTextColor(context.getColorStateList(R.color.tab_indicator_text_v4));
629             }
630 
631             return tabIndicator;
632         }
633     }
634 
635     /**
636      * How to create a tab indicator by specifying a view.
637      */
638     private class ViewIndicatorStrategy implements IndicatorStrategy {
639 
640         private final View mView;
641 
ViewIndicatorStrategy(View view)642         private ViewIndicatorStrategy(View view) {
643             mView = view;
644         }
645 
createIndicatorView()646         public View createIndicatorView() {
647             return mView;
648         }
649     }
650 
651     /**
652      * How to create the tab content via a view id.
653      */
654     private class ViewIdContentStrategy implements ContentStrategy {
655 
656         private final View mView;
657 
ViewIdContentStrategy(int viewId)658         private ViewIdContentStrategy(int viewId) {
659             mView = mTabContent.findViewById(viewId);
660             if (mView != null) {
661                 mView.setVisibility(View.GONE);
662             } else {
663                 throw new RuntimeException("Could not create tab content because " +
664                         "could not find view with id " + viewId);
665             }
666         }
667 
getContentView()668         public View getContentView() {
669             mView.setVisibility(View.VISIBLE);
670             return mView;
671         }
672 
tabClosed()673         public void tabClosed() {
674             mView.setVisibility(View.GONE);
675         }
676     }
677 
678     /**
679      * How tab content is managed using {@link TabContentFactory}.
680      */
681     private class FactoryContentStrategy implements ContentStrategy {
682         private View mTabContent;
683         private final CharSequence mTag;
684         private TabContentFactory mFactory;
685 
FactoryContentStrategy(CharSequence tag, TabContentFactory factory)686         public FactoryContentStrategy(CharSequence tag, TabContentFactory factory) {
687             mTag = tag;
688             mFactory = factory;
689         }
690 
getContentView()691         public View getContentView() {
692             if (mTabContent == null) {
693                 mTabContent = mFactory.createTabContent(mTag.toString());
694             }
695             mTabContent.setVisibility(View.VISIBLE);
696             return mTabContent;
697         }
698 
tabClosed()699         public void tabClosed() {
700             mTabContent.setVisibility(View.GONE);
701         }
702     }
703 
704     /**
705      * How tab content is managed via an {@link Intent}: the content view is the
706      * decorview of the launched activity.
707      */
708     private class IntentContentStrategy implements ContentStrategy {
709 
710         private final String mTag;
711         private final Intent mIntent;
712 
713         private View mLaunchedView;
714 
IntentContentStrategy(String tag, Intent intent)715         private IntentContentStrategy(String tag, Intent intent) {
716             mTag = tag;
717             mIntent = intent;
718         }
719 
getContentView()720         public View getContentView() {
721             if (mLocalActivityManager == null) {
722                 throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?");
723             }
724             final Window w = mLocalActivityManager.startActivity(
725                     mTag, mIntent);
726             final View wd = w != null ? w.getDecorView() : null;
727             if (mLaunchedView != wd && mLaunchedView != null) {
728                 if (mLaunchedView.getParent() != null) {
729                     mTabContent.removeView(mLaunchedView);
730                 }
731             }
732             mLaunchedView = wd;
733 
734             // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get
735             // focus if none of their children have it. They need focus to be able to
736             // display menu items.
737             //
738             // Replace this with something better when Bug 628886 is fixed...
739             //
740             if (mLaunchedView != null) {
741                 mLaunchedView.setVisibility(View.VISIBLE);
742                 mLaunchedView.setFocusableInTouchMode(true);
743                 ((ViewGroup) mLaunchedView).setDescendantFocusability(
744                         FOCUS_AFTER_DESCENDANTS);
745             }
746             return mLaunchedView;
747         }
748 
tabClosed()749         public void tabClosed() {
750             if (mLaunchedView != null) {
751                 mLaunchedView.setVisibility(View.GONE);
752             }
753         }
754     }
755 
756 }
757