mobile/android/base/TabsPanel.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko;
michael@0 7
michael@0 8 import org.mozilla.gecko.Telemetry;
michael@0 9 import org.mozilla.gecko.TelemetryContract;
michael@0 10 import org.mozilla.gecko.animation.PropertyAnimator;
michael@0 11 import org.mozilla.gecko.animation.ViewHelper;
michael@0 12 import org.mozilla.gecko.widget.IconTabWidget;
michael@0 13
michael@0 14 import android.content.Context;
michael@0 15 import android.content.res.Resources;
michael@0 16 import android.graphics.Rect;
michael@0 17 import android.os.Build;
michael@0 18 import android.util.AttributeSet;
michael@0 19 import android.view.LayoutInflater;
michael@0 20 import android.view.View;
michael@0 21 import android.view.ViewGroup;
michael@0 22 import android.widget.Button;
michael@0 23 import android.widget.FrameLayout;
michael@0 24 import android.widget.ImageButton;
michael@0 25 import android.widget.LinearLayout;
michael@0 26 import android.widget.RelativeLayout;
michael@0 27
michael@0 28 public class TabsPanel extends LinearLayout
michael@0 29 implements LightweightTheme.OnChangeListener,
michael@0 30 IconTabWidget.OnTabChangedListener {
michael@0 31 private static final String LOGTAG = "GeckoTabsPanel";
michael@0 32
michael@0 33 public static enum Panel {
michael@0 34 NORMAL_TABS,
michael@0 35 PRIVATE_TABS,
michael@0 36 REMOTE_TABS
michael@0 37 }
michael@0 38
michael@0 39 public static interface PanelView {
michael@0 40 public ViewGroup getLayout();
michael@0 41 public void setTabsPanel(TabsPanel panel);
michael@0 42 public void show();
michael@0 43 public void hide();
michael@0 44 public boolean shouldExpand();
michael@0 45 }
michael@0 46
michael@0 47 public static interface TabsLayoutChangeListener {
michael@0 48 public void onTabsLayoutChange(int width, int height);
michael@0 49 }
michael@0 50
michael@0 51 private Context mContext;
michael@0 52 private final GeckoApp mActivity;
michael@0 53 private final LightweightTheme mTheme;
michael@0 54 private RelativeLayout mHeader;
michael@0 55 private TabsListContainer mTabsContainer;
michael@0 56 private PanelView mPanel;
michael@0 57 private PanelView mPanelNormal;
michael@0 58 private PanelView mPanelPrivate;
michael@0 59 private PanelView mPanelRemote;
michael@0 60 private RelativeLayout mFooter;
michael@0 61 private TabsLayoutChangeListener mLayoutChangeListener;
michael@0 62
michael@0 63 private IconTabWidget mTabWidget;
michael@0 64 private static ImageButton mAddTab;
michael@0 65
michael@0 66 private Panel mCurrentPanel;
michael@0 67 private boolean mIsSideBar;
michael@0 68 private boolean mVisible;
michael@0 69
michael@0 70 public TabsPanel(Context context, AttributeSet attrs) {
michael@0 71 super(context, attrs);
michael@0 72 mContext = context;
michael@0 73 mActivity = (GeckoApp) context;
michael@0 74 mTheme = ((GeckoApplication) context.getApplicationContext()).getLightweightTheme();
michael@0 75
michael@0 76 setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
michael@0 77 LinearLayout.LayoutParams.FILL_PARENT));
michael@0 78 setOrientation(LinearLayout.VERTICAL);
michael@0 79
michael@0 80 mCurrentPanel = Panel.NORMAL_TABS;
michael@0 81 mVisible = false;
michael@0 82
michael@0 83 mIsSideBar = false;
michael@0 84
michael@0 85 LayoutInflater.from(context).inflate(R.layout.tabs_panel, this);
michael@0 86 initialize();
michael@0 87 }
michael@0 88
michael@0 89 private void initialize() {
michael@0 90 mHeader = (RelativeLayout) findViewById(R.id.tabs_panel_header);
michael@0 91 mTabsContainer = (TabsListContainer) findViewById(R.id.tabs_container);
michael@0 92
michael@0 93 mPanelNormal = (PanelView) findViewById(R.id.normal_tabs);
michael@0 94 mPanelNormal.setTabsPanel(this);
michael@0 95
michael@0 96 mPanelPrivate = (PanelView) findViewById(R.id.private_tabs);
michael@0 97 mPanelPrivate.setTabsPanel(this);
michael@0 98
michael@0 99 mPanelRemote = (PanelView) findViewById(R.id.synced_tabs);
michael@0 100 mPanelRemote.setTabsPanel(this);
michael@0 101
michael@0 102 mFooter = (RelativeLayout) findViewById(R.id.tabs_panel_footer);
michael@0 103
michael@0 104 mAddTab = (ImageButton) findViewById(R.id.add_tab);
michael@0 105 mAddTab.setOnClickListener(new Button.OnClickListener() {
michael@0 106 @Override
michael@0 107 public void onClick(View v) {
michael@0 108 TabsPanel.this.addTab();
michael@0 109 }
michael@0 110 });
michael@0 111
michael@0 112 mTabWidget = (IconTabWidget) findViewById(R.id.tab_widget);
michael@0 113
michael@0 114 mTabWidget.addTab(R.drawable.tabs_normal, R.string.tabs_normal);
michael@0 115 mTabWidget.addTab(R.drawable.tabs_private, R.string.tabs_private);
michael@0 116
michael@0 117 if (!GeckoProfile.get(mContext).inGuestMode()) {
michael@0 118 mTabWidget.addTab(R.drawable.tabs_synced, R.string.tabs_synced);
michael@0 119 }
michael@0 120
michael@0 121 mTabWidget.setTabSelectionListener(this);
michael@0 122 }
michael@0 123
michael@0 124 private void addTab() {
michael@0 125 if (mCurrentPanel == Panel.NORMAL_TABS) {
michael@0 126 Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.ACTIONBAR, "new_tab");
michael@0 127 mActivity.addTab();
michael@0 128 } else {
michael@0 129 Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.ACTIONBAR, "new_private_tab");
michael@0 130 mActivity.addPrivateTab();
michael@0 131 }
michael@0 132
michael@0 133 mActivity.autoHideTabs();
michael@0 134 }
michael@0 135
michael@0 136 @Override
michael@0 137 public void onTabChanged(int index) {
michael@0 138 if (index == 0)
michael@0 139 show(Panel.NORMAL_TABS, false);
michael@0 140 else if (index == 1)
michael@0 141 show(Panel.PRIVATE_TABS, false);
michael@0 142 else
michael@0 143 show(Panel.REMOTE_TABS, false);
michael@0 144 }
michael@0 145
michael@0 146 private static int getTabContainerHeight(TabsListContainer listContainer) {
michael@0 147 Resources resources = listContainer.getContext().getResources();
michael@0 148
michael@0 149 PanelView panelView = listContainer.getCurrentPanelView();
michael@0 150 if (panelView != null && !panelView.shouldExpand()) {
michael@0 151 return resources.getDimensionPixelSize(R.dimen.tabs_tray_horizontal_height);
michael@0 152 }
michael@0 153
michael@0 154 int actionBarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
michael@0 155 int screenHeight = resources.getDisplayMetrics().heightPixels;
michael@0 156
michael@0 157 Rect windowRect = new Rect();
michael@0 158 listContainer.getWindowVisibleDisplayFrame(windowRect);
michael@0 159 int windowHeight = windowRect.bottom - windowRect.top;
michael@0 160
michael@0 161 // The web content area should have at least 1.5x the height of the action bar.
michael@0 162 // The tabs panel shouldn't take less than 50% of the screen height and can take
michael@0 163 // up to 80% of the window height.
michael@0 164 return (int) Math.max(screenHeight * 0.5f,
michael@0 165 Math.min(windowHeight - 2.5f * actionBarHeight, windowHeight * 0.8f) - actionBarHeight);
michael@0 166 }
michael@0 167
michael@0 168 @Override
michael@0 169 public void onAttachedToWindow() {
michael@0 170 super.onAttachedToWindow();
michael@0 171 mTheme.addListener(this);
michael@0 172 }
michael@0 173
michael@0 174 @Override
michael@0 175 public void onDetachedFromWindow() {
michael@0 176 super.onDetachedFromWindow();
michael@0 177 mTheme.removeListener(this);
michael@0 178 }
michael@0 179
michael@0 180 @Override
michael@0 181 public void onLightweightThemeChanged() {
michael@0 182 final int background = getResources().getColor(R.color.background_tabs);
michael@0 183 final LightweightThemeDrawable drawable = mTheme.getColorDrawable(this, background, true);
michael@0 184 if (drawable == null)
michael@0 185 return;
michael@0 186
michael@0 187 drawable.setAlpha(34, 0);
michael@0 188 setBackgroundDrawable(drawable);
michael@0 189 }
michael@0 190
michael@0 191 @Override
michael@0 192 public void onLightweightThemeReset() {
michael@0 193 setBackgroundColor(getContext().getResources().getColor(R.color.background_tabs));
michael@0 194 }
michael@0 195
michael@0 196 @Override
michael@0 197 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
michael@0 198 super.onLayout(changed, left, top, right, bottom);
michael@0 199 onLightweightThemeChanged();
michael@0 200 }
michael@0 201
michael@0 202 // Tabs List Container holds the ListView
michael@0 203 public static class TabsListContainer extends FrameLayout {
michael@0 204 public TabsListContainer(Context context, AttributeSet attrs) {
michael@0 205 super(context, attrs);
michael@0 206 }
michael@0 207
michael@0 208 public PanelView getCurrentPanelView() {
michael@0 209 final int childCount = getChildCount();
michael@0 210 for (int i = 0; i < childCount; i++) {
michael@0 211 View child = getChildAt(i);
michael@0 212 if (!(child instanceof PanelView))
michael@0 213 continue;
michael@0 214
michael@0 215 if (child.getVisibility() == View.VISIBLE)
michael@0 216 return (PanelView) child;
michael@0 217 }
michael@0 218
michael@0 219 return null;
michael@0 220 }
michael@0 221
michael@0 222 @Override
michael@0 223 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
michael@0 224 if (!GeckoAppShell.getGeckoInterface().hasTabsSideBar()) {
michael@0 225 int heightSpec = MeasureSpec.makeMeasureSpec(getTabContainerHeight(TabsListContainer.this), MeasureSpec.EXACTLY);
michael@0 226 super.onMeasure(widthMeasureSpec, heightSpec);
michael@0 227 } else {
michael@0 228 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
michael@0 229 }
michael@0 230 }
michael@0 231 }
michael@0 232
michael@0 233 // Tabs Panel Toolbar contains the Buttons
michael@0 234 public static class TabsPanelToolbar extends LinearLayout
michael@0 235 implements LightweightTheme.OnChangeListener {
michael@0 236 private final LightweightTheme mTheme;
michael@0 237
michael@0 238 public TabsPanelToolbar(Context context, AttributeSet attrs) {
michael@0 239 super(context, attrs);
michael@0 240 mTheme = ((GeckoApplication) context.getApplicationContext()).getLightweightTheme();
michael@0 241
michael@0 242 setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
michael@0 243 (int) context.getResources().getDimension(R.dimen.browser_toolbar_height)));
michael@0 244
michael@0 245 setOrientation(LinearLayout.HORIZONTAL);
michael@0 246 }
michael@0 247
michael@0 248 @Override
michael@0 249 public void onAttachedToWindow() {
michael@0 250 super.onAttachedToWindow();
michael@0 251 mTheme.addListener(this);
michael@0 252 }
michael@0 253
michael@0 254 @Override
michael@0 255 public void onDetachedFromWindow() {
michael@0 256 super.onDetachedFromWindow();
michael@0 257 mTheme.removeListener(this);
michael@0 258 }
michael@0 259
michael@0 260 @Override
michael@0 261 public void onLightweightThemeChanged() {
michael@0 262 final int background = getResources().getColor(R.color.background_tabs);
michael@0 263 final LightweightThemeDrawable drawable = mTheme.getColorDrawable(this, background);
michael@0 264 if (drawable == null)
michael@0 265 return;
michael@0 266
michael@0 267 drawable.setAlpha(34, 34);
michael@0 268 setBackgroundDrawable(drawable);
michael@0 269 }
michael@0 270
michael@0 271 @Override
michael@0 272 public void onLightweightThemeReset() {
michael@0 273 setBackgroundColor(getContext().getResources().getColor(R.color.background_tabs));
michael@0 274 }
michael@0 275
michael@0 276 @Override
michael@0 277 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
michael@0 278 super.onLayout(changed, left, top, right, bottom);
michael@0 279 onLightweightThemeChanged();
michael@0 280 }
michael@0 281 }
michael@0 282
michael@0 283 public void show(Panel panel) {
michael@0 284 show(panel, true);
michael@0 285 }
michael@0 286
michael@0 287 public void show(Panel panel, boolean shouldResize) {
michael@0 288 if (!isShown())
michael@0 289 setVisibility(View.VISIBLE);
michael@0 290
michael@0 291 if (mPanel != null) {
michael@0 292 // Hide the old panel.
michael@0 293 mPanel.hide();
michael@0 294 }
michael@0 295
michael@0 296 final boolean showAnimation = !mVisible;
michael@0 297 mVisible = true;
michael@0 298 mCurrentPanel = panel;
michael@0 299
michael@0 300 int index = panel.ordinal();
michael@0 301 mTabWidget.setCurrentTab(index);
michael@0 302
michael@0 303 if (index == 0) {
michael@0 304 mPanel = mPanelNormal;
michael@0 305 } else if (index == 1) {
michael@0 306 mPanel = mPanelPrivate;
michael@0 307 } else {
michael@0 308 mPanel = mPanelRemote;
michael@0 309 }
michael@0 310
michael@0 311 mPanel.show();
michael@0 312
michael@0 313 if (mCurrentPanel == Panel.REMOTE_TABS) {
michael@0 314 if (mFooter != null)
michael@0 315 mFooter.setVisibility(View.GONE);
michael@0 316
michael@0 317 mAddTab.setVisibility(View.INVISIBLE);
michael@0 318 } else {
michael@0 319 if (mFooter != null)
michael@0 320 mFooter.setVisibility(View.VISIBLE);
michael@0 321
michael@0 322 mAddTab.setVisibility(View.VISIBLE);
michael@0 323 mAddTab.setImageLevel(index);
michael@0 324 }
michael@0 325
michael@0 326 if (shouldResize) {
michael@0 327 if (isSideBar()) {
michael@0 328 if (showAnimation)
michael@0 329 dispatchLayoutChange(getWidth(), getHeight());
michael@0 330 } else {
michael@0 331 int actionBarHeight = mContext.getResources().getDimensionPixelSize(R.dimen.browser_toolbar_height);
michael@0 332 int height = actionBarHeight + getTabContainerHeight(mTabsContainer);
michael@0 333 dispatchLayoutChange(getWidth(), height);
michael@0 334 }
michael@0 335 }
michael@0 336 }
michael@0 337
michael@0 338 public void hide() {
michael@0 339 if (mVisible) {
michael@0 340 mVisible = false;
michael@0 341 dispatchLayoutChange(0, 0);
michael@0 342 }
michael@0 343 }
michael@0 344
michael@0 345 public void refresh() {
michael@0 346 removeAllViews();
michael@0 347
michael@0 348 LayoutInflater.from(mContext).inflate(R.layout.tabs_panel, this);
michael@0 349 initialize();
michael@0 350
michael@0 351 if (mVisible)
michael@0 352 show(mCurrentPanel);
michael@0 353 }
michael@0 354
michael@0 355 public void autoHidePanel() {
michael@0 356 mActivity.autoHideTabs();
michael@0 357 }
michael@0 358
michael@0 359 @Override
michael@0 360 public boolean isShown() {
michael@0 361 return mVisible;
michael@0 362 }
michael@0 363
michael@0 364 public boolean isSideBar() {
michael@0 365 return mIsSideBar;
michael@0 366 }
michael@0 367
michael@0 368 public void setIsSideBar(boolean isSideBar) {
michael@0 369 mIsSideBar = isSideBar;
michael@0 370 }
michael@0 371
michael@0 372 public Panel getCurrentPanel() {
michael@0 373 return mCurrentPanel;
michael@0 374 }
michael@0 375
michael@0 376 public void prepareTabsAnimation(PropertyAnimator animator) {
michael@0 377 // Not worth doing this on pre-Honeycomb without proper
michael@0 378 // hardware accelerated animations.
michael@0 379 if (Build.VERSION.SDK_INT < 11) {
michael@0 380 return;
michael@0 381 }
michael@0 382
michael@0 383 final Resources resources = getContext().getResources();
michael@0 384 final int toolbarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
michael@0 385 final int tabsPanelWidth = getWidth();
michael@0 386
michael@0 387 if (mVisible) {
michael@0 388 if (mIsSideBar) {
michael@0 389 ViewHelper.setTranslationX(mHeader, -tabsPanelWidth);
michael@0 390 } else {
michael@0 391 ViewHelper.setTranslationY(mHeader, -toolbarHeight);
michael@0 392 }
michael@0 393
michael@0 394 if (mIsSideBar) {
michael@0 395 ViewHelper.setTranslationX(mTabsContainer, -tabsPanelWidth);
michael@0 396 } else {
michael@0 397 ViewHelper.setTranslationY(mTabsContainer, -toolbarHeight);
michael@0 398 ViewHelper.setAlpha(mTabsContainer, 0);
michael@0 399 }
michael@0 400
michael@0 401 // The footer view is only present on the sidebar
michael@0 402 if (mIsSideBar) {
michael@0 403 ViewHelper.setTranslationX(mFooter, -tabsPanelWidth);
michael@0 404 }
michael@0 405 }
michael@0 406
michael@0 407 if (mIsSideBar) {
michael@0 408 final int translationX = (mVisible ? 0 : -tabsPanelWidth);
michael@0 409
michael@0 410 animator.attach(mTabsContainer,
michael@0 411 PropertyAnimator.Property.TRANSLATION_X,
michael@0 412 translationX);
michael@0 413 animator.attach(mHeader,
michael@0 414 PropertyAnimator.Property.TRANSLATION_X,
michael@0 415 translationX);
michael@0 416 animator.attach(mFooter,
michael@0 417 PropertyAnimator.Property.TRANSLATION_X,
michael@0 418 translationX);
michael@0 419 } else {
michael@0 420 final int translationY = (mVisible ? 0 : -toolbarHeight);
michael@0 421
michael@0 422 animator.attach(mTabsContainer,
michael@0 423 PropertyAnimator.Property.ALPHA,
michael@0 424 mVisible ? 1.0f : 0.0f);
michael@0 425 animator.attach(mTabsContainer,
michael@0 426 PropertyAnimator.Property.TRANSLATION_Y,
michael@0 427 translationY);
michael@0 428 animator.attach(mHeader,
michael@0 429 PropertyAnimator.Property.TRANSLATION_Y,
michael@0 430 translationY);
michael@0 431 }
michael@0 432
michael@0 433 mHeader.setLayerType(View.LAYER_TYPE_HARDWARE, null);
michael@0 434 mTabsContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
michael@0 435 }
michael@0 436
michael@0 437 public void finishTabsAnimation() {
michael@0 438 if (Build.VERSION.SDK_INT < 11) {
michael@0 439 return;
michael@0 440 }
michael@0 441
michael@0 442 mHeader.setLayerType(View.LAYER_TYPE_NONE, null);
michael@0 443 mTabsContainer.setLayerType(View.LAYER_TYPE_NONE, null);
michael@0 444
michael@0 445 // If the tray is now hidden, call hide() on current panel and unset it as the current panel
michael@0 446 // to avoid hide() being called again when the tray is opened next.
michael@0 447 if (!mVisible && mPanel != null) {
michael@0 448 mPanel.hide();
michael@0 449 mPanel = null;
michael@0 450 }
michael@0 451 }
michael@0 452
michael@0 453 public void setTabsLayoutChangeListener(TabsLayoutChangeListener listener) {
michael@0 454 mLayoutChangeListener = listener;
michael@0 455 }
michael@0 456
michael@0 457 private void dispatchLayoutChange(int width, int height) {
michael@0 458 if (mLayoutChangeListener != null)
michael@0 459 mLayoutChangeListener.onTabsLayoutChange(width, height);
michael@0 460 }
michael@0 461 }

mercurial