1a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang/* 2a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Copyright (C) 2014 The Android Open Source Project 3a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 4a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Licensed under the Apache License, Version 2.0 (the "License"); 5a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * you may not use this file except in compliance with the License. 6a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * You may obtain a copy of the License at 7a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 8a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * http://www.apache.org/licenses/LICENSE-2.0 9a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 10a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Unless required by applicable law or agreed to in writing, software 11a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * distributed under the License is distributed on an "AS IS" BASIS, 12a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * See the License for the specific language governing permissions and 14a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * limitations under the License. 15a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 16a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 17a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangpackage com.android.fmradio.views; 18a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 19a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.animation.Animator; 20a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.animation.Animator.AnimatorListener; 21a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.animation.AnimatorListenerAdapter; 22a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.animation.ObjectAnimator; 23a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.content.Context; 24a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.content.res.Configuration; 25a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.content.res.Resources; 26a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.content.res.TypedArray; 27a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.database.Cursor; 28a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.graphics.Canvas; 29a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.graphics.Color; 30a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.graphics.Paint; 31a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.graphics.Typeface; 32a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.hardware.display.DisplayManagerGlobal; 33a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.os.Handler; 34a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.os.Looper; 35a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.util.AttributeSet; 36a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.util.DisplayMetrics; 37a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.Display; 38a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.DisplayInfo; 39a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.LayoutInflater; 40a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.Menu; 41a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.MenuItem; 42a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.MotionEvent; 43a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.VelocityTracker; 44a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.View; 45a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.ViewConfiguration; 46a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.ViewGroup; 47a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.ViewTreeObserver.OnPreDrawListener; 48a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.animation.Interpolator; 49a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.AdapterView; 50a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.AdapterView.OnItemClickListener; 51a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.BaseAdapter; 52a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.EdgeEffect; 53a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.FrameLayout; 54a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.GridView; 55a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.ImageView; 56a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.PopupMenu; 57a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.PopupMenu.OnMenuItemClickListener; 58a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.ScrollView; 59a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.Scroller; 60a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.TextView; 61a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 62a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport com.android.fmradio.FmStation; 63a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport com.android.fmradio.FmUtils; 64a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport com.android.fmradio.R; 65a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport com.android.fmradio.FmStation.Station; 66a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 67a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang/** 68a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Modified from Contact MultiShrinkScroll Handle the touch event and change 69a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * header size and scroll 70a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 71a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangpublic class FmScroller extends FrameLayout { 72a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final String TAG = "FmScroller"; 73a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 74a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 75a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 1000 pixels per millisecond. Ie, 1 pixel per second. 76a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 77a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final int PIXELS_PER_SECOND = 1000; 78a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final int ON_PLAY_ANIMATION_DELAY = 1000; 79a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final int PORT_COLUMN_NUM = 3; 80a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final int LAND_COLUMN_NUM = 5; 81a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final int STATE_NO_FAVORITE = 0; 82a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final int STATE_HAS_FAVORITE = 1; 83a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 84a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private float[] mLastEventPosition = { 85a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 0, 0 86a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }; 87a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private VelocityTracker mVelocityTracker; 88a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private boolean mIsBeingDragged = false; 89a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private boolean mReceivedDown = false; 90a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private boolean mFirstOnResume = true; 91a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 92a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private String mSelection = "IS_FAVORITE=?"; 93a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private String[] mSelectionArgs = { 94a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang "1" 95a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }; 96a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 97a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private EventListener mEventListener; 98a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private PopupMenu mPopupMenu; 99a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private Handler mMainHandler; 100a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private ScrollView mScrollView; 101a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private View mScrollViewChild; 102a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private GridView mGridView; 103a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private TextView mFavoriteText; 104a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private View mHeader; 105a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int mMaximumHeaderHeight; 106a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int mMinimumHeaderHeight; 107a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private Adjuster mAdjuster; 108a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int mCurrentStation; 109a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private boolean mIsFmPlaying; 110a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 111a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private FavoriteAdapter mAdapter; 112a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final Scroller mScroller; 113a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final EdgeEffect mEdgeGlowBottom; 114a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mTouchSlop; 115a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mMaximumVelocity; 116a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mMinimumVelocity; 117a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mActionBarSize; 118a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 119a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final AnimatorListener mHeaderExpandAnimationListener = new AnimatorListenerAdapter() { 120a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 121a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void onAnimationEnd(Animator animation) { 122a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang refreshStateHeight(); 123a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 124a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }; 125a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 126a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 127a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Interpolator from android.support.v4.view.ViewPager. Snappier and more 128a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * elastic feeling than the default interpolator. 129a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 130a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static final Interpolator INTERPOLATOR = new Interpolator() { 131a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 132a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 133a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * {@inheritDoc} 134a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 135a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 136a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public float getInterpolation(float t) { 137a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang t -= 1.0f; 138a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return t * t * t * t * t + 1.0f; 139a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 140a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }; 141a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 142a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 143a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Constructor 144a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 145a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param context The context 146a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 147a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public FmScroller(Context context) { 148a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang this(context, null); 149a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 150a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 151a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 152a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Constructor 153a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 154a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param context The context 155a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param attrs The attrs 156a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 157a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public FmScroller(Context context, AttributeSet attrs) { 158a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang this(context, attrs, 0); 159a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 160a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 161a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 162a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Constructor 163a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 164a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param context The context 165a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param attrs The attrs 166a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param defStyleAttr The default attr 167a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 168a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public FmScroller(Context context, AttributeSet attrs, int defStyleAttr) { 169a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang super(context, attrs, defStyleAttr); 170a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 171a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final ViewConfiguration configuration = ViewConfiguration.get(context); 172a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setFocusable(false); 173a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 174a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Drawing must be enabled in order to support EdgeEffect 175a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setWillNotDraw(/* willNotDraw = */false); 176a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 177a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEdgeGlowBottom = new EdgeEffect(context); 178a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScroller = new Scroller(context, INTERPOLATOR); 179a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mTouchSlop = configuration.getScaledTouchSlop(); 180a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 181a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 182a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 183a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final TypedArray attributeArray = context.obtainStyledAttributes(new int[] { 184a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang android.R.attr.actionBarSize 185a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }); 186a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mActionBarSize = attributeArray.getDimensionPixelSize(0, 0); 187a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang attributeArray.recycle(); 188a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 189a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 190a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 191a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * This method must be called inside the Activity's OnCreate. 192a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 193a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void initialize() { 194a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScrollView = (ScrollView) findViewById(R.id.content_scroller); 195a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScrollViewChild = findViewById(R.id.favorite_container); 196a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mHeader = findViewById(R.id.main_header_parent); 197a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 198a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMainHandler = new Handler(Looper.getMainLooper()); 199a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 200a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFavoriteText = (TextView) findViewById(R.id.favorite_text); 201a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mGridView = (GridView) findViewById(R.id.gridview); 202a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter = new FavoriteAdapter(getContext()); 203a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 204a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdjuster = new Adjuster(getContext()); 205a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 206a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mGridView.setAdapter(mAdapter); 207a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Cursor c = getData(); 208a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter.swipResult(c); 209a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mGridView.setFocusable(false); 210a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mGridView.setFocusableInTouchMode(false); 211a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 212a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mGridView.setOnItemClickListener(new OnItemClickListener() { 213a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 214a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 215a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 216a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mEventListener != null && mAdapter != null) { 217a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEventListener.onPlay(mAdapter.getFrequency(position)); 218a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 219a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 220a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMainHandler.removeCallbacks(null); 221a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMainHandler.postDelayed(new Runnable() { 222a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 223a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void run() { 224a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMaximumHeaderHeight = getMaxHeight(STATE_HAS_FAVORITE); 225a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang expandHeader(); 226a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 227a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }, ON_PLAY_ANIMATION_DELAY); 228a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 229a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 230a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }); 231a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 232a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Called when first time create activity 233a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang doOnPreDraw(this, /* drawNextFrame = */false, new Runnable() { 234a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 235a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void run() { 236a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang refreshStateHeight(); 237a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setHeaderHeight(getMaximumScrollableHeaderHeight()); 238a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang updateHeaderTextAndButton(); 239a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang refreshFavoriteLayout(); 240a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 241a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }); 242a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 243a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 244a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 245a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Runs a piece of code just before the next draw, after layout and measurement 246a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 247a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param view The view depend on 248a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param drawNextFrame Whether to draw next frame 249a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param runnable The executed runnable instance 250a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 251a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void doOnPreDraw(final View view, final boolean drawNextFrame, 252a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final Runnable runnable) { 253a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final OnPreDrawListener listener = new OnPreDrawListener() { 254a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 255a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public boolean onPreDraw() { 256a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang view.getViewTreeObserver().removeOnPreDrawListener(this); 257a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang runnable.run(); 258a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return drawNextFrame; 259a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 260a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }; 261a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang view.getViewTreeObserver().addOnPreDrawListener(listener); 262a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 263a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 264a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void refreshFavoriteLayout() { 265a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setFavoriteTextHeight(mAdapter.getCount() == 0); 266a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setGridViewHeight(computeGridViewHeight()); 267a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 268a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 269a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void setFavoriteTextHeight(boolean show) { 270a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mAdapter.getCount() == 0) { 271a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFavoriteText.setVisibility(View.GONE); 272a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 273a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFavoriteText.setVisibility(View.VISIBLE); 274a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 275a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 276a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 277a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void setGridViewHeight(int height) { 278a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final ViewGroup.LayoutParams params = mGridView.getLayoutParams(); 279a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang params.height = height; 280a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mGridView.setLayoutParams(params); 281a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 282a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 283a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int computeGridViewHeight() { 284a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int itemcount = mAdapter.getCount(); 285a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (itemcount == 0) { 286a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return 0; 287a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 288a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int curOrientation = getResources().getConfiguration().orientation; 289a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final boolean isLandscape = curOrientation == Configuration.ORIENTATION_LANDSCAPE; 290a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int columnNum = isLandscape ? LAND_COLUMN_NUM : PORT_COLUMN_NUM; 291a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int itemHeight = (int) getResources().getDimension(R.dimen.fm_gridview_item_height); 292a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int itemPadding = (int) getResources().getDimension(R.dimen.fm_gridview_item_padding); 293a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int rownum = (int) Math.ceil(itemcount / (float) columnNum); 294a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int totalHeight = rownum * itemHeight + rownum * itemPadding; 295a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (rownum == 2) { 296a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int minGridViewHeight = getHeight() - getMinHeight(STATE_HAS_FAVORITE) - 72; 297a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang totalHeight = Math.max(totalHeight, minGridViewHeight); 298a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 299a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 300a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return totalHeight; 301a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 302a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 303a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 304a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public boolean onInterceptTouchEvent(MotionEvent event) { 305a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // The only time we want to intercept touch events is when we are being 306a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // dragged. 307a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return shouldStartDrag(event); 308a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 309a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 310a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private boolean shouldStartDrag(MotionEvent event) { 311a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mIsBeingDragged) { 312a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mIsBeingDragged = false; 313a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return false; 314a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 315a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 316a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang switch (event.getAction()) { 317a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // If we are in the middle of a fling and there is a down event, 318a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // we'll steal it and 319a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // start a drag. 320a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case MotionEvent.ACTION_DOWN: 321a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang updateLastEventPosition(event); 322a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!mScroller.isFinished()) { 323a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang startDrag(); 324a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return true; 325a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 326a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mReceivedDown = true; 327a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 328a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 329a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 330a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Otherwise, we will start a drag if there is enough motion in the 331a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // direction we are 332a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // capable of scrolling. 333a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case MotionEvent.ACTION_MOVE: 334a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (motionShouldStartDrag(event)) { 335a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang updateLastEventPosition(event); 336a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang startDrag(); 337a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return true; 338a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 339a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 340a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 341a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang default: 342a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 343a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 344a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 345a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return false; 346a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 347a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 348a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 349a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public boolean onTouchEvent(MotionEvent event) { 350a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int action = event.getAction(); 351a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 352a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mVelocityTracker == null) { 353a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mVelocityTracker = VelocityTracker.obtain(); 354a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 355a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mVelocityTracker.addMovement(event); 356a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!mIsBeingDragged) { 357a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (shouldStartDrag(event)) { 358a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return true; 359a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 360a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 361a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (action == MotionEvent.ACTION_UP && mReceivedDown) { 362a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mReceivedDown = false; 363a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return performClick(); 364a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 365a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return true; 366a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 367a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 368a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang switch (action) { 369a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case MotionEvent.ACTION_MOVE: 370a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final float delta = updatePositionAndComputeDelta(event); 371a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang scrollTo(0, getScroll() + (int) delta); 372a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mReceivedDown = false; 373a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 374a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mIsBeingDragged) { 375a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int distanceFromMaxScrolling = getMaximumScrollUpwards() - getScroll(); 376a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (delta > distanceFromMaxScrolling) { 377a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // The ScrollView is being pulled upwards while there is 378a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // no more 379a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // content offscreen, and the view port is already fully 380a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // expanded. 381a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEdgeGlowBottom.onPull(delta / getHeight(), 1 - event.getX() / getWidth()); 382a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 383a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 384a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!mEdgeGlowBottom.isFinished()) { 385a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang postInvalidateOnAnimation(); 386a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 387a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 388a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 389a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 390a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 391a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case MotionEvent.ACTION_UP: 392a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case MotionEvent.ACTION_CANCEL: 393a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang stopDrag(action == MotionEvent.ACTION_CANCEL); 394a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mReceivedDown = false; 395a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 396a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 397a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang default: 398a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 399a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 400a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 401a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return true; 402a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 403a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 404a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 405a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Expand to maximum size or starting size. Disable clicks on the 406a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * photo until the animation is complete. 407a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 408a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void expandHeader() { 409a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (getHeaderHeight() != mMaximumHeaderHeight) { 410a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Expand header 411a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final ObjectAnimator animator = ObjectAnimator.ofInt(this, "headerHeight", 412a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMaximumHeaderHeight); 413a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang animator.addListener(mHeaderExpandAnimationListener); 414a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang animator.setDuration(300); 415a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang animator.start(); 416a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Scroll nested scroll view to its top 417a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mScrollView.getScrollY() != 0) { 418a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang ObjectAnimator.ofInt(mScrollView, "scrollY", 0).setDuration(300).start(); 419a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 420a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 421a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 422a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 423a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void collapseHeader() { 424a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (getHeaderHeight() != mMinimumHeaderHeight) { 425a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final ObjectAnimator animator = ObjectAnimator.ofInt(this, "headerHeight", 426a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMinimumHeaderHeight); 427a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang animator.addListener(mHeaderExpandAnimationListener); 428a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang animator.start(); 429a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 430a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 431a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 432a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void startDrag() { 433a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mIsBeingDragged = true; 434a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScroller.abortAnimation(); 435a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 436a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 437a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void stopDrag(boolean cancelled) { 438a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mIsBeingDragged = false; 439a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!cancelled && getChildCount() > 0) { 440a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final float velocity = getCurrentVelocity(); 441a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (velocity > mMinimumVelocity || velocity < -mMinimumVelocity) { 442a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang fling(-velocity); 443a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 444a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 445a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 446a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mVelocityTracker != null) { 447a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mVelocityTracker.recycle(); 448a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mVelocityTracker = null; 449a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 450a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 451a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEdgeGlowBottom.onRelease(); 452a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 453a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 454a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 455a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void scrollTo(int x, int y) { 456a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int delta = y - getScroll(); 457a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (delta > 0) { 458a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang scrollUp(delta); 459a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 460a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang scrollDown(delta); 461a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 462a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang updateHeaderTextAndButton(); 463a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 464a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 465a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getToolbarHeight() { 466a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return mHeader.getLayoutParams().height; 467a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 468a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 469a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 470a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Set the height of the toolbar and update its tint accordingly. 471a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 472a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @FmReflection 473a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void setHeaderHeight(int height) { 474a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final ViewGroup.LayoutParams toolbarLayoutParams = mHeader.getLayoutParams(); 475a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang toolbarLayoutParams.height = height; 476a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mHeader.setLayoutParams(toolbarLayoutParams); 477a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang updateHeaderTextAndButton(); 478a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 479a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 480a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 481a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Get header height. Used in ObjectAnimator 482a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 483a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @return The header height 484a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 485a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @FmReflection 486a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public int getHeaderHeight() { 487a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return mHeader.getLayoutParams().height; 488a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 489a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 490a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 491a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Set scroll. Used in ObjectAnimator 492a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 493a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @FmReflection 494a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void setScroll(int scroll) { 495a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang scrollTo(0, scroll); 496a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 497a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 498a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 499a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Returns the total amount scrolled inside the nested ScrollView + the amount 500a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * of shrinking performed on the ToolBar. This is the value inspected by animators. 501a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 502a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @FmReflection 503a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public int getScroll() { 504a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return getMaximumScrollableHeaderHeight() - getToolbarHeight() + mScrollView.getScrollY(); 505a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 506a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 507a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getMaximumScrollableHeaderHeight() { 508a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return mMaximumHeaderHeight; 509a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 510a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 511a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 512a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * A variant of {@link #getScroll} that pretends the header is never 513a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * larger than than mIntermediateHeaderHeight. This function is sometimes 514a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * needed when making scrolling decisions that will not change the header 515a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * size (ie, snapping to the bottom or top). When mIsOpenContactSquare is 516a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * true, this function considers mIntermediateHeaderHeight == mMaximumHeaderHeight, 517a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * since snapping decisions will be made relative the full header size when 518a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * mIsOpenContactSquare = true. This value should never be used in conjunction 519a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * with {@link #getScroll} values. 520a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 521a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getScrollIgnoreOversizedHeaderForSnapping() { 522a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return Math.max(getMaximumScrollableHeaderHeight() - getToolbarHeight(), 0) 523a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang + mScrollView.getScrollY(); 524a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 525a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 526a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 527a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Return amount of scrolling needed in order for all the visible 528a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * subviews to scroll off the bottom. 529a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 530a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getScrollUntilOffBottom() { 531a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return getHeight() + getScrollIgnoreOversizedHeaderForSnapping(); 532a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 533a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 534a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 535a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void computeScroll() { 536a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mScroller.computeScrollOffset()) { 537a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Examine the fling results in order to activate EdgeEffect when we 538a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // fling to the end. 539a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int oldScroll = getScroll(); 540a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang scrollTo(0, mScroller.getCurrY()); 541a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int delta = mScroller.getCurrY() - oldScroll; 542a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int distanceFromMaxScrolling = getMaximumScrollUpwards() - getScroll(); 543a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (delta > distanceFromMaxScrolling && distanceFromMaxScrolling > 0) { 544a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity()); 545a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 546a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 547a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!awakenScrollBars()) { 548a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Keep on drawing until the animation has finished. 549a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang postInvalidateOnAnimation(); 550a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 551a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mScroller.getCurrY() >= getMaximumScrollUpwards()) { 552a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScroller.abortAnimation(); 553a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 554a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 555a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 556a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 557a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 558a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void draw(Canvas canvas) { 559a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang super.draw(canvas); 560a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 561a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!mEdgeGlowBottom.isFinished()) { 562a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int restoreCount = canvas.save(); 563a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int width = getWidth() - getPaddingLeft() - getPaddingRight(); 564a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int height = getHeight(); 565a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 566a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Draw the EdgeEffect on the bottom of the Window (Or a little bit 567a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // below the bottom 568a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // of the Window if we start to scroll upwards while EdgeEffect is 569a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // visible). This 570a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // does not need to consider the case where this MultiShrinkScroller 571a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // doesn't fill 572a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // the Window, since the nested ScrollView should be set to 573a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // fillViewport. 574a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang canvas.translate(-width + getPaddingLeft(), height + getMaximumScrollUpwards() 575a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang - getScroll()); 576a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 577a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang canvas.rotate(180, width, 0); 578a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEdgeGlowBottom.setSize(width, height); 579a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mEdgeGlowBottom.draw(canvas)) { 580a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang postInvalidateOnAnimation(); 581a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 582a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang canvas.restoreToCount(restoreCount); 583a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 584a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 585a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 586a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private float getCurrentVelocity() { 587a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mVelocityTracker == null) { 588a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return 0; 589a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 590a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND, mMaximumVelocity); 591a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return mVelocityTracker.getYVelocity(); 592a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 593a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 594a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void fling(float velocity) { 595a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // For reasons I do not understand, scrolling is less janky when 596a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // maxY=Integer.MAX_VALUE 597a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // then when maxY is set to an actual value. 598a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScroller.fling(0, getScroll(), 0, (int) velocity, 0, 0, -Integer.MAX_VALUE, 599a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Integer.MAX_VALUE); 600a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang invalidate(); 601a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 602a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 603a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getMaximumScrollUpwards() { 604a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return // How much the Header view can compress 605a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang getMaximumScrollableHeaderHeight() - getFullyCompressedHeaderHeight() 606a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // How much the ScrollView can scroll. 0, if child is 607a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // smaller than ScrollView. 608a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang + Math.max(0, mScrollViewChild.getHeight() - getHeight() 609a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang + getFullyCompressedHeaderHeight()); 610a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 611a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 612a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void scrollUp(int delta) { 613a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final ViewGroup.LayoutParams toolbarLayoutParams = mHeader.getLayoutParams(); 614a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (toolbarLayoutParams.height > getFullyCompressedHeaderHeight()) { 615a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int originalValue = toolbarLayoutParams.height; 616a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang toolbarLayoutParams.height -= delta; 617a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang toolbarLayoutParams.height = Math.max(toolbarLayoutParams.height, 618a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang getFullyCompressedHeaderHeight()); 619a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mHeader.setLayoutParams(toolbarLayoutParams); 620a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang delta -= originalValue - toolbarLayoutParams.height; 621a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 622a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScrollView.scrollBy(0, delta); 623a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 624a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 625a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 626a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Returns the minimum size that we want to compress the header to, 627a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * given that we don't want to allow the the ScrollView to scroll 628a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * unless there is new content off of the edge of ScrollView. 629a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 630a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getFullyCompressedHeaderHeight() { 631a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int height = Math.min(Math.max(mHeader.getLayoutParams().height 632a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang - getOverflowingChildViewSize(), mMinimumHeaderHeight), 633a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang getMaximumScrollableHeaderHeight()); 634a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return height; 635a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 636a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 637a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 638a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Returns the amount of mScrollViewChild that doesn't fit inside its parent. Outside size 639a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 640a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getOverflowingChildViewSize() { 641a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int usedScrollViewSpace = mScrollViewChild.getHeight(); 642a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return -getHeight() + usedScrollViewSpace + mHeader.getLayoutParams().height; 643a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 644a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 645a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void scrollDown(int delta) { 646a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mScrollView.getScrollY() > 0) { 647a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int originalValue = mScrollView.getScrollY(); 648a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mScrollView.scrollBy(0, delta); 649a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 650a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 651a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 652a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void updateHeaderTextAndButton() { 653a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdjuster.handleScroll(); 654a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 655a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 656a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void updateLastEventPosition(MotionEvent event) { 657a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mLastEventPosition[0] = event.getX(); 658a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mLastEventPosition[1] = event.getY(); 659a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 660a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 661a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private boolean motionShouldStartDrag(MotionEvent event) { 662a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final float deltaX = event.getX() - mLastEventPosition[0]; 663a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final float deltaY = event.getY() - mLastEventPosition[1]; 664a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final boolean draggedX = (deltaX > mTouchSlop || deltaX < -mTouchSlop); 665a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final boolean draggedY = (deltaY > mTouchSlop || deltaY < -mTouchSlop); 666a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return draggedY && !draggedX; 667a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 668a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 669a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private float updatePositionAndComputeDelta(MotionEvent event) { 670a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int vertical = 1; 671a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final float position = mLastEventPosition[vertical]; 672a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang updateLastEventPosition(event); 673a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return position - mLastEventPosition[vertical]; 674a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 675a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 676a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 677a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Interpolator that enforces a specific starting velocity. 678a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * This is useful to avoid a discontinuity between dragging 679a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * speed and flinging speed. Similar to a 680a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * {@link android.view.animation.AccelerateInterpolator} in 681a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * the sense that getInterpolation() is a quadratic function. 682a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 683a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private static class AcceleratingFlingInterpolator implements Interpolator { 684a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 685a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final float mStartingSpeedPixelsPerFrame; 686a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 687a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final float mDurationMs; 688a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 689a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mPixelsDelta; 690a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 691a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final float mNumberFrames; 692a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 693a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public AcceleratingFlingInterpolator(int durationMs, float startingSpeedPixelsPerSecond, 694a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int pixelsDelta) { 695a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStartingSpeedPixelsPerFrame = startingSpeedPixelsPerSecond / getRefreshRate(); 696a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mDurationMs = durationMs; 697a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPixelsDelta = pixelsDelta; 698a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mNumberFrames = mDurationMs / getFrameIntervalMs(); 699a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 700a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 701a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 702a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public float getInterpolation(float input) { 703a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final float animationIntervalNumber = mNumberFrames * input; 704a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final float linearDelta = (animationIntervalNumber * mStartingSpeedPixelsPerFrame) 705a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / mPixelsDelta; 706a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Add the results of a linear interpolator (with the initial speed) 707a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // with the 708a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // results of a AccelerateInterpolator. 709a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mStartingSpeedPixelsPerFrame > 0) { 710a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return Math.min(input * input + linearDelta, 1); 711a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 712a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Initial fling was in the wrong direction, make sure that the 713a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // quadratic component 714a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // grows faster in order to make up for this. 715a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return Math.min(input * (input - linearDelta) + linearDelta, 1); 716a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 717a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 718a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 719a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private float getRefreshRate() { 720a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo( 721a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Display.DEFAULT_DISPLAY); 722be90b9dd03b98eacd3801018cc23555b9eeeef98P.Y. Laligand return di.getMode().getRefreshRate(); 723a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 724a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 725a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public long getFrameIntervalMs() { 726a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return (long) (1000 / getRefreshRate()); 727a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 728a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 729a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 730a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getMaxHeight(int state) { 731a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int height = 0; 732a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang switch (state) { 733a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case STATE_NO_FAVORITE: 734a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang height = getHeight(); 735a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 736a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case STATE_HAS_FAVORITE: 737a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang height = (int) getResources().getDimension(R.dimen.fm_main_header_big); 738a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 739a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang default: 740a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 741a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 742a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return height; 743a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 744a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 745a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private int getMinHeight(int state) { 746a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int height = 0; 747a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang switch (state) { 748a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case STATE_NO_FAVORITE: 749a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang height = (int) getResources().getDimension(R.dimen.fm_main_header_big); 750a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 751a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case STATE_HAS_FAVORITE: 752a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang height = (int) getResources().getDimension(R.dimen.fm_main_header_small); 753a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 754a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang default: 755a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 756a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 757a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return height; 758a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 759a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 760a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void setMinHeight(int height) { 761a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMinimumHeaderHeight = height; 762a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 763a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 764a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang class FavoriteAdapter extends BaseAdapter { 765a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private Cursor mCursor; 766a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 767a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private LayoutInflater mInflater; 768a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 769a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public FavoriteAdapter(Context context) { 770a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mInflater = LayoutInflater.from(context); 771a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 772a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 773a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public int getFrequency(int position) { 774a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mCursor != null && mCursor.moveToFirst()) { 775a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mCursor.moveToPosition(position); 776a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return mCursor.getInt(mCursor.getColumnIndex(FmStation.Station.FREQUENCY)); 777a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 778a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return 0; 779a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 780a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 781a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void swipResult(Cursor cursor) { 782a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (null != mCursor) { 783a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mCursor.close(); 784a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 785a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mCursor = cursor; 786a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang notifyDataSetChanged(); 787a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 788a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 789a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 790a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public int getCount() { 791a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (null != mCursor) { 792a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return mCursor.getCount(); 793a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 794a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return 0; 795a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 796a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 797a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 798a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public Object getItem(int position) { 799a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return null; 800a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 801a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 802a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 803a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public long getItemId(int position) { 804a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return 0; 805a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 806a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 807a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 808a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public View getView(int position, View convertView, ViewGroup parent) { 809a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang ViewHolder viewHolder = null; 810a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (null == convertView) { 811a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder = new ViewHolder(); 812a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang convertView = mInflater.inflate(R.layout.favorite_gridview_item, null); 813a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationFreq = (TextView) convertView.findViewById(R.id.station_freq); 814a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mPlayIndicator = (FmVisualizerView) convertView 815a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .findViewById(R.id.fm_play_indicator); 816a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationName = (TextView) convertView.findViewById(R.id.station_name); 817a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mMoreButton = (ImageView) convertView.findViewById(R.id.station_more); 818a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mPopupMenuAnchor = convertView.findViewById(R.id.popupmenu_anchor); 819a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang convertView.setTag(viewHolder); 820a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 821a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder = (ViewHolder) convertView.getTag(); 822a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 823a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 824a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mCursor != null && mCursor.moveToPosition(position)) { 825a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int stationFreq = mCursor.getInt(mCursor 826a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getColumnIndex(FmStation.Station.FREQUENCY)); 827a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang String name = mCursor.getString(mCursor 828a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getColumnIndex(FmStation.Station.STATION_NAME)); 829a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang String rds = mCursor.getString(mCursor 830a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getColumnIndex(FmStation.Station.RADIO_TEXT)); 831a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final int isFavorite = mCursor.getInt(mCursor 832a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getColumnIndex(FmStation.Station.IS_FAVORITE)); 833a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 834a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (null == name || "".equals(name)) { 835a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang name = mCursor.getString(mCursor 836a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getColumnIndex(FmStation.Station.PROGRAM_SERVICE)); 837a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 838a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (null == name || "".equals(name)) { 839a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang name = ""; 840a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 841a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 842a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationFreq.setText(FmUtils.formatStation(stationFreq)); 843a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationName.setText(name); 844a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 845a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mCurrentStation == stationFreq) { 846a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mPlayIndicator.setVisibility(View.VISIBLE); 847a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mIsFmPlaying) { 848a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mPlayIndicator.startAnimation(); 849a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 850a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mPlayIndicator.stopAnimation(); 851a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 852a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationFreq.setTextColor(Color.parseColor("#607D8B")); 853a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationFreq.setAlpha(1f); 854a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationName.setMaxLines(1); 855a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 856a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mPlayIndicator.setVisibility(View.GONE); 857a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mPlayIndicator.stopAnimation(); 858a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationFreq.setTextColor(Color.parseColor("#000000")); 859a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationFreq.setAlpha(0.87f); 860a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mStationName.setMaxLines(2); 861a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 862a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 863a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mMoreButton.setTag(viewHolder.mPopupMenuAnchor); 864a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang viewHolder.mMoreButton.setOnClickListener(new OnClickListener() { 865a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 866a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void onClick(View v) { 867a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Use anchor view to fix PopupMenu postion and cover more button 868a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang View anchor = v; 869a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (v.getTag() != null) { 870a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang anchor = (View) v.getTag(); 871a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 872a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang showPopupMenu(anchor, stationFreq); 873a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 874a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }); 875a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 876a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 877a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return convertView; 878a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 879a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 880a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 881a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private Cursor getData() { 882a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Cursor cursor = getContext().getContentResolver().query(Station.CONTENT_URI, 883a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang FmStation.COLUMNS, mSelection, mSelectionArgs, 884a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang FmStation.Station.FREQUENCY); 885a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return cursor; 886a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 887a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 888a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 889a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Called when FmRadioActivity.onResume(), refresh layout 890a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 891a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void onResume() { 892a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Cursor c = getData(); 893a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter.swipResult(c); 894a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mFirstOnResume) { 895a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFirstOnResume = false; 896a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 897a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang refreshStateHeight(); 898a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang updateHeaderTextAndButton(); 899a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang refreshFavoriteLayout(); 900a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 901a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int curOrientation = getResources().getConfiguration().orientation; 902a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang final boolean isLandscape = curOrientation == Configuration.ORIENTATION_LANDSCAPE; 903a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int columnNum = isLandscape ? LAND_COLUMN_NUM : PORT_COLUMN_NUM; 904a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang boolean isOneRow = c.getCount() <= columnNum; 905a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 906a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang boolean hasFavoriteCurrent = c.getCount() > 0; 907a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mHasFavoriteWhenOnPause != hasFavoriteCurrent || isOneRow) { 908a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setHeaderHeight(getMaximumScrollableHeaderHeight()); 909a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 910a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 911a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 912a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 913a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private boolean mHasFavoriteWhenOnPause = false; 914a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 915a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 916a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Called when FmRadioActivity.onPause() 917a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 918a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void onPause() { 919a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mAdapter != null && mAdapter.getCount() > 0) { 920a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mHasFavoriteWhenOnPause = true; 921a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 922a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mHasFavoriteWhenOnPause = false; 923a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 924a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 925a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 926a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 927a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Notify refresh adapter when data change 928a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 929a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void notifyAdatperChange() { 930a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Cursor c = getData(); 931a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter.swipResult(c); 932a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 933a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 934a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void refreshStateHeight() { 935a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mAdapter != null && mAdapter.getCount() > 0) { 936a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMaximumHeaderHeight = getMaxHeight(STATE_HAS_FAVORITE); 937a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMinimumHeaderHeight = getMinHeight(STATE_HAS_FAVORITE); 938a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 939a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMaximumHeaderHeight = getMaxHeight(STATE_NO_FAVORITE); 940a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMinimumHeaderHeight = getMinHeight(STATE_NO_FAVORITE); 941a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 942a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 943a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 944a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 945a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Called when add a favorite 946a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 947a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void onAddFavorite() { 948a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Cursor c = getData(); 949a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter.swipResult(c); 950a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang refreshFavoriteLayout(); 951a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (c.getCount() == 1) { 952a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Last time count is 0, so need set STATE_NO_FAVORITE then collapse header 953a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMinimumHeaderHeight = getMinHeight(STATE_NO_FAVORITE); 954a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMaximumHeaderHeight = getMaxHeight(STATE_NO_FAVORITE); 955a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang collapseHeader(); 956a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 957a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 958a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 959a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 960a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Called when remove a favorite 961a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 962a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void onRemoveFavorite() { 963a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Cursor c = getData(); 964a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter.swipResult(c); 965a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang refreshFavoriteLayout(); 966a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (c != null && c.getCount() == 0) { 967a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Stop the play animation 968a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMainHandler.removeCallbacks(null); 969a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 970a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Last time count is 1, so need set STATE_NO_FAVORITE then expand header 971a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMinimumHeaderHeight = getMinHeight(STATE_NO_FAVORITE); 972a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mMaximumHeaderHeight = getMaxHeight(STATE_NO_FAVORITE); 973a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang expandHeader(); 974a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 975a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 976a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 977a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void showPopupMenu(View anchor, final int frequency) { 978a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang dismissPopupMenu(); 979a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPopupMenu = new PopupMenu(getContext(), anchor); 980a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Menu menu = mPopupMenu.getMenu(); 981a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPopupMenu.getMenuInflater().inflate(R.menu.gridview_item_more_menu, menu); 982a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPopupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() { 983a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 984a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public boolean onMenuItemClick(MenuItem item) { 985a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang switch (item.getItemId()) { 986a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case R.id.remove_favorite: 987a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mEventListener != null) { 988a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEventListener.onRemoveFavorite(frequency); 989a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 990a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 991a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang case R.id.rename: 992a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mEventListener != null) { 993a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEventListener.onRename(frequency); 994a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 995a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 996a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang default: 997a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang break; 998a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 999a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return false; 1000a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1001a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang }); 1002a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPopupMenu.show(); 1003a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1004a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1005a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void dismissPopupMenu() { 1006a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mPopupMenu != null) { 1007a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPopupMenu.dismiss(); 1008a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPopupMenu = null; 1009a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1010a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1011a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1012a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1013a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Called when FmRadioActivity.onDestory() 1014a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1015a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void closeAdapterCursor() { 1016a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter.swipResult(null); 1017a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1018a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1019a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1020a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Register a listener for GridView item event 1021a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 1022a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param listener The event listener 1023a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1024a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void registerListener(EventListener listener) { 1025a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEventListener = listener; 1026a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1027a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1028a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1029a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Unregister a listener for GridView item event 1030a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 1031a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param listener The event listener 1032a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1033a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void unregisterListener(EventListener listener) { 1034a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mEventListener = null; 1035a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1036a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1037a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1038a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Listen for GridView item event: remove, rename, click play 1039a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1040a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public interface EventListener { 1041a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1042a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Callback when click remove favorite menu 1043a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 1044a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param frequency The frequency want to remove 1045a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1046a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang void onRemoveFavorite(int frequency); 1047a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1048a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1049a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Callback when click rename favorite menu 1050a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 1051a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param frequency The frequency want to rename 1052a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1053a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang void onRename(int frequency); 1054a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1055a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1056a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Callback when click gridview item to play 1057a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 1058a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param frequency The frequency want to play 1059a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1060a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang void onPlay(int frequency); 1061a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1062a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1063a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1064a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Refresh the play indicator in gridview when play station or play state change 1065a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 1066a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param currentStation current station 1067a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * @param isFmPlaying whether fm is playing 1068a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1069a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void refreshPlayIndicator(int currentStation, boolean isFmPlaying) { 1070a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mCurrentStation = currentStation; 1071a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mIsFmPlaying = isFmPlaying; 1072a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mAdapter != null) { 1073a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mAdapter.notifyDataSetChanged(); 1074a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1075a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1076a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1077a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /** 1078a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Adjust view padding and text size when scroll 1079a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1080a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private class Adjuster { 1081a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final DisplayMetrics mDisplayMetrics; 1082a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1083a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mFirstTargetHeight; 1084a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1085a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mSecondTargetHeight; 1086a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1087a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mActionBarHeight = mActionBarSize; 1088a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1089a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mStatusBarHeight; 1090a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1091a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final int mFullHeight;// display height without status bar 1092a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1093a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final float mDensity; 1094a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1095a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final Typeface mDefaultFrequencyTypeface; 1096a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1097a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Text view 1098a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private TextView mFrequencyText; 1099a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 110040cbbc57444d732004bba3c8464c979f83290279Benson Huang private TextView mFmDescriptionText; 1101a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1102a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private TextView mStationNameText; 1103a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1104a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private TextView mStationRdsText; 1105a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1106a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /* 1107a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * The five control buttons view(previous, next, increase, 1108a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * decrease, favorite) and stop button 1109a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1110a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private View mControlView; 1111a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1112a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private View mPlayButtonView; 1113a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1114a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final Context mContext; 1115a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1116a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final boolean mIsLandscape; 1117a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1118a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private FirstRangeAdjuster mFirstRangeAdjuster; 1119a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1120a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private SecondRangeAdjuster mSecondRangeAdjusterr; 1121a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1122a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public Adjuster(Context context) { 1123a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mContext = context; 1124a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mDisplayMetrics = mContext.getResources().getDisplayMetrics(); 1125a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mDensity = mDisplayMetrics.density; 1126a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int curOrientation = getResources().getConfiguration().orientation; 1127a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mIsLandscape = curOrientation == Configuration.ORIENTATION_LANDSCAPE; 1128a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Resources res = mContext.getResources(); 1129a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFirstTargetHeight = res.getDimensionPixelSize(R.dimen.fm_main_header_big); 1130a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mSecondTargetHeight = res.getDimensionPixelSize(R.dimen.fm_main_header_small); 1131a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStatusBarHeight = res 1132a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 1133a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFullHeight = mDisplayMetrics.heightPixels - mStatusBarHeight; 1134a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1135a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyText = (TextView) findViewById(R.id.station_value); 113640cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionText = (TextView) findViewById(R.id.text_fm); 1137a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameText = (TextView) findViewById(R.id.station_name); 1138a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsText = (TextView) findViewById(R.id.station_rds); 1139a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlView = findViewById(R.id.rl_imgbtnpart); 1140a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonView = findViewById(R.id.play_button_container); 1141a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1142a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFirstRangeAdjuster = new FirstRangeAdjuster(); 1143a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mSecondRangeAdjusterr = new SecondRangeAdjuster(); 1144a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlView.setMinimumWidth(mIsLandscape ? mDisplayMetrics.heightPixels 1145a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang : mDisplayMetrics.widthPixels); 1146a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mDefaultFrequencyTypeface = mFrequencyText.getTypeface(); 1147a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1148a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1149a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void handleScroll() { 1150a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int height = getHeaderHeight(); 1151a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mIsLandscape || height > mFirstTargetHeight) { 1152a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFirstRangeAdjuster.handleScroll(); 1153a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else if (height >= mSecondTargetHeight) { 1154a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mSecondRangeAdjusterr.handleScroll(); 1155a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1156a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1157a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1158a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private class FirstRangeAdjuster { 1159a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected int mTargetHeight; 1160a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1161a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // start text size and margin 116240cbbc57444d732004bba3c8464c979f83290279Benson Huang protected float mFmDescriptionTextSizeStart; 116340cbbc57444d732004bba3c8464c979f83290279Benson Huang 1164a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mFrequencyStartTextSize; 1165a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1166a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationNameTextSizeStart; 1167a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 116840cbbc57444d732004bba3c8464c979f83290279Benson Huang protected float mFmDescriptionMarginTopStart; 116940cbbc57444d732004bba3c8464c979f83290279Benson Huang 117040cbbc57444d732004bba3c8464c979f83290279Benson Huang protected float mFmDescriptionStartPaddingLeft; 1171a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1172a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mFrequencyMarginTopStart; 1173a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1174a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationNameMarginTopStart; 1175a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1176a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationRdsMarginTopStart; 1177a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1178a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mControlViewMarginTopStart; 1179a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1180a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // target text size and margin 118140cbbc57444d732004bba3c8464c979f83290279Benson Huang protected float mFmDescriptionTextSizeTarget; 118240cbbc57444d732004bba3c8464c979f83290279Benson Huang 1183a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mFrequencyTextSizeTarget; 1184a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1185a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationNameTextSizeTarget; 1186a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 118740cbbc57444d732004bba3c8464c979f83290279Benson Huang protected float mFmDescriptionMarginTopTarget; 1188a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1189a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mFrequencyMarginTopTarget; 1190a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1191a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationNameMarginTopTarget; 1192a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1193a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationRdsMarginTopTarget; 1194a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1195a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mControlViewMarginTopTarget; 1196a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1197a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mPlayButtonMarginTopStart; 1198a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1199a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mPlayButtonMarginTopTarget; 1200a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1201a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mPlayButtonHeight; 1202a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1203a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Padding adjust rate as linear 120440cbbc57444d732004bba3c8464c979f83290279Benson Huang protected float mFmDescriptionPaddingRate; 1205a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1206a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mFrequencyPaddingRate; 1207a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1208a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationNamePaddingRate; 1209a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1210a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationRdsPaddingRate; 1211a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1212a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mControlViewPaddingRate; 1213a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1214a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init it with display height 1215a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mPlayButtonPaddingRate; 1216a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1217a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // Text size adjust rate as linear 1218a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // adjust from first to target critical height 121940cbbc57444d732004bba3c8464c979f83290279Benson Huang protected float mFmDescriptionTextSizeRate; 122040cbbc57444d732004bba3c8464c979f83290279Benson Huang 1221a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mFrequencyTextSizeRate; 1222a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1223a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // adjust before first critical height 1224a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang protected float mStationNameTextSizeRate; 1225a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1226a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public FirstRangeAdjuster() { 1227a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Resources res = mContext.getResources(); 1228a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mTargetHeight = mFirstTargetHeight; 1229a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init start 123040cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionTextSizeStart = res.getDimension(R.dimen.fm_description_text_size); 1231a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyStartTextSize = res.getDimension(R.dimen.fm_frequency_text_size_start); 1232a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeStart = res 1233a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_text_size_start); 1234a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // first view, margin refer to parent 123540cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionMarginTopStart = res 1236a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_description_margin_top_start) + mActionBarHeight; 1237a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyMarginTopStart = res.getDimension(R.dimen.fm_frequency_margin_top_start); 1238a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameMarginTopStart = res 1239a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_margin_top_start); 1240a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsMarginTopStart = res 1241a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_rds_margin_top_start); 1242a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewMarginTopStart = res 1243a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_control_buttons_margin_top_start); 1244a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init target 1245a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyTextSizeTarget = res 1246a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_frequency_text_size_first_target); 124740cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionTextSizeTarget = mFrequencyTextSizeTarget; 1248a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeTarget = res 1249a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_text_size_first_target); 125040cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionMarginTopTarget = res 1251a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_description_margin_top_first_target); 125240cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionStartPaddingLeft = mFrequencyText.getPaddingLeft(); 1253a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // first view, margin refer to parent if not in landscape 1254a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!mIsLandscape) { 125540cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionMarginTopTarget += mActionBarHeight; 125640cbbc57444d732004bba3c8464c979f83290279Benson Huang } else { 125740cbbc57444d732004bba3c8464c979f83290279Benson Huang mFrequencyMarginTopStart += mActionBarHeight + mFmDescriptionTextSizeStart; 1258a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1259a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyMarginTopTarget = res 1260a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_frequency_margin_top_first_target); 1261a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameMarginTopTarget = res 1262a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_margin_top_first_target); 1263a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsMarginTopTarget = res 1264a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_rds_margin_top_first_target); 1265a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewMarginTopTarget = res 1266a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_control_buttons_margin_top_first_target); 1267a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init text size and margin adjust rate 1268a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int scrollHeight = mFullHeight - mTargetHeight; 126940cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionTextSizeRate = 127040cbbc57444d732004bba3c8464c979f83290279Benson Huang (mFmDescriptionTextSizeStart - mFmDescriptionTextSizeTarget) / scrollHeight; 1271a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyTextSizeRate = (mFrequencyStartTextSize - mFrequencyTextSizeTarget) 1272a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1273a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeRate = (mStationNameTextSizeStart - mStationNameTextSizeTarget) 1274a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 127540cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionPaddingRate = 127640cbbc57444d732004bba3c8464c979f83290279Benson Huang (mFmDescriptionMarginTopStart - mFmDescriptionMarginTopTarget) 1277a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1278a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyPaddingRate = (mFrequencyMarginTopStart - mFrequencyMarginTopTarget) 1279a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1280a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNamePaddingRate = (mStationNameMarginTopStart - mStationNameMarginTopTarget) 1281a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1282a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsPaddingRate = (mStationRdsMarginTopStart - mStationRdsMarginTopTarget) 1283a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1284a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewPaddingRate = (mControlViewMarginTopStart - mControlViewMarginTopTarget) 1285a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1286a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init play button padding, it different to others, padding top refer to parent 1287a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonHeight = res.getDimension(R.dimen.play_button_height); 1288a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonMarginTopStart = mFullHeight - mPlayButtonHeight - 16 * mDensity; 1289a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonMarginTopTarget = mFirstTargetHeight - mPlayButtonHeight / 2; 1290a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonPaddingRate = (mPlayButtonMarginTopStart - mPlayButtonMarginTopTarget) 1291a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1292a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1293a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1294a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void handleScroll() { 1295a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (mIsLandscape) { 1296a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang handleScrollLandscapeMode(); 1297a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return; 1298a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1299a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int currentHeight = getHeaderHeight(); 1300a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float newMargin = 0; 1301a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float lastHeight = 0; 1302a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float newTextSize; 1303a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 1.FM description (margin) 130440cbbc57444d732004bba3c8464c979f83290279Benson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mFmDescriptionMarginTopTarget, 130540cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionPaddingRate); 130640cbbc57444d732004bba3c8464c979f83290279Benson Huang lastHeight = setNewPadding(mFmDescriptionText, newMargin); 1307a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 2. frequency text (text size and margin) 1308a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newTextSize = getNewSize(currentHeight, mTargetHeight, mFrequencyTextSizeTarget, 1309a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyTextSizeRate); 1310a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyText.setTextSize(newTextSize / mDensity); 1311a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mFrequencyMarginTopTarget, 1312a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyPaddingRate); 1313a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = setNewPadding(mFrequencyText, newMargin + lastHeight); 1314a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 3. station name (margin and text size) 1315a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mStationNameMarginTopTarget, 1316a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNamePaddingRate); 1317a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = setNewPadding(mStationNameText, newMargin + lastHeight); 1318a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newTextSize = getNewSize(currentHeight, mTargetHeight, mStationNameTextSizeTarget, 1319a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeRate); 1320a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameText.setTextSize(newTextSize / mDensity); 1321a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 4. station rds (margin) 1322a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mStationRdsMarginTopTarget, 1323a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsPaddingRate); 1324a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = setNewPadding(mStationRdsText, newMargin + lastHeight); 1325a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 5. control buttons (margin) 1326a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mControlViewMarginTopTarget, 1327a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewPaddingRate); 1328a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewPadding(mControlView, newMargin + lastHeight); 1329a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 6. stop button (padding), it different to others, padding top refer to parent 1330a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mPlayButtonMarginTopTarget, 1331a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonPaddingRate); 1332a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewPadding(mPlayButtonView, newMargin); 1333a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1334a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1335a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void handleScrollLandscapeMode() { 1336a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int currentHeight = getHeaderHeight(); 1337a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float newMargin = 0; 1338a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float lastHeight = 0; 1339a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float newTextSize; 134040cbbc57444d732004bba3c8464c979f83290279Benson Huang // 1. FM description (color, alpha and margin) 134140cbbc57444d732004bba3c8464c979f83290279Benson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mFmDescriptionMarginTopTarget, 134240cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionPaddingRate); 134340cbbc57444d732004bba3c8464c979f83290279Benson Huang setNewPadding(mFmDescriptionText, newMargin); 134440cbbc57444d732004bba3c8464c979f83290279Benson Huang 134540cbbc57444d732004bba3c8464c979f83290279Benson Huang newTextSize = getNewSize(currentHeight, mTargetHeight, mFmDescriptionTextSizeTarget, 134640cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionTextSizeRate); 134740cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionText.setTextSize(newTextSize / mDensity); 134840cbbc57444d732004bba3c8464c979f83290279Benson Huang boolean reachTop = (mSecondTargetHeight == getHeaderHeight()); 134940cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionText.setTextColor(reachTop ? Color.WHITE 135040cbbc57444d732004bba3c8464c979f83290279Benson Huang : getResources().getColor(R.color.text_fm_color)); 135140cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionText.setAlpha(reachTop ? 0.87f : 1.0f); 135240cbbc57444d732004bba3c8464c979f83290279Benson Huang 135340cbbc57444d732004bba3c8464c979f83290279Benson Huang // 2. frequency text (text size, padding and margin) 1354a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newTextSize = getNewSize(currentHeight, mTargetHeight, mFrequencyTextSizeTarget, 1355a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyTextSizeRate); 1356a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyText.setTextSize(newTextSize / mDensity); 1357a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mFrequencyMarginTopTarget, 1358a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyPaddingRate); 135940cbbc57444d732004bba3c8464c979f83290279Benson Huang // Move frequency text like "103.7" from middle to action bar in landscape, 136040cbbc57444d732004bba3c8464c979f83290279Benson Huang // or opposite direction. For example: 136140cbbc57444d732004bba3c8464c979f83290279Benson Huang // ************************* ************************* 136240cbbc57444d732004bba3c8464c979f83290279Benson Huang // * * * FM 103.7 * 136340cbbc57444d732004bba3c8464c979f83290279Benson Huang // * FM * <--> * * 136440cbbc57444d732004bba3c8464c979f83290279Benson Huang // * 103.7 * * * 136540cbbc57444d732004bba3c8464c979f83290279Benson Huang // ************************* ************************* 136640cbbc57444d732004bba3c8464c979f83290279Benson Huang // "FM", "103.7" and other subviews are in a RelativeLayout (id actionbar_parent) 136740cbbc57444d732004bba3c8464c979f83290279Benson Huang // in main_header.xml. The position is controlled by the padding of each subview. 136840cbbc57444d732004bba3c8464c979f83290279Benson Huang // Because "FM" and "103.7" move up, we need to change the padding top and change 136940cbbc57444d732004bba3c8464c979f83290279Benson Huang // the padding left of "103.7". 137040cbbc57444d732004bba3c8464c979f83290279Benson Huang // The padding between "FM" and "103.7" is 0.2 (e.g. paddingRate) times 137140cbbc57444d732004bba3c8464c979f83290279Benson Huang // the length of "FM" string length. 137240cbbc57444d732004bba3c8464c979f83290279Benson Huang float paddingRate = 0.2f; 137340cbbc57444d732004bba3c8464c979f83290279Benson Huang float addPadding = (((1 + paddingRate) * computeFmDescriptionWidth()) 137440cbbc57444d732004bba3c8464c979f83290279Benson Huang * (mFullHeight - currentHeight)) / (mFullHeight - mTargetHeight); 137540cbbc57444d732004bba3c8464c979f83290279Benson Huang mFrequencyText.setPadding((int) (addPadding + mFmDescriptionStartPaddingLeft), 137640cbbc57444d732004bba3c8464c979f83290279Benson Huang (int) (newMargin), mFrequencyText.getPaddingRight(), 137740cbbc57444d732004bba3c8464c979f83290279Benson Huang mFrequencyText.getPaddingBottom()); 137840cbbc57444d732004bba3c8464c979f83290279Benson Huang lastHeight = newMargin + lastHeight + mFrequencyText.getTextSize(); 1379a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // If frequency text move to action bar, change it to bold 1380a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewTypefaceForFrequencyText(); 138140cbbc57444d732004bba3c8464c979f83290279Benson Huang 1382a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 3. station name (text size and margin) 1383a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newTextSize = getNewSize(currentHeight, mTargetHeight, mStationNameTextSizeTarget, 1384a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeRate); 1385a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameText.setTextSize(newTextSize / mDensity); 1386a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mStationNameMarginTopTarget, 1387a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNamePaddingRate); 1388a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // if move to target position, need not move over the edge of actionbar 1389a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (lastHeight <= mActionBarHeight) { 1390a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = mActionBarHeight; 1391a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1392a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = setNewPadding(mStationNameText, newMargin + lastHeight); 1393a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang /* 1394a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * 4. station rds (margin), in landscape with favorite 1395a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * it need parallel to station name 1396a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */ 1397a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mStationRdsMarginTopTarget, 1398a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsPaddingRate); 1399a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int targetHeight = mFullHeight - (mFullHeight - mTargetHeight) / 2; 1400a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (currentHeight <= targetHeight) { 1401a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang String stationName = "" + mStationNameText.getText(); 1402a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int stationNameTextWidth = mStationNameText.getPaddingLeft(); 1403a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (!stationName.equals("")) { 1404a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Paint paint = mStationNameText.getPaint(); 1405a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang stationNameTextWidth += (int) paint.measureText(stationName) + 8; 1406a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1407a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsText.setPadding((int) stationNameTextWidth, 1408a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang (int) (newMargin + lastHeight), mStationRdsText.getPaddingRight(), 1409a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsText.getPaddingBottom()); 1410a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else { 1411a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsText.setPadding((int) (16 * mDensity), 1412a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang (int) (newMargin + lastHeight), mStationRdsText.getPaddingRight(), 1413a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsText.getPaddingBottom()); 1414a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1415a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 5. control buttons (margin) 1416a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mControlViewMarginTopTarget, 1417a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewPaddingRate); 1418a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewPadding(mControlView, newMargin + lastHeight); 1419a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 6. stop button (padding), it different to others, padding top refer to parent 1420a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mPlayButtonMarginTopTarget, 1421a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonPaddingRate); 1422a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewPadding(mPlayButtonView, newMargin); 1423a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 142440cbbc57444d732004bba3c8464c979f83290279Benson Huang 142540cbbc57444d732004bba3c8464c979f83290279Benson Huang // Compute the text "FM" width 142640cbbc57444d732004bba3c8464c979f83290279Benson Huang private float computeFmDescriptionWidth() { 142740cbbc57444d732004bba3c8464c979f83290279Benson Huang Paint paint = mFmDescriptionText.getPaint(); 142840cbbc57444d732004bba3c8464c979f83290279Benson Huang return (float) paint.measureText(mFmDescriptionText.getText().toString()); 142940cbbc57444d732004bba3c8464c979f83290279Benson Huang } 1430a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1431a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1432a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private class SecondRangeAdjuster extends FirstRangeAdjuster { 1433a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public SecondRangeAdjuster() { 1434a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang Resources res = mContext.getResources(); 1435a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mTargetHeight = mSecondTargetHeight; 1436a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init start 1437a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyStartTextSize = res 1438a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_frequency_text_size_first_target); 1439a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeStart = res 1440a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_text_size_first_target); 144140cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionMarginTopStart = res 1442a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_description_margin_top_first_target) 1443a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang + mActionBarHeight;// first view, margin refer to parent 1444a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyMarginTopStart = res 1445a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_frequency_margin_top_first_target); 1446a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameMarginTopStart = res 1447a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_margin_top_first_target); 1448a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsMarginTopStart = res 1449a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_rds_margin_top_first_target); 1450a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewMarginTopStart = res 1451a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_control_buttons_margin_top_first_target); 1452a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init target 1453a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyTextSizeTarget = res 1454a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_frequency_text_size_second_target); 1455a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeTarget = res 1456a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_text_size_second_target); 145740cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionMarginTopTarget = res 1458a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_description_margin_top_second_target); 1459a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyMarginTopTarget = res 1460a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_frequency_margin_top_second_target); 1461a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameMarginTopTarget = res 1462a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_name_margin_top_second_target); 1463a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsMarginTopTarget = res 1464a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_station_rds_margin_top_second_target); 1465a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewMarginTopTarget = res 1466a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang .getDimension(R.dimen.fm_control_buttons_margin_top_second_target); 1467a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init text size and margin adjust rate 1468a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float scrollHeight = mFirstTargetHeight - mTargetHeight; 1469a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyTextSizeRate = 1470a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang (mFrequencyStartTextSize - mFrequencyTextSizeTarget) 1471a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1472a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeRate = 1473a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang (mStationNameTextSizeStart - mStationNameTextSizeTarget) 1474a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 147540cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionPaddingRate = 147640cbbc57444d732004bba3c8464c979f83290279Benson Huang (mFmDescriptionMarginTopStart - mFmDescriptionMarginTopTarget) 147740cbbc57444d732004bba3c8464c979f83290279Benson Huang 1478a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1479a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyPaddingRate = (mFrequencyMarginTopStart - mFrequencyMarginTopTarget) 1480a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1481a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNamePaddingRate = (mStationNameMarginTopStart - mStationNameMarginTopTarget) 1482a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1483a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsPaddingRate = (mStationRdsMarginTopStart - mStationRdsMarginTopTarget) 1484a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1485a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewPaddingRate = (mControlViewMarginTopStart - mControlViewMarginTopTarget) 1486a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1487a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // init play button padding, it different to others, padding top refer to parent 1488a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonHeight = res.getDimension(R.dimen.play_button_height); 1489a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonMarginTopStart = mFullHeight - mPlayButtonHeight - 16 * mDensity; 1490a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonMarginTopTarget = mFirstTargetHeight - mPlayButtonHeight / 2; 1491a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mPlayButtonPaddingRate = (mPlayButtonMarginTopStart - mPlayButtonMarginTopTarget) 1492a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang / scrollHeight; 1493a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1494a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1495a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang @Override 1496a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang public void handleScroll() { 1497a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int currentHeight = getHeaderHeight(); 1498a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float newMargin = 0; 1499a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float lastHeight = 0; 1500a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float newTextSize; 1501a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 1. FM description (alpha and margin) 1502a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float alpha = 0f; 1503a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang int offset = (int) ((mFirstTargetHeight - currentHeight) / mDensity);// dip 1504a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (offset <= 0) { 1505a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang alpha = 1f; 1506a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } else if (offset <= 16) { 1507a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang alpha = 1 - offset / 16f; 1508a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 150940cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionText.setAlpha(alpha); 151040cbbc57444d732004bba3c8464c979f83290279Benson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mFmDescriptionMarginTopTarget, 151140cbbc57444d732004bba3c8464c979f83290279Benson Huang mFmDescriptionPaddingRate); 151240cbbc57444d732004bba3c8464c979f83290279Benson Huang lastHeight = setNewPadding(mFmDescriptionText, newMargin); 1513a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 2. frequency text (text size and margin) 1514a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newTextSize = getNewSize(currentHeight, mTargetHeight, mFrequencyTextSizeTarget, 1515a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyTextSizeRate); 1516a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyText.setTextSize(newTextSize / mDensity); 1517a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mFrequencyMarginTopTarget, 1518a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyPaddingRate); 1519a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = setNewPadding(mFrequencyText, newMargin + lastHeight); 1520a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // If frequency text move to action bar, change it to bold 1521a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewTypefaceForFrequencyText(); 1522a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 3. station name (text size and margin) 1523a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newTextSize = getNewSize(currentHeight, mTargetHeight, mStationNameTextSizeTarget, 1524a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameTextSizeRate); 1525a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNameText.setTextSize(newTextSize / mDensity); 1526a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mStationNameMarginTopTarget, 1527a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationNamePaddingRate); 1528a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // if move to target position, need not move over the edge of actionbar 1529a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (lastHeight <= mActionBarHeight) { 1530a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = mActionBarHeight; 1531a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1532a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = setNewPadding(mStationNameText, newMargin + lastHeight); 1533a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 4. station rds (margin) 1534a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mStationRdsMarginTopTarget, 1535a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mStationRdsPaddingRate); 1536a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang lastHeight = setNewPadding(mStationRdsText, newMargin + lastHeight); 1537a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 5. control buttons (margin) 1538a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = getNewSize(currentHeight, mTargetHeight, mControlViewMarginTopTarget, 1539a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mControlViewPaddingRate); 1540a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewPadding(mControlView, newMargin + lastHeight); 1541a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang // 6. stop button (padding), it different to others, padding top refer to parent 1542a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang newMargin = currentHeight - mPlayButtonHeight / 2; 1543a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang setNewPadding(mPlayButtonView, newMargin); 1544a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1545a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1546a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1547a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void setNewTypefaceForFrequencyText() { 1548a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang boolean needBold = (mSecondTargetHeight == getHeaderHeight()); 1549a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang mFrequencyText.setTypeface(needBold ? Typeface.SANS_SERIF : mDefaultFrequencyTypeface); 1550a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1551a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1552a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private float setNewPadding(TextView current, float newMargin) { 1553a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang current.setPadding(current.getPaddingLeft(), (int) (newMargin), 1554a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang current.getPaddingRight(), current.getPaddingBottom()); 1555a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float nextLayoutPadding = newMargin + current.getTextSize(); 1556a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return nextLayoutPadding; 1557a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1558a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1559a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private void setNewPadding(View current, float newMargin) { 1560a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float newPadding = newMargin; 1561a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang current.setPadding(current.getPaddingLeft(), (int) (newPadding), 1562a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang current.getPaddingRight(), current.getPaddingBottom()); 1563a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1564a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1565a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private float getNewSize(int currentHeight, int targetHeight, 1566a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang float targetSize, float rate) { 1567a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang if (currentHeight == targetHeight) { 1568a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return targetSize; 1569a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1570a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang return targetSize + (currentHeight - targetHeight) * rate; 1571a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1572a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1573a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang 1574a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang private final class ViewHolder { 1575a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang ImageView mMoreButton; 1576a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang FmVisualizerView mPlayIndicator; 1577a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang TextView mStationFreq; 1578a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang TextView mStationName; 1579a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang View mPopupMenuAnchor; 1580a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang } 1581a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang} 1582