1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/toolbar/TabCounter.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,133 @@ 1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +package org.mozilla.gecko.toolbar; 1.10 + 1.11 +import org.mozilla.gecko.animation.Rotate3DAnimation; 1.12 +import org.mozilla.gecko.R; 1.13 +import org.mozilla.gecko.widget.ThemedTextSwitcher; 1.14 + 1.15 +import android.content.Context; 1.16 +import android.os.Build; 1.17 +import android.view.accessibility.AccessibilityNodeInfo; 1.18 +import android.view.animation.Animation; 1.19 +import android.view.animation.AnimationSet; 1.20 +import android.view.animation.AlphaAnimation; 1.21 +import android.view.LayoutInflater; 1.22 +import android.view.View; 1.23 +import android.util.AttributeSet; 1.24 +import android.widget.ViewSwitcher; 1.25 + 1.26 +public class TabCounter extends ThemedTextSwitcher 1.27 + implements ViewSwitcher.ViewFactory { 1.28 + 1.29 + private static final float CENTER_X = 0.5f; 1.30 + private static final float CENTER_Y = 1.25f; 1.31 + private static final int DURATION = 500; 1.32 + private static final float Z_DISTANCE = 200; 1.33 + 1.34 + private final AnimationSet mFlipInForward; 1.35 + private final AnimationSet mFlipInBackward; 1.36 + private final AnimationSet mFlipOutForward; 1.37 + private final AnimationSet mFlipOutBackward; 1.38 + private final LayoutInflater mInflater; 1.39 + 1.40 + private int mCount = 0; 1.41 + 1.42 + private enum FadeMode { 1.43 + FADE_IN, 1.44 + FADE_OUT 1.45 + } 1.46 + 1.47 + public TabCounter(Context context, AttributeSet attrs) { 1.48 + super(context, attrs); 1.49 + mInflater = LayoutInflater.from(context); 1.50 + 1.51 + mFlipInForward = createAnimation(-90, 0, FadeMode.FADE_IN, -1 * Z_DISTANCE, false); 1.52 + mFlipInBackward = createAnimation(90, 0, FadeMode.FADE_IN, Z_DISTANCE, false); 1.53 + mFlipOutForward = createAnimation(0, -90, FadeMode.FADE_OUT, -1 * Z_DISTANCE, true); 1.54 + mFlipOutBackward = createAnimation(0, 90, FadeMode.FADE_OUT, Z_DISTANCE, true); 1.55 + 1.56 + removeAllViews(); 1.57 + setFactory(this); 1.58 + 1.59 + if (Build.VERSION.SDK_INT >= 16) { 1.60 + // This adds the TextSwitcher to the a11y node tree, where we in turn 1.61 + // could make it return an empty info node. If we don't do this the 1.62 + // TextSwitcher's child TextViews get picked up, and we don't want 1.63 + // that since the tabs ImageButton is already properly labeled for 1.64 + // accessibility. 1.65 + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 1.66 + setAccessibilityDelegate(new View.AccessibilityDelegate() { 1.67 + @Override 1.68 + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {} 1.69 + }); 1.70 + } 1.71 + } 1.72 + 1.73 + void setCountWithAnimation(int count) { 1.74 + // Don't animate from initial state 1.75 + if (mCount == 0) { 1.76 + setCount(count); 1.77 + return; 1.78 + } 1.79 + 1.80 + if (mCount == count) { 1.81 + return; 1.82 + } 1.83 + 1.84 + if (count < mCount) { 1.85 + setInAnimation(mFlipInBackward); 1.86 + setOutAnimation(mFlipOutForward); 1.87 + } else { 1.88 + setInAnimation(mFlipInForward); 1.89 + setOutAnimation(mFlipOutBackward); 1.90 + } 1.91 + 1.92 + // Eliminate screen artifact. Set explicit In/Out animation pair order. This will always 1.93 + // animate pair in In->Out child order, prevent alternating use of the Out->In case. 1.94 + setDisplayedChild(0); 1.95 + 1.96 + // Set In value, trigger animation to Out value 1.97 + setCurrentText(String.valueOf(mCount)); 1.98 + setText(String.valueOf(count)); 1.99 + 1.100 + mCount = count; 1.101 + } 1.102 + 1.103 + void setCount(int count) { 1.104 + setCurrentText(String.valueOf(count)); 1.105 + mCount = count; 1.106 + } 1.107 + 1.108 + // Alpha animations in editing mode cause action bar corruption on the 1.109 + // Nexus 7 (bug 961749). As a workaround, skip these animations in editing 1.110 + // mode. 1.111 + void onEnterEditingMode() { 1.112 + final int childCount = getChildCount(); 1.113 + for (int i = 0; i < childCount; i++) { 1.114 + getChildAt(i).clearAnimation(); 1.115 + } 1.116 + } 1.117 + 1.118 + private AnimationSet createAnimation(float startAngle, float endAngle, 1.119 + FadeMode fadeMode, 1.120 + float zEnd, boolean reverse) { 1.121 + final Context context = getContext(); 1.122 + AnimationSet set = new AnimationSet(context, null); 1.123 + set.addAnimation(new Rotate3DAnimation(startAngle, endAngle, CENTER_X, CENTER_Y, zEnd, reverse)); 1.124 + set.addAnimation(fadeMode == FadeMode.FADE_IN ? new AlphaAnimation(0.0f, 1.0f) : 1.125 + new AlphaAnimation(1.0f, 0.0f)); 1.126 + set.setDuration(DURATION); 1.127 + set.setInterpolator(context, android.R.anim.accelerate_interpolator); 1.128 + return set; 1.129 + } 1.130 + 1.131 + @Override 1.132 + public View makeView() { 1.133 + return mInflater.inflate(R.layout.tabs_counter, null); 1.134 + } 1.135 + 1.136 +}