17d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko/* 27d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * Copyright (C) 2015 The Android Open Source Project 37d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * 47d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 57d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * you may not use this file except in compliance with the License. 67d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * You may obtain a copy of the License at 77d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * 87d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 97d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * 107d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * Unless required by applicable law or agreed to in writing, software 117d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 127d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * See the License for the specific language governing permissions and 147d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * limitations under the License. 157d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko */ 167d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 177d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkopackage com.android.tv.onboarding; 187d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.ActivityNotFoundException; 201abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.ComponentName; 211abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Intent; 23ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.graphics.Typeface; 24ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.graphics.drawable.Drawable; 251abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.media.tv.TvInputInfo; 26ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.media.tv.TvInputManager.TvInputCallback; 277d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.os.Bundle; 28ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.NonNull; 297d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.support.v17.leanback.widget.GuidanceStylist.Guidance; 307d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.support.v17.leanback.widget.GuidedAction; 31ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.v17.leanback.widget.GuidedActionsStylist; 321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.support.v17.leanback.widget.VerticalGridView; 337d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.view.LayoutInflater; 347d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.view.View; 357d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.view.ViewGroup; 36ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.widget.ImageView; 37ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.widget.TextView; 381abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.widget.Toast; 397d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 401abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.ApplicationSingletons; 41ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.Features; 427d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport com.android.tv.R; 431abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.SetupPassthroughActivity; 441abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.TvApplication; 451abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.common.TvCommonUtils; 467d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport com.android.tv.common.ui.setup.SetupGuidedStepFragment; 477d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport com.android.tv.common.ui.setup.SetupMultiPaneFragment; 481abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.data.ChannelDataManager; 491abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.data.TvInputNewComparator; 501abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.util.SetupUtils; 511abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.util.TvInputManagerHelper; 52ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.util.Utils; 537d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.ArrayList; 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Collections; 567d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport java.util.List; 577d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 587d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko/** 597d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko * A fragment for channel source info/setup. 607d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko */ 617d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkopublic class SetupSourcesFragment extends SetupMultiPaneFragment { 6248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final String TAG = "SetupSourcesFragment"; 6348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 64ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public static final String ACTION_CATEGORY = 65ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko "com.android.tv.onboarding.SetupSourcesFragment"; 66ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public static final int ACTION_PLAY_STORE = 1; 67ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 68ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final String SETUP_TRACKER_LABEL = "Setup fragment"; 69ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 70ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private InputSetupRunnable mInputSetupRunnable; 71ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 72ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private ContentFragment mContentFragment; 73ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 747d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 757d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko public View onCreateView(LayoutInflater inflater, ViewGroup container, 767d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko Bundle savedInstanceState) { 7748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho View view = super.onCreateView(inflater, container, savedInstanceState); 78ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko TvApplication.getSingletons(getActivity()).getTracker().sendScreenView(SETUP_TRACKER_LABEL); 797d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko return view; 807d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 817d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 827d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 83ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected void onEnterTransitionEnd() { 84ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mContentFragment != null) { 85ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mContentFragment.executePendingAction(); 86ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 87ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 88ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 89ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko protected SetupGuidedStepFragment onCreateContentFragment() { 91ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mContentFragment = new ContentFragment(); 9248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mContentFragment.setParentFragment(this); 931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Bundle arguments = new Bundle(); 941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko arguments.putBoolean(SetupGuidedStepFragment.KEY_THREE_PANE, true); 95ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mContentFragment.setArguments(arguments); 96ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return mContentFragment; 97ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 98ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 99ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 100ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected String getActionCategory() { 101ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return ACTION_CATEGORY; 1027d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 1037d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 104ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 105ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Call this method to run customized input setup. 106ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 107ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * @param runnable runnable to be called when the input setup is necessary. 108ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 109ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void setInputSetupRunnable(InputSetupRunnable runnable) { 110ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mInputSetupRunnable = runnable; 111ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 112ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 113ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 114ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Interface for the customized input setup. 115ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 116ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public interface InputSetupRunnable { 117ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 118ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Called for the input setup. 119ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 120ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * @param input TV input for setup. 121ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 122ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko void runInputSetup(TvInputInfo input); 123ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 124ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 125ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public static class ContentFragment extends SetupGuidedStepFragment { 1261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1; 1271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 128ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // ACTION_PLAY_STORE is defined in the outer class. 129ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int ACTION_DIVIDER = 2; 130ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int ACTION_HEADER = 3; 131ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int ACTION_INPUT_START = 4; 132ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 133ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int PENDING_ACTION_NONE = 0; 134ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int PENDING_ACTION_INPUT_CHANGED = 1; 135ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int PENDING_ACTION_CHANNEL_CHANGED = 2; 1361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 137ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private TvInputManagerHelper mInputManager; 138ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private ChannelDataManager mChannelDataManager; 139ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private SetupUtils mSetupUtils; 140ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private List<TvInputInfo> mInputs; 1411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private int mKnownInputStartIndex; 142ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private int mDoneInputStartIndex; 143ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 144ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private SetupSourcesFragment mParentFragment; 145ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 146ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private String mNewlyAddedInputId; 147ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 148ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private int mPendingAction = PENDING_ACTION_NONE; 149ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 150ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final TvInputCallback mInputCallback = new TvInputCallback() { 151ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 152ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onInputAdded(String inputId) { 153ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko handleInputChanged(); 154ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 155ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 156ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 157ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onInputRemoved(String inputId) { 158ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko handleInputChanged(); 159ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 160ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 16148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 16248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void onInputUpdated(String inputId) { 16348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho handleInputChanged(); 16448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 16548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 166ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private void handleInputChanged() { 167ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // The actions created while enter transition is running will not be included in the 168ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // fragment transition. 169ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mParentFragment.isEnterTransitionRunning()) { 170ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mPendingAction = PENDING_ACTION_INPUT_CHANGED; 171ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return; 172ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 173ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko buildInputs(); 174ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko updateActions(); 175ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 176ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko }; 177ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 178ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko void setParentFragment(SetupSourcesFragment parentFragment) { 179ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mParentFragment = parentFragment; 180ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 181ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 182ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final ChannelDataManager.Listener mChannelDataManagerListener 183ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko = new ChannelDataManager.Listener() { 184ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 185ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onLoadFinished() { 186ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko handleChannelChanged(); 187ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 188ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 189ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 190ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onChannelListUpdated() { 191ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko handleChannelChanged(); 192ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 1931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 194ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 195ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onChannelBrowsableChanged() { 196ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko handleChannelChanged(); 197ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 198ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 199ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private void handleChannelChanged() { 200ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // The actions created while enter transition is running will not be included in the 201ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // fragment transition. 202ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mParentFragment.isEnterTransitionRunning()) { 203ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mPendingAction != PENDING_ACTION_INPUT_CHANGED) { 204ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mPendingAction = PENDING_ACTION_CHANNEL_CHANGED; 205ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 206ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return; 207ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 208ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko updateActions(); 209ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 210ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko }; 211ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 212ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 213ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onCreate(Bundle savedInstanceState) { 2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // TODO: Handle USB TV tuner differently. 215ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Context context = getActivity(); 2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko ApplicationSingletons app = TvApplication.getSingletons(context); 2171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mInputManager = app.getTvInputManagerHelper(); 2181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelDataManager = app.getChannelDataManager(); 2191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mSetupUtils = SetupUtils.getInstance(context); 220ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko buildInputs(); 221ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mInputManager.addCallback(mInputCallback); 222ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelDataManager.addListener(mChannelDataManagerListener); 223ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super.onCreate(savedInstanceState); 2241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 227ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onDestroy() { 228ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super.onDestroy(); 229ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelDataManager.removeListener(mChannelDataManagerListener); 230ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mInputManager.removeCallback(mInputCallback); 2311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 233ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @NonNull 2347d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 2357d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko public Guidance onCreateGuidance(Bundle savedInstanceState) { 2367d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko String title = getString(R.string.setup_sources_text); 2377d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko String description = getString(R.string.setup_sources_description); 2387d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko return new Guidance(title, description, null, null); 2397d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 2407d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 2417d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 242ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public GuidedActionsStylist onCreateActionsStylist() { 243ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return new SetupSourceGuidedActionsStylist(); 244ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 2451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 246ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 247ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onCreateActions(@NonNull List<GuidedAction> actions, 248ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Bundle savedInstanceState) { 249ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko createActionsInternal(actions); 250ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 2511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 252ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private void buildInputs() { 253ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko List<TvInputInfo> oldInputs = mInputs; 254ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mInputs = mInputManager.getTvInputInfos(true, true); 255ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Get newly installed input ID. 256ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (oldInputs != null) { 257ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko List<TvInputInfo> newList = new ArrayList<>(mInputs); 258ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko for (TvInputInfo input : oldInputs) { 259ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko newList.remove(input); 260ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 261ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (newList.size() > 0 && mSetupUtils.isNewInput(newList.get(0).getId())) { 262ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mNewlyAddedInputId = newList.get(0).getId(); 263ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } else { 264ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mNewlyAddedInputId = null; 265ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 266ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 267ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Collections.sort(mInputs, new TvInputNewComparator(mSetupUtils, mInputManager)); 268ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mKnownInputStartIndex = 0; 269ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mDoneInputStartIndex = 0; 270ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko for (TvInputInfo input : mInputs) { 271ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mSetupUtils.isNewInput(input.getId())) { 272ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mSetupUtils.markAsKnownInput(input.getId()); 273ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ++mKnownInputStartIndex; 274ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 275ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (!mSetupUtils.isSetupDone(input.getId())) { 276ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ++mDoneInputStartIndex; 277ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 2781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void updateActions() { 2821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko List<GuidedAction> actions = new ArrayList<>(); 2831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko createActionsInternal(actions); 2841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko setActions(actions); 2851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void createActionsInternal(List<GuidedAction> actions) { 288ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko int newPosition = -1; 289ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko int position = 0; 290ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mDoneInputStartIndex > 0) { 291ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Need a "New" category 292ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_HEADER) 293ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .title(null).description(getString(R.string.setup_category_new)) 294ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .focusable(false).build()); 295ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 296ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko for (int i = 0; i < mInputs.size(); ++i) { 297ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (i == mDoneInputStartIndex) { 298ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ++position; 299ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_HEADER) 300ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .title(null).description(getString(R.string.setup_category_done)) 301ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .focusable(false).build()); 3021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 303ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko TvInputInfo input = mInputs.get(i); 304ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko String inputId = input.getId(); 3051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko String description; 306ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko int channelCount = mChannelDataManager.getChannelCountForInput(inputId); 307ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mSetupUtils.isSetupDone(inputId) || channelCount > 0) { 3081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (channelCount == 0) { 309ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko description = getString(R.string.setup_input_no_channels); 3101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 3111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko description = getResources().getQuantityString( 3121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko R.plurals.setup_input_channels, channelCount, channelCount); 3131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else if (i >= mKnownInputStartIndex) { 315ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko description = getString(R.string.setup_input_setup_now); 3161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 317ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko description = getString(R.string.setup_input_new); 3181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 319ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ++position; 320ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (input.getId().equals(mNewlyAddedInputId)) { 321ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko newPosition = position; 322ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 323ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_INPUT_START + i) 3241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko .title(input.loadLabel(getActivity()).toString()).description(description) 3251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko .build()); 3261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 327ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (Features.ONBOARDING_PLAY_STORE.isEnabled(getActivity())) { 328ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mInputs.size() > 0) { 329ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Divider 330ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ++position; 331ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_DIVIDER) 332ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .title(null).description(null).focusable(false).build()); 333ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 334ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Play store action 335ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ++position; 336ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_PLAY_STORE) 337ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .title(getString(R.string.setup_play_store_action_title)) 338ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .description(getString(R.string.setup_play_store_action_description)) 339ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .icon(R.drawable.ic_playstore).build()); 340ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 341ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (newPosition != -1) { 342ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko VerticalGridView gridView = getGuidedActionsStylist().getActionsGridView(); 343ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko gridView.setSelectedPosition(newPosition); 344ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 345ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 346ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 347ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 348ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected String getActionCategory() { 349ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return ACTION_CATEGORY; 3501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 3531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void onGuidedActionClicked(GuidedAction action) { 354ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (action.getId() == ACTION_PLAY_STORE) { 355ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mParentFragment.onActionClick(ACTION_CATEGORY, (int) action.getId()); 356ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return; 357ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 358ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko TvInputInfo input = mInputs.get((int) action.getId() - ACTION_INPUT_START); 359ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mParentFragment.mInputSetupRunnable != null) { 360ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mParentFragment.mInputSetupRunnable.runInputSetup(input); 361ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return; 362ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 3631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Intent intent = TvCommonUtils.createSetupIntent(input); 3641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (intent == null) { 3651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Toast.makeText(getActivity(), R.string.msg_no_setup_activity, Toast.LENGTH_SHORT) 3661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko .show(); 3671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 3681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Even though other app can handle the intent, the setup launched by Live channels 3701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // should go through Live channels SetupPassthroughActivity. 3711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko intent.setComponent(new ComponentName(getActivity(), SetupPassthroughActivity.class)); 3721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko try { 373ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Now we know that the user intends to set up this input. Grant permission for 374ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // writing EPG data. 3751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko SetupUtils.grantEpgPermission(getActivity(), input.getServiceInfo().packageName); 3761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko startActivityForResult(intent, REQUEST_CODE_START_SETUP_ACTIVITY); 3771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } catch (ActivityNotFoundException e) { 3781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Toast.makeText(getActivity(), getString(R.string.msg_unable_to_start_setup_activity, 3791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko input.loadLabel(getActivity())), Toast.LENGTH_SHORT).show(); 3801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 3841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void onActivityResult(int requestCode, int resultCode, Intent data) { 3851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko updateActions(); 3861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 388ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko void executePendingAction() { 389ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko switch (mPendingAction) { 390ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko case PENDING_ACTION_INPUT_CHANGED: 391ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko buildInputs(); 392ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Fall through 393ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko case PENDING_ACTION_CHANNEL_CHANGED: 394ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko updateActions(); 395ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko break; 3961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 397ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mPendingAction = PENDING_ACTION_NONE; 398ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 399ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 400ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private class SetupSourceGuidedActionsStylist extends GuidedActionsStylist { 401ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int VIEW_TYPE_DIVIDER = 1; 402ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 403ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final float ALPHA_CATEGORY = 1.0f; 404ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final float ALPHA_INPUT_DESCRIPTION = 0.5f; 4051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 4061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 407ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public int getItemViewType(GuidedAction action) { 408ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (action.getId() == ACTION_DIVIDER) { 4091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return VIEW_TYPE_DIVIDER; 4101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 411ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return super.getItemViewType(action); 4121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 4141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 415ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public int onProvideItemLayoutId(int viewType) { 416ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (viewType == VIEW_TYPE_DIVIDER) { 417ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return R.layout.onboarding_item_divider; 4181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 419ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return super.onProvideItemLayoutId(viewType); 4201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 4221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 423ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onBindViewHolder(ViewHolder vh, GuidedAction action) { 424ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super.onBindViewHolder(vh, action); 425ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko TextView descriptionView = vh.getDescriptionView(); 426ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (descriptionView != null) { 427ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (action.getId() == ACTION_HEADER) { 428ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko descriptionView.setAlpha(ALPHA_CATEGORY); 429ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko descriptionView.setTextColor(Utils.getColor(getResources(), 430ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko R.color.setup_category)); 431ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko descriptionView.setTypeface(Typeface.create( 432ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko getString(R.string.condensed_font), 0)); 433ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } else { 434ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko descriptionView.setAlpha(ALPHA_INPUT_DESCRIPTION); 435ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko descriptionView.setTextColor(Utils.getColor(getResources(), 436ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko R.color.common_setup_input_description)); 437ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko descriptionView.setTypeface(Typeface.create(getString(R.string.font), 0)); 438ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 4391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 440ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Workaround for b/26473407. 441ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ImageView iconView = vh.getIconView(); 442ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (iconView != null) { 443ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Drawable icon = action.getIcon(); 444ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (icon != null) { 445ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // setImageDrawable resets the drawable's level unless we set the view level 446ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // first. 447ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko iconView.setImageLevel(icon.getLevel()); 448ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko iconView.setImageDrawable(icon); 449ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko iconView.setVisibility(View.VISIBLE); 450ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } else { 451ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko iconView.setVisibility(View.GONE); 452ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 4531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4577d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko} 458