Home | History | Annotate | Download | only in widget
      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 
     71     public TabHost(Context context) {
     72         super(context);
     73         initTabHost();
     74     }
     75 
     76     public TabHost(Context context, AttributeSet attrs) {
     77         this(context, attrs, com.android.internal.R.attr.tabWidgetStyle);
     78     }
     79 
     80     public TabHost(Context context, AttributeSet attrs, int defStyleAttr) {
     81         this(context, attrs, defStyleAttr, 0);
     82     }
     83 
     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 
    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      */
    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       */
    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
    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      */
    186     public void setup(LocalActivityManager activityGroup) {
    187         setup();
    188         mLocalActivityManager = activityGroup;
    189     }
    190 
    191     @Override
    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      */
    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      */
    230     public void clearAllTabs() {
    231         mTabWidget.removeAllViews();
    232         initTabHost();
    233         mTabContent.removeAllViews();
    234         mTabSpecs.clear();
    235         requestLayout();
    236         invalidate();
    237     }
    238 
    239     public TabWidget getTabWidget() {
    240         return mTabWidget;
    241     }
    242 
    243     public int getCurrentTab() {
    244         return mCurrentTab;
    245     }
    246 
    247     public String getCurrentTabTag() {
    248         if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
    249             return mTabSpecs.get(mCurrentTab).getTag();
    250         }
    251         return null;
    252     }
    253 
    254     public View getCurrentTabView() {
    255         if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
    256             return mTabWidget.getChildTabViewAt(mCurrentTab);
    257         }
    258         return null;
    259     }
    260 
    261     public View getCurrentView() {
    262         return mCurrentView;
    263     }
    264 
    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      */
    278     public FrameLayout getTabContentView() {
    279         return mTabContent;
    280     }
    281 
    282     /**
    283      * Get the location of the TabWidget.
    284      *
    285      * @return The TabWidget location.
    286      */
    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
    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
    355     public void dispatchWindowFocusChanged(boolean hasFocus) {
    356         if (mCurrentView != null){
    357             mCurrentView.dispatchWindowFocusChanged(hasFocus);
    358         }
    359     }
    360 
    361     @Override
    362     public CharSequence getAccessibilityClassName() {
    363         return TabHost.class.getName();
    364     }
    365 
    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      */
    415     public void setOnTabChangedListener(OnTabChangeListener l) {
    416         mOnTabChangeListener = l;
    417     }
    418 
    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 {
    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          */
    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 
    470         private TabSpec(String tag) {
    471             mTag = tag;
    472         }
    473 
    474         /**
    475          * Specify a label as the tab indicator.
    476          */
    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          */
    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          */
    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          */
    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          */
    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          */
    519         public TabSpec setContent(Intent intent) {
    520             mContentStrategy = new IntentContentStrategy(mTag, intent);
    521             return this;
    522         }
    523 
    524 
    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          */
    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          */
    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          */
    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 
    565         private LabelIndicatorStrategy(CharSequence label) {
    566             mLabel = label;
    567         }
    568 
    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 
    598         private LabelAndIconIndicatorStrategy(CharSequence label, Drawable icon) {
    599             mLabel = label;
    600             mIcon = icon;
    601         }
    602 
    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 
    642         private ViewIndicatorStrategy(View view) {
    643             mView = view;
    644         }
    645 
    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 
    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 
    668         public View getContentView() {
    669             mView.setVisibility(View.VISIBLE);
    670             return mView;
    671         }
    672 
    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 
    686         public FactoryContentStrategy(CharSequence tag, TabContentFactory factory) {
    687             mTag = tag;
    688             mFactory = factory;
    689         }
    690 
    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 
    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 
    715         private IntentContentStrategy(String tag, Intent intent) {
    716             mTag = tag;
    717             mIntent = intent;
    718         }
    719 
    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 
    749         public void tabClosed() {
    750             if (mLaunchedView != null) {
    751                 mLaunchedView.setVisibility(View.GONE);
    752             }
    753         }
    754     }
    755 
    756 }
    757