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