12055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich/* 22055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** 32055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** Copyright 2013, The Android Open Source Project 42055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** 52055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** Licensed under the Apache License, Version 2.0 (the "License"); 62055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** you may not use this file except in compliance with the License. 72055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** You may obtain a copy of the License at 82055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** 92055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** http://www.apache.org/licenses/LICENSE-2.0 102055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** 112055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** Unless required by applicable law or agreed to in writing, software 122055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** distributed under the License is distributed on an "AS IS" BASIS, 132055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** See the License for the specific language governing permissions and 152055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich** limitations under the License. 162055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich*/ 172055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichpackage com.android.packageinstaller; 182055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 192055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.app.Activity; 202055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.content.Context; 212055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.graphics.Rect; 222055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.support.v4.view.PagerAdapter; 232055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.support.v4.view.ViewPager; 242055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.view.View; 252055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.view.ViewGroup; 262055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.widget.TabHost; 272055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport android.widget.TabWidget; 282055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 292055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichimport java.util.ArrayList; 302055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 312055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich/** 322055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * This is a helper class that implements the management of tabs and all 332055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * details of connecting a ViewPager with associated TabHost. It relies on a 342055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * trick. Normally a tab host has a simple API for supplying a View or 352055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * Intent that each tab will show. This is not sufficient for switching 362055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * between pages. So instead we make the content part of the tab host 372055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy 382055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * view to show as the tab content. It listens to changes in tabs, and takes 392055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * care of switch to the correct paged in the ViewPager whenever the selected 402055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich * tab changes. 412055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich */ 422055eecd55b944643111c4987e507f4a650f95e4Nick Kralevichpublic class TabsAdapter extends PagerAdapter 432055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener { 442055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final Context mContext; 452055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final TabHost mTabHost; 462055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final ViewPager mViewPager; 472055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); 482055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final Rect mTempRect = new Rect(); 497b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin private TabHost.OnTabChangeListener mOnTabChangeListener; 502055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 512055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich static final class TabInfo { 522055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final String tag; 532055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final View view; 542055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 552055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich TabInfo(String _tag, View _view) { 562055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich tag = _tag; 572055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich view = _view; 582055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 592055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 602055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 612055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich static class DummyTabFactory implements TabHost.TabContentFactory { 622055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich private final Context mContext; 632055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 642055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public DummyTabFactory(Context context) { 652055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mContext = context; 662055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 672055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 682055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 692055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public View createTabContent(String tag) { 702055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich View v = new View(mContext); 712055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich v.setMinimumWidth(0); 722055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich v.setMinimumHeight(0); 732055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich return v; 742055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 752055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 762055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 772055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public TabsAdapter(Activity activity, TabHost tabHost, ViewPager pager) { 782055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mContext = activity; 792055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mTabHost = tabHost; 802055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mViewPager = pager; 812055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mTabHost.setOnTabChangedListener(this); 822055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mViewPager.setAdapter(this); 832055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mViewPager.setOnPageChangeListener(this); 842055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 852055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 862055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public void addTab(TabHost.TabSpec tabSpec, View view) { 872055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich tabSpec.setContent(new DummyTabFactory(mContext)); 882055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich String tag = tabSpec.getTag(); 892055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 902055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich TabInfo info = new TabInfo(tag, view); 912055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mTabs.add(info); 922055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mTabHost.addTab(tabSpec); 932055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich notifyDataSetChanged(); 942055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 952055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 962055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 972055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public int getCount() { 982055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich return mTabs.size(); 992055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1002055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1012055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 1022055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public Object instantiateItem(ViewGroup container, int position) { 1032055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich View view = mTabs.get(position).view; 1042055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich container.addView(view); 1052055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich return view; 1062055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1072055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1082055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 1092055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public void destroyItem(ViewGroup container, int position, Object object) { 1102055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich container.removeView((View)object); 1112055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1122055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1132055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 1142055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public boolean isViewFromObject(View view, Object object) { 1152055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich return view == object; 1162055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1172055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1187b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin public void setOnTabChangedListener(TabHost.OnTabChangeListener listener) { 1197b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin mOnTabChangeListener = listener; 1207b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin } 1217b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin 1222055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 1232055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public void onTabChanged(String tabId) { 1242055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich int position = mTabHost.getCurrentTab(); 1252055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mViewPager.setCurrentItem(position); 1267b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin if (mOnTabChangeListener != null) { 1277b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin mOnTabChangeListener.onTabChanged(tabId); 1287b30bc34492a0c53b02cec2fee7d0993da407fc4Alex Klyubin } 1292055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1302055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1312055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 1322055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 1332055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1342055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1352055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 1362055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public void onPageSelected(int position) { 1372055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich // Unfortunately when TabHost changes the current tab, it kindly 1382055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich // also takes care of putting focus on it when not in touch mode. 1392055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich // The jerk. 1402055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich // This hack tries to prevent this from pulling focus out of our 1412055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich // ViewPager. 1422055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich TabWidget widget = mTabHost.getTabWidget(); 1432055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich int oldFocusability = widget.getDescendantFocusability(); 1442055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 1452055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mTabHost.setCurrentTab(position); 1462055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich widget.setDescendantFocusability(oldFocusability); 1472055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1482055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich // Scroll the current tab into visibility if needed. 1492055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich View tab = widget.getChildTabViewAt(position); 1502055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich mTempRect.set(tab.getLeft(), tab.getTop(), tab.getRight(), tab.getBottom()); 1512055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich widget.requestRectangleOnScreen(mTempRect, false); 1522055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1532055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich // Make sure the scrollbars are visible for a moment after selection 1542055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich final View contentView = mTabs.get(position).view; 1552055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich if (contentView instanceof CaffeinatedScrollView) { 1562055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich ((CaffeinatedScrollView) contentView).awakenScrollBars(); 1572055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1582055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1592055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich 1602055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich @Override 1612055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich public void onPageScrollStateChanged(int state) { 1622055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich } 1632055eecd55b944643111c4987e507f4a650f95e4Nick Kralevich} 164