1816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/* 2816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Copyright (C) 2015 The Android Open Source Project 3816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 4816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 5816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * you may not use this file except in compliance with the License. 6816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * You may obtain a copy of the License at 7816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 8816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 9816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 10816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Unless required by applicable law or agreed to in writing, software 11816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 12816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * See the License for the specific language governing permissions and 14816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * limitations under the License. 15816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 16816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 17816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopackage com.android.tv.ui; 18816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 19816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.Animator; 20816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.AnimatorListenerAdapter; 21816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.ValueAnimator; 22816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.Context; 23816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.res.Resources; 247d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.support.annotation.Nullable; 25816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.util.AttributeSet; 26816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.util.Log; 27816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.KeyEvent; 28816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.LayoutInflater; 29816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.View; 30816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.ViewGroup; 31816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.animation.AnimationUtils; 32816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.animation.Interpolator; 33816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.widget.AdapterView; 34816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.widget.BaseAdapter; 35816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.widget.LinearLayout; 36816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.widget.ListView; 37816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.widget.TextView; 38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 39816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.MainActivity; 40816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.R; 41816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.TvApplication; 426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.util.DurationTimer; 43816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.analytics.Tracker; 442e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport com.android.tv.common.SoftPreconditions; 45816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.Channel; 46816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.ChannelNumber; 47816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 48816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.ArrayList; 49816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.List; 50816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 51816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopublic class KeypadChannelSwitchView extends LinearLayout implements 52816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko TvTransitionManager.TransitionLayout { 53816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final String TAG = "KeypadChannelSwitchView"; 54816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final int MAX_CHANNEL_NUMBER_DIGIT = 4; 56816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final int MAX_MINOR_CHANNEL_NUMBER_DIGIT = 3; 57816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final int MAX_CHANNEL_ITEM = 8; 58816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final String CHANNEL_DELIMITERS_REGEX = "[-\\.\\s]"; 59816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public static final String SCREEN_NAME = "Channel switch"; 60816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 61816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final MainActivity mMainActivity; 62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Tracker mTracker; 63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final DurationTimer mViewDurationTimer = new DurationTimer(); 64816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private boolean mNavigated = false; 657d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Nullable //Once mChannels is set to null it should not be used again. 66816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private List<Channel> mChannels; 67816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private TextView mChannelNumberView; 68816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private ListView mChannelItemListView; 69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ChannelNumber mTypedChannelNumber = new ChannelNumber(); 70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ArrayList<Channel> mChannelCandidates = new ArrayList<>(); 71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected final ChannelItemAdapter mAdapter = new ChannelItemAdapter(); 72816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final LayoutInflater mLayoutInflater; 73816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private Channel mSelectedChannel; 74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Runnable mHideRunnable = new Runnable() { 76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 77816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void run() { 78816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentHeight = 0; 79816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mSelectedChannel != null) { 80816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mMainActivity.tuneToChannel(mSelectedChannel); 81816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendChannelNumberItemChosenByTimeout(); 82816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 8307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMainActivity.getOverlayManager().hideOverlays( 8407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko TvOverlayManager.FLAG_HIDE_OVERLAYS_KEEP_DIALOG 8507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko | TvOverlayManager.FLAG_HIDE_OVERLAYS_KEEP_SIDE_PANELS 8607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko | TvOverlayManager.FLAG_HIDE_OVERLAYS_KEEP_PROGRAM_GUIDE 87ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko | TvOverlayManager.FLAG_HIDE_OVERLAYS_KEEP_MENU 88ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko | TvOverlayManager.FLAG_HIDE_OVERLAYS_KEEP_FRAGMENT); 89816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 90816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 91816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }; 92816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final long mShowDurationMillis; 93816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final long mRippleAnimDurationMillis; 94816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mBaseViewHeight; 95816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mItemHeight; 96816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mResizeAnimDuration; 97816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private Animator mResizeAnimator; 98816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Interpolator mResizeInterpolator; 99816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // NOTE: getHeight() will be updated after layout() is called. mCurrentHeight is needed for 100816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // getting the latest updated value of the view height before layout(). 101816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private int mCurrentHeight; 102816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 103816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public KeypadChannelSwitchView(Context context) { 104816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko this(context, null, 0); 105816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 106816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 107816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public KeypadChannelSwitchView(Context context, AttributeSet attrs) { 108816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko this(context, attrs, 0); 109816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 110816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 111816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public KeypadChannelSwitchView(Context context, AttributeSet attrs, int defStyleAttr) { 112816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super(context, attrs, defStyleAttr); 113816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 114816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mMainActivity = (MainActivity) context; 1151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mTracker = TvApplication.getSingletons(context).getTracker(); 116816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Resources resources = getResources(); 117816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mLayoutInflater = LayoutInflater.from(context); 118816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mShowDurationMillis = resources.getInteger(R.integer.keypad_channel_switch_show_duration); 119816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mRippleAnimDurationMillis = resources.getInteger( 120816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.integer.keypad_channel_switch_ripple_anim_duration); 121816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mBaseViewHeight = resources.getDimensionPixelSize( 122816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.dimen.keypad_channel_switch_base_height); 123816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mItemHeight = resources.getDimensionPixelSize(R.dimen.keypad_channel_switch_item_height); 124816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mResizeAnimDuration = resources.getInteger(R.integer.keypad_channel_switch_anim_duration); 125816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mResizeInterpolator = AnimationUtils.loadInterpolator(context, 126816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko android.R.interpolator.linear_out_slow_in); 127816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 128816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 129816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 130816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void onFinishInflate(){ 131ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super.onFinishInflate(); 132816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelNumberView = (TextView) findViewById(R.id.channel_number); 133816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView = (ListView) findViewById(R.id.channel_list); 134816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView.setAdapter(mAdapter); 135816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 136816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 137816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 138816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (position >= mAdapter.getCount()) { 139816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // It can happen during closing. 140816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 141816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 142816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView.setFocusable(false); 143816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko final Channel channel = ((Channel) mAdapter.getItem(position)); 144816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko postDelayed(new Runnable() { 145816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 146816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void run() { 147816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView.setFocusable(true); 148816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mMainActivity.tuneToChannel(channel); 149816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendChannelNumberItemClicked(); 150816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 151816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }, mRippleAnimDurationMillis); 152816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 153816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 154816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 155816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 156816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 157816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (position >= mAdapter.getCount()) { 158816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // It can happen during closing. 159816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedChannel = null; 160816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 161816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedChannel = (Channel) mAdapter.getItem(position); 162816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 1637d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (position != 0 && !mNavigated) { 164816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mNavigated = true; 165816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendChannelInputNavigated(); 166816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 167816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 168816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 169816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 170816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onNothingSelected(AdapterView<?> parent) { 171816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedChannel = null; 172816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 173816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 174816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 175816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 176816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 177816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public boolean dispatchKeyEvent(KeyEvent event) { 178816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko scheduleHide(); 179816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return super.dispatchKeyEvent(event); 180816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 181816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 182816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 183816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public boolean onKeyUp(int keyCode, KeyEvent event) { 1847d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko SoftPreconditions.checkNotNull(mChannels, TAG, "mChannels"); 185816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (isChannelNumberKey(keyCode)) { 186816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko onNumberKeyUp(keyCode - KeyEvent.KEYCODE_0); 187816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return true; 188816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 189816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (ChannelNumber.isChannelNumberDelimiterKey(keyCode)) { 190816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko onDelimiterKeyUp(); 191816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return true; 192816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 193816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return super.onKeyUp(keyCode, event); 194816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 195816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 196816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 197816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onEnterAction(boolean fromEmptyScene) { 198816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko reset(); 199816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (fromEmptyScene) { 200816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ViewUtils.setTransitionAlpha(mChannelItemListView, 1f); 201816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 202816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mNavigated = false; 203816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mViewDurationTimer.start(); 204816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendShowChannelSwitch(); 205816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendScreenView(SCREEN_NAME); 206816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko updateView(); 207816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko scheduleHide(); 208816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 209816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 210816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 211816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onExitAction() { 212816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentHeight = 0; 213816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendHideChannelSwitch(mViewDurationTimer.reset()); 214816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko cancelHide(); 215816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 216816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 217816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void scheduleHide() { 218816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko cancelHide(); 219816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko postDelayed(mHideRunnable, mShowDurationMillis); 220816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 221816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 222816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void cancelHide() { 223816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko removeCallbacks(mHideRunnable); 224816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 225816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 226816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void reset() { 227816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTypedChannelNumber.reset(); 228816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedChannel = null; 229816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelCandidates.clear(); 230816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mAdapter.notifyDataSetChanged(); 231816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 232816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 2337d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko public void setChannels(@Nullable List<Channel> channels) { 234816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannels = channels; 235816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 236816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 237816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public static boolean isChannelNumberKey(int keyCode) { 238816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9; 239816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 240816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 241816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onNumberKeyUp(int num) { 242816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Reset typed channel number in some cases. 243816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mTypedChannelNumber.majorNumber == null) { 244816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTypedChannelNumber.reset(); 245816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (!mTypedChannelNumber.hasDelimiter 246816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko && mTypedChannelNumber.majorNumber.length() >= MAX_CHANNEL_NUMBER_DIGIT) { 247816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTypedChannelNumber.reset(); 248816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (mTypedChannelNumber.hasDelimiter 249816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko && mTypedChannelNumber.minorNumber != null 250816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko && mTypedChannelNumber.minorNumber.length() >= MAX_MINOR_CHANNEL_NUMBER_DIGIT) { 251816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTypedChannelNumber.reset(); 252816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 253816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 254816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!mTypedChannelNumber.hasDelimiter) { 255816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTypedChannelNumber.majorNumber += String.valueOf(num); 256816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 257816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTypedChannelNumber.minorNumber += String.valueOf(num); 258816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 259816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendChannelNumberInput(); 260816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko updateView(); 261816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 262816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 263816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void onDelimiterKeyUp() { 264816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mTypedChannelNumber.hasDelimiter || mTypedChannelNumber.majorNumber.length() == 0) { 265816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 266816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 267816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTypedChannelNumber.hasDelimiter = true; 268816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendChannelNumberInput(); 269816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko updateView(); 270816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 271816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 272816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void updateView() { 273816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelNumberView.setText(mTypedChannelNumber.toString() + "_"); 274816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelCandidates.clear(); 275816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ArrayList<Channel> secondaryChannelCandidates = new ArrayList<>(); 276816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko for (Channel channel : mChannels) { 277816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ChannelNumber chNumber = ChannelNumber.parseChannelNumber(channel.getDisplayNumber()); 278816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (chNumber == null) { 279816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Log.i(TAG, "Malformed channel number (name=" + channel.getDisplayName() 280816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko + ", number=" + channel.getDisplayNumber() + ")"); 281816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko continue; 282816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 283816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (matchChannelNumber(mTypedChannelNumber, chNumber)) { 284816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelCandidates.add(channel); 285816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (!mTypedChannelNumber.hasDelimiter) { 286816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Even if a user doesn't type '-', we need to match the typed number to not only 287816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // the major number but also the minor number. For example, when a user types '111' 288816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // without delimiter, it should be matched to '111', '1-11' and '11-1'. 289816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (channel.getDisplayNumber().replaceAll(CHANNEL_DELIMITERS_REGEX, "") 290816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko .startsWith(mTypedChannelNumber.majorNumber)) { 291816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko secondaryChannelCandidates.add(channel); 292816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 293816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 294816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 295816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelCandidates.addAll(secondaryChannelCandidates); 296816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mAdapter.notifyDataSetChanged(); 297816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mAdapter.getCount() > 0) { 298816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView.requestFocus(); 299816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelItemListView.setSelection(0); 300816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedChannel = mChannelCandidates.get(0); 301816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 302816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 303816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko updateViewHeight(); 304816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 305816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 306816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void updateViewHeight() { 307816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int itemListHeight = mItemHeight * Math.min(MAX_CHANNEL_ITEM, mAdapter.getCount()); 308816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int targetHeight = mBaseViewHeight + itemListHeight; 309816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mResizeAnimator != null) { 310816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mResizeAnimator.cancel(); 311816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mResizeAnimator = null; 312816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 313816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 314816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mCurrentHeight == 0) { 315816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Do not add the resize animation when the banner has not been shown before. 316816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentHeight = targetHeight; 317816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko setViewHeight(this, targetHeight); 318816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (mCurrentHeight != targetHeight){ 319816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mResizeAnimator = createResizeAnimator(targetHeight); 320816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mResizeAnimator.start(); 321816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 322816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 323816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 324816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private Animator createResizeAnimator(int targetHeight) { 325816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ValueAnimator animator = ValueAnimator.ofInt(mCurrentHeight, targetHeight); 326816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 327816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 328816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationUpdate(ValueAnimator animation) { 329816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int value = (Integer) animation.getAnimatedValue(); 330816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko setViewHeight(KeypadChannelSwitchView.this, value); 331816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentHeight = value; 332816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 333816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 334816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko animator.setDuration(mResizeAnimDuration); 335816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko animator.addListener(new AnimatorListenerAdapter() { 336816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 337816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animator) { 338816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mResizeAnimator = null; 339816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 340816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 341816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko animator.setInterpolator(mResizeInterpolator); 342816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return animator; 343816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 344816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 345816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void setViewHeight(View view, int height) { 346816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); 347816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (height != layoutParams.height) { 348816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko layoutParams.height = height; 349816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko view.setLayoutParams(layoutParams); 350816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 351816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 352816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 353816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static boolean matchChannelNumber(ChannelNumber typedChNumber, ChannelNumber chNumber) { 354816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!chNumber.majorNumber.equals(typedChNumber.majorNumber)) { 355816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return false; 356816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 357816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (typedChNumber.hasDelimiter) { 358816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!chNumber.hasDelimiter) { 359816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return false; 360816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 361816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!chNumber.minorNumber.startsWith(typedChNumber.minorNumber)) { 362816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return false; 363816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 364816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 365816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return true; 366816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 367816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 368816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko class ChannelItemAdapter extends BaseAdapter { 369816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 370816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public int getCount() { 371816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mChannelCandidates.size(); 372816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 373816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 374816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 375816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public Object getItem(int position) { 376816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mChannelCandidates.get(position); 377816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 378816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 379816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 380816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public long getItemId(int position) { 381816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return position; 382816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 383816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 384816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 385816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public View getView(int position, View convertView, ViewGroup parent) { 386816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko final Channel channel = mChannelCandidates.get(position); 387816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko View v = convertView; 388816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (v == null) { 389816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko v = mLayoutInflater.inflate(R.layout.keypad_channel_switch_item, parent, false); 390816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 391816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 392816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko TextView channelNumberView = (TextView) v.findViewById(R.id.number); 393816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko channelNumberView.setText(channel.getDisplayNumber()); 394816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 395816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko TextView channelNameView = (TextView) v.findViewById(R.id.name); 396816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko channelNameView.setText(channel.getDisplayName()); 397816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return v; 398816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 399816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 400816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko} 401