Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org.mozilla.gecko.home;
8 import org.mozilla.gecko.R;
10 import android.content.Context;
11 import android.content.res.TypedArray;
12 import android.graphics.Canvas;
13 import android.graphics.drawable.Drawable;
14 import android.util.AttributeSet;
15 import android.view.LayoutInflater;
16 import android.view.View;
17 import android.view.ViewTreeObserver;
18 import android.view.accessibility.AccessibilityEvent;
19 import android.widget.LinearLayout;
20 import android.widget.TextView;
22 /**
23 * {@code TabMenuStripLayout} is the view that draws the {@code HomePager}
24 * tabs that are displayed in {@code TabMenuStrip}.
25 */
26 class TabMenuStripLayout extends LinearLayout
27 implements View.OnFocusChangeListener {
29 private HomePager.OnTitleClickListener onTitleClickListener;
30 private Drawable strip;
31 private View selectedView;
33 // Data associated with the scrolling of the strip drawable.
34 private View toTab;
35 private View fromTab;
36 private float progress;
38 // This variable is used to predict the direction of scroll.
39 private float prevProgress;
41 TabMenuStripLayout(Context context, AttributeSet attrs) {
42 super(context, attrs);
44 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabMenuStrip);
45 final int stripResId = a.getResourceId(R.styleable.TabMenuStrip_strip, -1);
46 a.recycle();
48 if (stripResId != -1) {
49 strip = getResources().getDrawable(stripResId);
50 }
52 setWillNotDraw(false);
53 }
55 void onAddPagerView(String title) {
56 final TextView button = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.tab_menu_strip, this, false);
57 button.setText(title.toUpperCase());
59 addView(button);
60 button.setOnClickListener(new ViewClickListener(getChildCount() - 1));
61 button.setOnFocusChangeListener(this);
62 }
64 void onPageSelected(final int position) {
65 selectedView = getChildAt(position);
67 // Callback to measure and draw the strip after the view is visible.
68 ViewTreeObserver vto = selectedView.getViewTreeObserver();
69 if (vto.isAlive()) {
70 vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
71 @Override
72 public void onGlobalLayout() {
73 selectedView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
75 if (strip != null) {
76 strip.setBounds(selectedView.getLeft(),
77 selectedView.getTop(),
78 selectedView.getRight(),
79 selectedView.getBottom());
80 }
82 prevProgress = position;
83 }
84 });
85 }
86 }
88 // Page scroll animates the drawable and its bounds from the previous to next child view.
89 void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
90 if (strip == null) {
91 return;
92 }
94 setScrollingData(position, positionOffset);
96 if (fromTab == null || toTab == null) {
97 return;
98 }
100 final int fromTabLeft = fromTab.getLeft();
101 final int fromTabRight = fromTab.getRight();
103 final int toTabLeft = toTab.getLeft();
104 final int toTabRight = toTab.getRight();
106 strip.setBounds((int) (fromTabLeft + ((toTabLeft - fromTabLeft) * progress)),
107 0,
108 (int) (fromTabRight + ((toTabRight - fromTabRight) * progress)),
109 getHeight());
110 invalidate();
111 }
113 /*
114 * position + positionOffset goes from 0 to 2 as we scroll from page 1 to 3.
115 * Normalized progress is relative to the the direction the page is being scrolled towards.
116 * For this, we maintain direction of scroll with a state, and the child view we are moving towards and away from.
117 */
118 void setScrollingData(int position, float positionOffset) {
119 if (position >= getChildCount() - 1) {
120 return;
121 }
123 final float currProgress = position + positionOffset;
125 if (prevProgress > currProgress) {
126 toTab = getChildAt(position);
127 fromTab = getChildAt(position + 1);
128 progress = 1 - positionOffset;
129 } else {
130 toTab = getChildAt(position + 1);
131 fromTab = getChildAt(position);
132 progress = positionOffset;
133 }
135 prevProgress = currProgress;
136 }
138 @Override
139 public void onDraw(Canvas canvas) {
140 super.onDraw(canvas);
142 if (strip != null) {
143 strip.draw(canvas);
144 }
145 }
147 @Override
148 public void onFocusChange(View v, boolean hasFocus) {
149 if (v == this && hasFocus && getChildCount() > 0) {
150 selectedView.requestFocus();
151 return;
152 }
154 if (!hasFocus) {
155 return;
156 }
158 int i = 0;
159 final int numTabs = getChildCount();
161 while (i < numTabs) {
162 View view = getChildAt(i);
163 if (view == v) {
164 view.requestFocus();
165 if (isShown()) {
166 // A view is focused so send an event to announce the menu strip state.
167 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
168 }
169 break;
170 }
172 i++;
173 }
174 }
176 void setOnTitleClickListener(HomePager.OnTitleClickListener onTitleClickListener) {
177 this.onTitleClickListener = onTitleClickListener;
178 }
180 private class ViewClickListener implements OnClickListener {
181 private final int mIndex;
183 public ViewClickListener(int index) {
184 mIndex = index;
185 }
187 @Override
188 public void onClick(View view) {
189 if (onTitleClickListener != null) {
190 onTitleClickListener.onTitleClicked(mIndex);
191 }
192 }
193 }
194 }