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.guide; 18816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 19816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.Animator; 20816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.AnimatorInflater; 21816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.AnimatorListenerAdapter; 22816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.AnimatorSet; 23816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.ObjectAnimator; 24816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.animation.PropertyValuesHolder; 25d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.content.Context; 26816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.SharedPreferences; 27816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.res.Resources; 28816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.graphics.Point; 29816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.os.Handler; 30816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.os.Message; 31816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.os.SystemClock; 32816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.preference.PreferenceManager; 3307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.support.annotation.NonNull; 342e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport android.support.annotation.Nullable; 35816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.v17.leanback.widget.OnChildSelectedListener; 36816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.v17.leanback.widget.SearchOrbView; 37816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.v17.leanback.widget.VerticalGridView; 38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.v7.widget.RecyclerView; 39816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.util.Log; 40816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.View; 41816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.View.MeasureSpec; 42816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.ViewGroup; 43816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.ViewGroup.LayoutParams; 44816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.ViewTreeObserver; 45d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.view.accessibility.AccessibilityManager; 46816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 47816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.ChannelTuner; 487d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport com.android.tv.Features; 49816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.MainActivity; 50816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.R; 516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.util.DurationTimer; 52816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.analytics.Tracker; 5307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport com.android.tv.common.WeakHandler; 54816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.ChannelDataManager; 55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.GenreItems; 56816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.ProgramDataManager; 572e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport com.android.tv.dvr.DvrDataManager; 5865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dvr.DvrScheduleManager; 59816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.ui.HardwareLayerAnimatorListenerAdapter; 60d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport com.android.tv.ui.ViewUtils; 61816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.TvInputManagerHelper; 62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.Utils; 63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 64816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.ArrayList; 65816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.List; 66816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.concurrent.TimeUnit; 67816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 68816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/** 69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * The program guide. 70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopublic class ProgramGuide implements ProgramGrid.ChildFocusListener { 72816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final String TAG = "ProgramGuide"; 73816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final boolean DEBUG = false; 74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Whether we should show the guide partially. The first time the user enters the program guide, 76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // we show the grid partially together with the genre side panel on the left. Next time 77816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // the program guide is entered, we recover the previous state (partial or full). 78816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final String KEY_SHOW_GUIDE_PARTIAL = "show_guide_partial"; 79816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final long TIME_INDICATOR_UPDATE_FREQUENCY = TimeUnit.SECONDS.toMillis(1); 80816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final long HOUR_IN_MILLIS = TimeUnit.HOURS.toMillis(1); 81816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final long HALF_HOUR_IN_MILLIS = HOUR_IN_MILLIS / 2; 82816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // We keep the duration between mStartTime and the current time larger than this value. 83816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // We clip out the first program entry in ProgramManager, if it does not have enough width. 84816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // In order to prevent from clipping out the current program, this value need be larger than 85816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // or equal to ProgramManager.FIRST_ENTRY_MIN_DURATION. 86816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final long MIN_DURATION_FROM_START_TIME_TO_CURRENT_TIME 87816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko = ProgramManager.FIRST_ENTRY_MIN_DURATION; 88816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 89816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final int MSG_PROGRAM_TABLE_FADE_IN_ANIM = 1000; 90816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 91816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final String SCREEN_NAME = "EPG"; 92816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 93816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final MainActivity mActivity; 94816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ProgramManager mProgramManager; 95d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko private final AccessibilityManager mAccessibilityManager; 96816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ChannelTuner mChannelTuner; 97816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Tracker mTracker; 98816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final DurationTimer mVisibleDuration = new DurationTimer(); 99816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Runnable mPreShowRunnable; 100816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Runnable mPostHideRunnable; 101816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 102816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mWidthPerHour; 103816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final long mViewPortMillis; 104816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mRowHeight; 105816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mDetailHeight; 10607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mSelectionRow; // Row that is focused 107816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mTableFadeAnimDuration; 108816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mAnimationDuration; 109816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mDetailPadding; 110816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final SearchOrbView mSearchOrb; 111816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private int mCurrentTimeIndicatorWidth; 112816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 113816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final View mContainer; 114816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final View mSidePanel; 115816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final VerticalGridView mSidePanelGridView; 116816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final View mTable; 117816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final TimelineRow mTimelineRow; 118816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ProgramGrid mGrid; 119816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final TimeListAdapter mTimeListAdapter; 120816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final View mCurrentTimeIndicator; 121816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 122816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mShowAnimatorFull; 123816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mShowAnimatorPartial; 124816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // mHideAnimatorFull and mHideAnimatorPartial are created from the same animation xmls. 125816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // When we share the one animator for two different animations, the starting value 126816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // is broken, even though the starting value is not defined in XML. 127816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mHideAnimatorFull; 128816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mHideAnimatorPartial; 129816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mPartialToFullAnimator; 130816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mFullToPartialAnimator; 131816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mProgramTableFadeOutAnimator; 132816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Animator mProgramTableFadeInAnimator; 133816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 134816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // When the program guide is popped up, we keep the previous state of the guide. 135816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private boolean mShowGuidePartial; 136816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final SharedPreferences mSharedPreference; 137816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private View mSelectedRow; 138816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private Animator mDetailOutAnimator; 139816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private Animator mDetailInAnimator; 140816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 141816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private long mStartUtcTime; 142816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private boolean mTimelineAnimation; 143816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private int mLastRequestedGenreId = GenreItems.ID_ALL_CHANNELS; 144816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private boolean mIsDuringResetRowSelection; 14507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final Handler mHandler = new ProgramGuideHandler(this); 1466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private boolean mActive; 147816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 148816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Runnable mHideRunnable = new Runnable() { 149816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 150816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void run() { 151816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko hide(); 152816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 153816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }; 154816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final long mShowDurationMillis; 15507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private ViewTreeObserver.OnGlobalLayoutListener mOnLayoutListenerForShow; 156816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 157816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ProgramManagerListener mProgramManagerListener = new ProgramManagerListener(); 158816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 159816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Runnable mUpdateTimeIndicator = new Runnable() { 160816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 161816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void run() { 162816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko positionCurrentTimeIndicator(); 163816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.postAtTime(this, 164816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Utils.ceilTime(SystemClock.uptimeMillis(), TIME_INDICATOR_UPDATE_FREQUENCY)); 165816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 166816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }; 167816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 168816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public ProgramGuide(MainActivity activity, ChannelTuner channelTuner, 169816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko TvInputManagerHelper tvInputManagerHelper, ChannelDataManager channelDataManager, 1702e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko ProgramDataManager programDataManager, @Nullable DvrDataManager dvrDataManager, 17165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Nullable DvrScheduleManager dvrScheduleManager, Tracker tracker, 17265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko Runnable preShowRunnable, Runnable postHideRunnable) { 173816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mActivity = activity; 1742e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko mProgramManager = new ProgramManager(tvInputManagerHelper, channelDataManager, 17565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko programDataManager, dvrDataManager, dvrScheduleManager); 176816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelTuner = channelTuner; 177816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker = tracker; 178816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mPreShowRunnable = preShowRunnable; 179816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mPostHideRunnable = postHideRunnable; 180816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 181816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Resources res = activity.getResources(); 182816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 183816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mWidthPerHour = res.getDimensionPixelSize(R.dimen.program_guide_table_width_per_hour); 184816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko GuideUtils.setWidthPerHour(mWidthPerHour); 185816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 186816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Point displaySize = new Point(); 187816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mActivity.getWindowManager().getDefaultDisplay().getSize(displaySize); 188816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int gridWidth = displaySize.x 189816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko - res.getDimensionPixelOffset(R.dimen.program_guide_table_margin_start) 190816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko - res.getDimensionPixelSize(R.dimen.program_guide_table_header_column_width); 191816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mViewPortMillis = (gridWidth * HOUR_IN_MILLIS) / mWidthPerHour; 192816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 193816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mRowHeight = res.getDimensionPixelSize(R.dimen.program_guide_table_item_row_height); 194816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailHeight = res.getDimensionPixelSize(R.dimen.program_guide_table_detail_height); 19507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mSelectionRow = res.getInteger(R.integer.program_guide_selection_row); 196816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTableFadeAnimDuration = 197816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko res.getInteger(R.integer.program_guide_table_detail_fade_anim_duration); 198816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mShowDurationMillis = res.getInteger(R.integer.program_guide_show_duration); 199816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mAnimationDuration = 200816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko res.getInteger(R.integer.program_guide_table_detail_toggle_anim_duration); 201816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailPadding = res.getDimensionPixelOffset(R.dimen.program_guide_table_detail_padding); 202816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 203816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mContainer = mActivity.findViewById(R.id.program_guide); 204816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ViewTreeObserver.OnGlobalFocusChangeListener globalFocusChangeListener 205816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko = new GlobalFocusChangeListener(); 206816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mContainer.getViewTreeObserver().addOnGlobalFocusChangeListener(globalFocusChangeListener); 207816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 208816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko GenreListAdapter genreListAdapter = new GenreListAdapter(mActivity, mProgramManager, this); 209816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanel = mContainer.findViewById(R.id.program_guide_side_panel); 210816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView = (VerticalGridView) mContainer.findViewById( 211816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.id.program_guide_side_panel_grid_view); 212816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.getRecycledViewPool().setMaxRecycledViews( 213816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.layout.program_guide_side_panel_row, 214816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko res.getInteger(R.integer.max_recycled_view_pool_epg_side_panel_row)); 215816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setAdapter(genreListAdapter); 216816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE); 217816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setWindowAlignmentOffset(mActivity.getResources() 218816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko .getDimensionPixelOffset(R.dimen.program_guide_side_panel_alignment_y)); 219816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setWindowAlignmentOffsetPercent( 220816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 2216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 2227d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (Features.EPG_SEARCH.isEnabled(mActivity)) { 223816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSearchOrb = (SearchOrbView) mContainer.findViewById( 224816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.id.program_guide_side_panel_search_orb); 225816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSearchOrb.setVisibility(View.VISIBLE); 226816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 227816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSearchOrb.setOnOrbClickedListener(new View.OnClickListener() { 228816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 229816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onClick(View view) { 230816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko hide(); 231816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mActivity.showProgramGuideSearchFragment(); 232816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 233816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 234816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setOnChildSelectedListener( 235816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko new android.support.v17.leanback.widget.OnChildSelectedListener() { 236816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 237816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onChildSelected(ViewGroup viewGroup, View view, int i, long l) { 238816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSearchOrb.animate().alpha(i == 0 ? 1.0f : 0.0f); 239816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 240816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 241816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 242816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSearchOrb = null; 243816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 244816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 245816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTable = mContainer.findViewById(R.id.program_guide_table); 246816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 247816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineRow = (TimelineRow) mTable.findViewById(R.id.time_row); 248816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimeListAdapter = new TimeListAdapter(res); 249816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineRow.getRecycledViewPool().setMaxRecycledViews( 250816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.layout.program_guide_table_header_row_item, 251816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko res.getInteger(R.integer.max_recycled_view_pool_epg_header_row_item)); 252816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineRow.setAdapter(mTimeListAdapter); 253816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 2546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ProgramTableAdapter programTableAdapter = new ProgramTableAdapter(mActivity, this); 255816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko programTableAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { 256816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 257816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onChanged() { 258816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // It is usually called when Genre is changed. 259816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Reset selection of ProgramGrid 260816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko resetRowSelection(); 261ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko updateGuidePosition(); 262816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 263816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 264816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 265816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid = (ProgramGrid) mTable.findViewById(R.id.grid); 266816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.initialize(mProgramManager); 267816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.getRecycledViewPool().setMaxRecycledViews( 268816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.layout.program_guide_table_row, 269816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko res.getInteger(R.integer.max_recycled_view_pool_epg_table_row)); 270816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setAdapter(programTableAdapter); 271816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 272816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setChildFocusListener(this); 273816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setOnChildSelectedListener(new OnChildSelectedListener() { 274816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 275816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onChildSelected(ViewGroup parent, View view, int position, long id) { 276816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mIsDuringResetRowSelection) { 277816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Ignore if it's during the first resetRowSelection, because onChildSelected 278816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // will be called again when rows are bound to the program table. if selectRow 279816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // is called here, mSelectedRow is set and the second selectRow call doesn't 280816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // work as intended. 281816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mIsDuringResetRowSelection = false; 282816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 283816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 284816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko selectRow(view); 285816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 286816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 287816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setFocusScrollStrategy(ProgramGrid.FOCUS_SCROLL_ALIGNED); 28807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mGrid.setWindowAlignmentOffset(mSelectionRow * mRowHeight); 289816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setWindowAlignmentOffsetPercent(ProgramGrid.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 290816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setItemAlignmentOffset(0); 291816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setItemAlignmentOffsetPercent(ProgramGrid.ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 292816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 293816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { 294816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 295816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 296816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko onHorizontalScrolled(dx); 297816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 298816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }; 299816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineRow.addOnScrollListener(onScrollListener); 300816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 301816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentTimeIndicator = mTable.findViewById(R.id.current_time_indicator); 302816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 303816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mShowAnimatorFull = createAnimator( 304816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_enter_full, 305816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 0, 306816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_enter_full); 307816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 308816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mShowAnimatorPartial = createAnimator( 309816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_enter_partial, 310816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 0, 311816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_enter_partial); 312816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mShowAnimatorPartial.addListener(new AnimatorListenerAdapter() { 313816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 314816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationStart(Animator animation) { 315816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setVisibility(View.VISIBLE); 316816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setAlpha(1.0f); 317816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 318816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 319816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 320816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHideAnimatorFull = createAnimator( 321816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_exit, 322816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 0, 323816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_exit); 324816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHideAnimatorFull.addListener(new AnimatorListenerAdapter() { 325816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 326816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animation) { 32707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mContainer.setVisibility(View.GONE); 328816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 329816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 330816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHideAnimatorPartial = createAnimator( 331816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_exit, 332816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 0, 333816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_exit); 334816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHideAnimatorPartial.addListener(new AnimatorListenerAdapter() { 335816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 336816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animation) { 33707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mContainer.setVisibility(View.GONE); 338816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 339816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 340816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 341816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mPartialToFullAnimator = createAnimator( 342816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_hide, 343816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_grid_fade_out, 344816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_partial_to_full); 345816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mFullToPartialAnimator = createAnimator( 346816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_reveal, 347816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_side_panel_grid_fade_in, 348816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_full_to_partial); 349816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 350816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeOutAnimator = AnimatorInflater.loadAnimator(mActivity, 351816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_fade_out); 352816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeOutAnimator.setTarget(mTable); 353816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeOutAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(mTable) { 354816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 355816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animation) { 356816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super.onAnimationEnd(animation); 357816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 358816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!isActive()) { 359816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 360816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 361816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramManager.resetChannelListWithGenre(mLastRequestedGenreId); 362816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko resetTimelineScroll(); 363816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!mHandler.hasMessages(MSG_PROGRAM_TABLE_FADE_IN_ANIM)) { 364816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.sendEmptyMessage(MSG_PROGRAM_TABLE_FADE_IN_ANIM); 365816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 366816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 367816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 368816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeInAnimator = AnimatorInflater.loadAnimator(mActivity, 369816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.animator.program_guide_table_fade_in); 370816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeInAnimator.setTarget(mTable); 371816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeInAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(mTable)); 372816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSharedPreference = PreferenceManager.getDefaultSharedPreferences(mActivity); 373d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mAccessibilityManager = 374d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko (AccessibilityManager) mActivity.getSystemService(Context.ACCESSIBILITY_SERVICE); 375d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mShowGuidePartial = mAccessibilityManager.isEnabled() 376d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko || mSharedPreference.getBoolean(KEY_SHOW_GUIDE_PARTIAL, true); 377816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 378816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 379816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 380816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onRequestChildFocus(View oldFocus, View newFocus) { 381816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (oldFocus != null && newFocus != null) { 38207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int selectionRowOffset = mSelectionRow * mRowHeight; 383816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (oldFocus.getTop() < newFocus.getTop()) { 384816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Selection moves downwards 385816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Adjust scroll offset to be at the bottom of the target row and to expand up. This 386816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // will set the scroll target to be one row height up from its current position. 387816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setWindowAlignmentOffset(selectionRowOffset + mRowHeight + mDetailHeight); 388816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setItemAlignmentOffsetPercent(100); 389816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (oldFocus.getTop() > newFocus.getTop()) { 390816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Selection moves upwards 391816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Adjust scroll offset to be at the top of the target row and to expand down. This 392816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // will set the scroll target to be one row height down from its current position. 393816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setWindowAlignmentOffset(selectionRowOffset); 394816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setItemAlignmentOffsetPercent(0); 395816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 396816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 397816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 398816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 399816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 400816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Show the program guide. This reveals the side panel, and the program guide table is shown 401816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * partially. 40207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 40307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * <p>Note: the animation which starts together with ProgramGuide showing animation needs to 40407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * be initiated in {@code runnableAfterAnimatorReady}. If the animation starts together 40507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * with show(), the animation may drop some frames. 406816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 40707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void show(final Runnable runnableAfterAnimatorReady) { 408816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mContainer.getVisibility() == View.VISIBLE) { 409816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 410816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 411816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendShowEpg(); 412816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendScreenView(SCREEN_NAME); 413816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mPreShowRunnable != null) { 414816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mPreShowRunnable.run(); 415816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 416816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mVisibleDuration.start(); 417816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 418816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramManager.programGuideVisibilityChanged(true); 419816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mStartUtcTime = Utils.floorTime( 420816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko System.currentTimeMillis() - MIN_DURATION_FROM_START_TIME_TO_CURRENT_TIME, 421816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko HALF_HOUR_IN_MILLIS); 42207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mProgramManager.updateInitialTimeRange(mStartUtcTime, mStartUtcTime + mViewPortMillis); 423816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramManager.addListener(mProgramManagerListener); 424816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mLastRequestedGenreId = GenreItems.ID_ALL_CHANNELS; 425816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimeListAdapter.update(mStartUtcTime); 426816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineRow.resetScroll(); 427816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 4286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mContainer.setVisibility(View.VISIBLE); 4296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mActive = true; 430816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!mShowGuidePartial) { 4316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTable.requestFocus(); 432816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 43307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko positionCurrentTimeIndicator(); 434816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelGridView.setSelectedPosition(0); 43507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) { 43607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Log.d(TAG, "show()"); 43707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 43807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mOnLayoutListenerForShow = new ViewTreeObserver.OnGlobalLayoutListener() { 439816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 44007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onGlobalLayout() { 44107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this); 44207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTable.setLayerType(View.LAYER_TYPE_HARDWARE, null); 44307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mSidePanelGridView.setLayerType(View.LAYER_TYPE_HARDWARE, null); 44407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTable.buildLayer(); 44507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mSidePanelGridView.buildLayer(); 44607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mOnLayoutListenerForShow = null; 44707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTimelineAnimation = true; 44807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Make sure that time indicator update starts after animation is finished. 44907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko startCurrentTimeIndicator(TIME_INDICATOR_UPDATE_FREQUENCY); 45007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) { 45107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mContainer.getViewTreeObserver().addOnDrawListener( 45207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko new ViewTreeObserver.OnDrawListener() { 453ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko long time = System.currentTimeMillis(); 454ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko int count = 0; 455ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 456ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 457ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onDraw() { 458ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko long curtime = System.currentTimeMillis(); 459ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Log.d(TAG, "onDraw " + count++ + " " + (curtime - time) + "ms"); 460ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko time = curtime; 461ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (count > 10) { 462ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mContainer.getViewTreeObserver().removeOnDrawListener(this); 463ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 464ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 465ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko }); 46607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 4676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko updateGuidePosition(); 46807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko runnableAfterAnimatorReady.run(); 469816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mShowGuidePartial) { 470816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mShowAnimatorPartial.start(); 471816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 472816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mShowAnimatorFull.start(); 473816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 474816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 47507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko }; 47607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mContainer.getViewTreeObserver().addOnGlobalLayoutListener(mOnLayoutListenerForShow); 477816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko scheduleHide(); 478816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 479816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 480816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 481816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Hide the program guide. 482816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 483816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void hide() { 484816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!isActive()) { 485816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 486816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 48707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mOnLayoutListenerForShow != null) { 48807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mContainer.getViewTreeObserver().removeOnGlobalLayoutListener(mOnLayoutListenerForShow); 48907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mOnLayoutListenerForShow = null; 49007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 491816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendHideEpg(mVisibleDuration.reset()); 492816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko cancelHide(); 493816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramManager.programGuideVisibilityChanged(false); 494816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramManager.removeListener(mProgramManagerListener); 4956ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mActive = false; 4966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (!mShowGuidePartial) { 497816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHideAnimatorFull.start(); 498816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 499816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHideAnimatorPartial.start(); 500816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 501816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 502816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Clears fade-out/in animation for genre change 503816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mProgramTableFadeOutAnimator.isRunning()) { 504816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeOutAnimator.cancel(); 505816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 506816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mProgramTableFadeInAnimator.isRunning()) { 507816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeInAnimator.cancel(); 508816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 509816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.removeMessages(MSG_PROGRAM_TABLE_FADE_IN_ANIM); 510816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTable.setAlpha(1.0f); 511816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 512816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineAnimation = false; 513816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko stopCurrentTimeIndicator(); 514816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mPostHideRunnable != null) { 515816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mPostHideRunnable.run(); 516816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 517816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 518816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 5196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 5206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Schedules hiding the program guide. 5216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 522816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void scheduleHide() { 523816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko cancelHide(); 524816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.postDelayed(mHideRunnable, mShowDurationMillis); 525816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 526816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 527816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 5286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Cancels hiding the program guide. 5292e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko */ 5302e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko public void cancelHide() { 531816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.removeCallbacks(mHideRunnable); 532816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 533816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 534816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 535816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Process the {@code KEYCODE_BACK} key event. 536816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 537816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onBackPressed() { 538816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko hide(); 539816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 540816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 541816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 5426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Returns {@code true} if the program guide should process the input events. 543816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 5446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public boolean isActive() { 5456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return mActive; 5466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 5476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 5486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 5496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Returns {@code true} if the program guide is shown, i.e. showing animation is done and 5506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * hiding animation is not started yet. 5516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 5526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public boolean isRunningAnimation() { 5536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return mShowAnimatorPartial.isStarted() || mShowAnimatorFull.isStarted() 5546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko || mHideAnimatorPartial.isStarted() || mHideAnimatorFull.isStarted(); 5556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 5566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 5576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** Returns if program table is in full screen mode. **/ 5586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko boolean isFull() { 5596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return !mShowGuidePartial; 560816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 561816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 562816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 563816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Requests change genre to {@code genreId}. 564816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 5656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko void requestGenreChange(int genreId) { 566816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mLastRequestedGenreId == genreId) { 567816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // When Recycler.onLayout() removes its children to recycle, 568816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // View tries to find next focus candidate immediately 569816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // so GenreListAdapter can take focus back while it's hiding. 570816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Returns early here to prevent re-entrance. 571816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 572816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 573816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mLastRequestedGenreId = genreId; 574816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mProgramTableFadeOutAnimator.isStarted()) { 575816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // When requestGenreChange is called repeatedly in short time, we keep the fade-out 576816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // state for mTableFadeAnimDuration from now. Without it, we'll see blinks. 577816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.removeMessages(MSG_PROGRAM_TABLE_FADE_IN_ANIM); 578816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.sendEmptyMessageDelayed(MSG_PROGRAM_TABLE_FADE_IN_ANIM, 579816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTableFadeAnimDuration); 580816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 581816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 582816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mHandler.hasMessages(MSG_PROGRAM_TABLE_FADE_IN_ANIM)) { 583816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramManager.resetChannelListWithGenre(mLastRequestedGenreId); 584816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.removeMessages(MSG_PROGRAM_TABLE_FADE_IN_ANIM); 585816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.sendEmptyMessageDelayed(MSG_PROGRAM_TABLE_FADE_IN_ANIM, 586816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTableFadeAnimDuration); 587816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 588816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 589816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mProgramTableFadeInAnimator.isStarted()) { 590816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeInAnimator.cancel(); 591816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 592816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 593816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramTableFadeOutAnimator.start(); 594816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 595816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 5966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 5976ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Returns the scroll offset of the time line row in pixels. 5986ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 5996ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int getTimelineRowScrollOffset() { 6006ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return mTimelineRow.getScrollOffset(); 6016ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6026ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6036ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** Returns the program grid view that hold all component views. */ 6046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ProgramGrid getProgramGrid() { 6056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return mGrid; 6066ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6076ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6086ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 6096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Gets {@link VerticalGridView} for "genre select" side panel. 6106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 6116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko VerticalGridView getSidePanel() { 6126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return mSidePanelGridView; 6136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** Returns the program manager the program guide is using to provide program information. */ 6166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ProgramManager getProgramManager() { 6176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return mProgramManager; 6186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private void updateGuidePosition() { 6216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // Align EPG at vertical center, if EPG table height is less than the screen size. 6226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Resources res = mActivity.getResources(); 6236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int screenHeight = mContainer.getHeight(); 6246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (screenHeight <= 0) { 6256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // mContainer is not initialized yet. 6266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return; 6276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int startPadding = res.getDimensionPixelOffset(R.dimen.program_guide_table_margin_start); 6296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int topPadding = res.getDimensionPixelOffset(R.dimen.program_guide_table_margin_top); 6306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int bottomPadding = res.getDimensionPixelOffset(R.dimen.program_guide_table_margin_bottom); 6316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int tableHeight = res.getDimensionPixelOffset(R.dimen.program_guide_table_header_row_height) 6326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko + mDetailHeight + mRowHeight * mGrid.getAdapter().getItemCount() + topPadding 6336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko + bottomPadding; 6346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (tableHeight > screenHeight) { 6356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // EPG height is longer that the screen height. 6366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTable.setPaddingRelative(startPadding, topPadding, 0, 0); 6376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko LayoutParams layoutParams = mTable.getLayoutParams(); 6386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko layoutParams.height = LayoutParams.WRAP_CONTENT; 6396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTable.setLayoutParams(layoutParams); 6406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } else { 6416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTable.setPaddingRelative(startPadding, topPadding, 0, bottomPadding); 6426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko LayoutParams layoutParams = mTable.getLayoutParams(); 6436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko layoutParams.height = tableHeight; 6446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTable.setLayoutParams(layoutParams); 6456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private Animator createAnimator(int sidePanelAnimResId, int sidePanelGridAnimResId, 6496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int tableAnimResId) { 6506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko List<Animator> animatorList = new ArrayList<>(); 6516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Animator sidePanelAnimator = AnimatorInflater.loadAnimator(mActivity, sidePanelAnimResId); 6536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko sidePanelAnimator.setTarget(mSidePanel); 6546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko animatorList.add(sidePanelAnimator); 6556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (sidePanelGridAnimResId != 0) { 6576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Animator sidePanelGridAnimator = AnimatorInflater.loadAnimator(mActivity, 6586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko sidePanelGridAnimResId); 6596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko sidePanelGridAnimator.setTarget(mSidePanelGridView); 6606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko sidePanelGridAnimator.addListener( 6616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko new HardwareLayerAnimatorListenerAdapter(mSidePanelGridView)); 6626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko animatorList.add(sidePanelGridAnimator); 6636ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Animator tableAnimator = AnimatorInflater.loadAnimator(mActivity, tableAnimResId); 6656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko tableAnimator.setTarget(mTable); 6666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko tableAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(mTable)); 6676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko animatorList.add(tableAnimator); 6686ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko AnimatorSet set = new AnimatorSet(); 6706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko set.playTogether(animatorList); 6716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return set; 6726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private void startFull() { 6756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (!mShowGuidePartial || mAccessibilityManager.isEnabled()) { 6766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // If accessibility service is enabled, focus cannot be moved to side panel due to it's 6776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // hidden. Therefore, we don't hide side panel when accessibility service is enabled. 6786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return; 6796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mShowGuidePartial = false; 6816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mSharedPreference.edit().putBoolean(KEY_SHOW_GUIDE_PARTIAL, mShowGuidePartial).apply(); 6826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mPartialToFullAnimator.start(); 6836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 6856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private void startPartial() { 6866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (mShowGuidePartial) { 6876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return; 6886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6896ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mShowGuidePartial = true; 6906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mSharedPreference.edit().putBoolean(KEY_SHOW_GUIDE_PARTIAL, mShowGuidePartial).apply(); 6916ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mFullToPartialAnimator.start(); 6926ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 6936ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 69407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private void startCurrentTimeIndicator(long initialDelay) { 69507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mHandler.postDelayed(mUpdateTimeIndicator, initialDelay); 696816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 697816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 698816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void stopCurrentTimeIndicator() { 699816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHandler.removeCallbacks(mUpdateTimeIndicator); 700816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 701816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 702816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void positionCurrentTimeIndicator() { 703816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int offset = GuideUtils.convertMillisToPixel(mStartUtcTime, System.currentTimeMillis()) 704816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko - mTimelineRow.getScrollOffset(); 705816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (offset < 0) { 706816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentTimeIndicator.setVisibility(View.GONE); 707816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 708816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mCurrentTimeIndicatorWidth == 0) { 709816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentTimeIndicator.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 710816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentTimeIndicatorWidth = mCurrentTimeIndicator.getMeasuredWidth(); 711816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 712816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentTimeIndicator.setPaddingRelative( 713816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko offset - mCurrentTimeIndicatorWidth / 2, 0, 0, 0); 714816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mCurrentTimeIndicator.setVisibility(View.VISIBLE); 715816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 716816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 717816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 718816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void resetTimelineScroll() { 719816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mProgramManager.getFromUtcMillis() != mStartUtcTime) { 720816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko boolean timelineAnimation = mTimelineAnimation; 721816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineAnimation = false; 722816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // mProgramManagerListener.onTimeRangeUpdated() will be called by shiftTime(). 723816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramManager.shiftTime(mStartUtcTime - mProgramManager.getFromUtcMillis()); 724816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineAnimation = timelineAnimation; 725816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 726816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 727816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 728816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void onHorizontalScrolled(int dx) { 729816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) Log.d(TAG, "onHorizontalScrolled(dx=" + dx + ")"); 730816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko positionCurrentTimeIndicator(); 731816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko for (int i = 0, n = mGrid.getChildCount(); i < n; ++i) { 732816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.getChildAt(i).findViewById(R.id.row).scrollBy(dx, 0); 733816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 734816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 735816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 736816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void resetRowSelection() { 737816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mDetailOutAnimator != null) { 738816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailOutAnimator.end(); 739816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 740816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mDetailInAnimator != null) { 741816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailInAnimator.cancel(); 742816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 743816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedRow = null; 744816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mIsDuringResetRowSelection = true; 745816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.setSelectedPosition( 746816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Math.max(mProgramManager.getChannelIndex(mChannelTuner.getCurrentChannel()), 747816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 0)); 748816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mGrid.resetFocusState(); 7492e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko mGrid.onItemSelectionReset(); 750816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mIsDuringResetRowSelection = false; 751816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 752816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 753816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void selectRow(View row) { 754816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (row == null || row == mSelectedRow) { 755816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 756816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 757816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mSelectedRow == null 758816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko || mGrid.getChildAdapterPosition(mSelectedRow) == RecyclerView.NO_POSITION) { 759816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mSelectedRow != null) { 760816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko View oldDetailView = mSelectedRow.findViewById(R.id.detail); 761816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko oldDetailView.setVisibility(View.GONE); 762816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 763816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko View detailView = row.findViewById(R.id.detail); 764816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko detailView.findViewById(R.id.detail_content_full).setAlpha(1); 765816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko detailView.findViewById(R.id.detail_content_full).setTranslationY(0); 766d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko ViewUtils.setLayoutHeight(detailView, mDetailHeight); 767816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko detailView.setVisibility(View.VISIBLE); 768816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 769816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko final ProgramRow programRow = (ProgramRow) row.findViewById(R.id.row); 770816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko programRow.post(new Runnable() { 771816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 772816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void run() { 773816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko programRow.focusCurrentProgram(); 774816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 775816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 776816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 777816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko animateRowChange(mSelectedRow, row); 778816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 779816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedRow = row; 780816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 781816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 782816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void animateRowChange(View outRow, View inRow) { 783816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mDetailOutAnimator != null) { 784816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailOutAnimator.end(); 785816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 786816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mDetailInAnimator != null) { 787816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailInAnimator.cancel(); 788816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 789816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 7906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int operationDirection = mGrid.getLastUpDownDirection(); 7916ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int animationPadding = 0; 7926ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (operationDirection == View.FOCUS_UP) { 7936ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko animationPadding = mDetailPadding; 7946ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } else if (operationDirection == View.FOCUS_DOWN) { 7956ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko animationPadding = -mDetailPadding; 796816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 797816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 798816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko View outDetail = outRow != null ? outRow.findViewById(R.id.detail) : null; 799816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (outDetail != null && outDetail.isShown()) { 800816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko final View outDetailContent = outDetail.findViewById(R.id.detail_content_full); 801816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 802816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Animator fadeOutAnimator = ObjectAnimator.ofPropertyValuesHolder(outDetailContent, 803816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko PropertyValuesHolder.ofFloat(View.ALPHA, outDetail.getAlpha(), 0f), 804816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 8056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko outDetailContent.getTranslationY(), animationPadding)); 806816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko fadeOutAnimator.setStartDelay(0); 807816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko fadeOutAnimator.setDuration(mAnimationDuration); 808816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko fadeOutAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(outDetailContent)); 809816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 810d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko Animator collapseAnimator = ViewUtils 811d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko .createHeightAnimator(outDetail, ViewUtils.getLayoutHeight(outDetail), 0); 812816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko collapseAnimator.setStartDelay(mAnimationDuration); 813816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko collapseAnimator.setDuration(mTableFadeAnimDuration); 814816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko collapseAnimator.addListener(new AnimatorListenerAdapter() { 815816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 816816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationStart(Animator animator) { 817816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko outDetailContent.setVisibility(View.GONE); 818816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 819816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 820816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 821816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animator) { 822816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko outDetailContent.setVisibility(View.VISIBLE); 823816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 824816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 825816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 826816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko AnimatorSet outAnimator = new AnimatorSet(); 827816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko outAnimator.playTogether(fadeOutAnimator, collapseAnimator); 828816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko outAnimator.addListener(new AnimatorListenerAdapter() { 829816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 830816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animator) { 831816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailOutAnimator = null; 832816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 833816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 834816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailOutAnimator = outAnimator; 835816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko outAnimator.start(); 836816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 837816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 838816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko View inDetail = inRow != null ? inRow.findViewById(R.id.detail) : null; 839816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (inDetail != null) { 840816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko final View inDetailContent = inDetail.findViewById(R.id.detail_content_full); 841816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 842d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko Animator expandAnimator = ViewUtils.createHeightAnimator(inDetail, 0, mDetailHeight); 843816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko expandAnimator.setStartDelay(mAnimationDuration); 844816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko expandAnimator.setDuration(mTableFadeAnimDuration); 845816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko expandAnimator.addListener(new AnimatorListenerAdapter() { 846816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 847816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationStart(Animator animator) { 848816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko inDetailContent.setVisibility(View.GONE); 849816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 850816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 851816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 852816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animator) { 853816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko inDetailContent.setVisibility(View.VISIBLE); 854816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko inDetailContent.setAlpha(0); 855816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 856816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 857816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Animator fadeInAnimator = ObjectAnimator.ofPropertyValuesHolder(inDetailContent, 858816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko PropertyValuesHolder.ofFloat(View.ALPHA, 0f, 1f), 8596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, -animationPadding, 0f)); 860816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko fadeInAnimator.setDuration(mAnimationDuration); 861816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko fadeInAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(inDetailContent)); 862816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 863816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko AnimatorSet inAnimator = new AnimatorSet(); 864d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko inAnimator.playSequentially(expandAnimator, fadeInAnimator); 865816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko inAnimator.addListener(new AnimatorListenerAdapter() { 866816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 867816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onAnimationEnd(Animator animator) { 868816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailInAnimator = null; 869816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 870816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }); 871816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDetailInAnimator = inAnimator; 872816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko inAnimator.start(); 873816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 874816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 875816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 876816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private class GlobalFocusChangeListener implements 877816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ViewTreeObserver.OnGlobalFocusChangeListener { 878816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final int UNKNOWN = 0; 879816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final int SIDE_PANEL = 1; 880816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final int PROGRAM_TABLE = 2; 881816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 882816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 883816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onGlobalFocusChanged(View oldFocus, View newFocus) { 884816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) Log.d(TAG, "onGlobalFocusChanged " + oldFocus + " -> " + newFocus); 885816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (!isActive()) { 886816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 887816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 888816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int fromLocation = getLocation(oldFocus); 889816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int toLocation = getLocation(newFocus); 890816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (fromLocation == SIDE_PANEL && toLocation == PROGRAM_TABLE) { 891816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko startFull(); 892816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (fromLocation == PROGRAM_TABLE && toLocation == SIDE_PANEL) { 893816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko startPartial(); 894816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 895816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 896816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 897816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private int getLocation(View view) { 898816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (view == null) { 899816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return UNKNOWN; 900816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 901816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko for (Object obj = view; obj instanceof View; obj = ((View) obj).getParent()) { 902816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (obj == mSidePanel) { 903816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return SIDE_PANEL; 904816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (obj == mGrid) { 905816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return PROGRAM_TABLE; 906816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 907816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 908816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return UNKNOWN; 909816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 910816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 911816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 912816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private class ProgramManagerListener extends ProgramManager.ListenerAdapter { 913816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 914816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onTimeRangeUpdated() { 915816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int scrollOffset = (int) (mWidthPerHour * mProgramManager.getShiftedTime() 916816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko / HOUR_IN_MILLIS); 917816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) { 918816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko Log.d(TAG, "Horizontal scroll to " + scrollOffset + " pixels (" 919816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko + mProgramManager.getShiftedTime() + " millis)"); 920816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 921816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTimelineRow.scrollTo(scrollOffset, mTimelineAnimation); 922816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 923816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 92407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 92507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private static class ProgramGuideHandler extends WeakHandler<ProgramGuide> { 9266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ProgramGuideHandler(ProgramGuide ref) { 92707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko super(ref); 92807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 92907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 93007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko @Override 93107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void handleMessage(Message msg, @NonNull ProgramGuide programGuide) { 93207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (msg.what == MSG_PROGRAM_TABLE_FADE_IN_ANIM) { 93307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko programGuide.mProgramTableFadeInAnimator.start(); 93407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 93507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 93607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 937816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko} 938