11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/* 21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project 31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License. 61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at 71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software 111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and 141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License. 151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.tuner.setup; 181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.animation.LayoutTransition; 201abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.app.Activity; 211abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.app.ProgressDialog; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context; 231abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.AsyncTask; 246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.os.Build; 251abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.Bundle; 261abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.ConditionVariable; 271abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.Handler; 281abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Log; 291abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.view.LayoutInflater; 301abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.view.View; 31ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.view.View.OnClickListener; 321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.view.ViewGroup; 331abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.widget.BaseAdapter; 341abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.widget.Button; 351abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.widget.ListView; 361abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.widget.ProgressBar; 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.widget.TextView; 381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.common.SoftPreconditions; 40ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.common.ui.setup.SetupFragment; 4165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.ChannelScanFileParser; 42721bd0da688cd552737fbb753a00597f95103b95Adrian Roosimport com.android.tv.tuner.R; 436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.tuner.TunerHal; 4465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.TunerPreferences; 4565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.data.PsipData; 4665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.data.TunerChannel; 476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.tuner.data.nano.Channel; 4865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.source.FileTsStreamer; 49d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport com.android.tv.tuner.source.TsDataSource; 5065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.source.TsStreamer; 5165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.source.TunerTsStreamer; 5265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.tvinput.ChannelDataManager; 5365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.tvinput.EventDetector; 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.ArrayList; 561abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.List; 5765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.util.Locale; 5865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.util.concurrent.CountDownLatch; 5965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.util.concurrent.TimeUnit; 601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 62ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * A fragment for scanning channels. 631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 64ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkopublic class ScanFragment extends SetupFragment { 65ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final String TAG = "ScanFragment"; 661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final boolean DEBUG = false; 676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 68ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // In the fake mode, the connection to antenna or cable is not necessary. 69ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Instead dummy channels are added. 70ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final boolean FAKE_MODE = false; 71ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 7265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private static final String VCTLESS_CHANNEL_NAME_FORMAT = "RF%d-%d"; 7365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 7465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public static final String ACTION_CATEGORY = "com.android.tv.tuner.setup.ScanFragment"; 75ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public static final int ACTION_CANCEL = 1; 76ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public static final int ACTION_FINISH = 2; 77ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 78ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public static final String EXTRA_FOR_CHANNEL_SCAN_FILE = "scan_file_choice"; 791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final long CHANNEL_SCAN_SHOW_DELAY_MS = 10000; 811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final long CHANNEL_SCAN_PERIOD_MS = 4000; 82ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final long SHOW_PROGRESS_DIALOG_DELAY_MS = 300; 831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Build channels out of the locally stored TS streams. 851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final boolean SCAN_LOCAL_STREAMS = true; 861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private ChannelDataManager mChannelDataManager; 881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private ChannelScanTask mChannelScanTask; 891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private ProgressBar mProgressBar; 901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private TextView mScanningMessage; 911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private View mChannelHolder; 921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private ChannelAdapter mAdapter; 931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private volatile boolean mChannelListVisible; 941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private Button mCancelButton; 951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 97ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public View onCreateView(LayoutInflater inflater, ViewGroup container, 98ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Bundle savedInstanceState) { 996ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (DEBUG) Log.d(TAG, "onCreateView"); 100ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko View view = super.onCreateView(inflater, container, savedInstanceState); 101ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelDataManager = new ChannelDataManager(getActivity()); 102ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelDataManager.checkDataVersion(getActivity()); 1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAdapter = new ChannelAdapter(); 104ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mProgressBar = (ProgressBar) view.findViewById(R.id.tune_progress); 105ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mScanningMessage = (TextView) view.findViewById(R.id.tune_description); 106ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ListView channelList = (ListView) view.findViewById(R.id.channel_list); 107ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko channelList.setAdapter(mAdapter); 108ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko channelList.setOnItemClickListener(null); 109ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ViewGroup progressHolder = (ViewGroup) view.findViewById(R.id.progress_holder); 1101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko LayoutTransition transition = new LayoutTransition(); 1111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko transition.enableTransitionType(LayoutTransition.CHANGING); 1121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko progressHolder.setLayoutTransition(transition); 113ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelHolder = view.findViewById(R.id.channel_holder); 114ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mCancelButton = (Button) view.findViewById(R.id.tune_cancel); 115ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mCancelButton.setOnClickListener(new OnClickListener() { 1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void onClick(View v) { 118ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko finishScan(false); 1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }); 121ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Bundle args = getArguments(); 1226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int tunerType = (args == null ? 0 : args.getInt(TunerSetupActivity.KEY_TUNER_TYPE, 0)); 123d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko // TODO: Handle the case when the fragment is restored. 124ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko startScan(args == null ? 0 : args.getInt(EXTRA_FOR_CHANNEL_SCAN_FILE, 0)); 12565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko TextView scanTitleView = (TextView) view.findViewById(R.id.tune_title); 1266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko switch (tunerType) { 1276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko case TunerHal.TUNER_TYPE_USB: 1286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko scanTitleView.setText(R.string.ut_channel_scan); 1296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko break; 1306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko case TunerHal.TUNER_TYPE_NETWORK: 1316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko scanTitleView.setText(R.string.nt_channel_scan); 1326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko break; 1336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko default: 1346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko scanTitleView.setText(R.string.bt_channel_scan); 13565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 136ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return view; 1371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 140ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected int getLayoutResourceId() { 141ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return R.layout.ut_channel_scan; 1421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 144ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 145ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected int[] getParentIdsForDelay() { 146ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return new int[] {R.id.progress_holder}; 1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 149ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private void startScan(int channelMapId) { 150ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelScanTask = new ChannelScanTask(channelMapId); 151ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelScanTask.execute(); 1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void onPause() { 1566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Log.d(TAG, "onPause"); 157d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko if (mChannelScanTask != null) { 158d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko // Ensure scan task will stop. 1596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Log.w(TAG, "The activity went to the background. Stopping channel scan."); 160d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mChannelScanTask.stopScan(); 161d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko } 1626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko super.onPause(); 1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 165ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 166ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Finishes the current scan thread. This fragment will be popped after the scan thread ends. 167ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 168ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * @param cancel a flag which indicates the scan is canceled or not. 169ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 170ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void finishScan(boolean cancel) { 1711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mChannelScanTask != null) { 172ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mChannelScanTask.cancelScan(cancel); 1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Notifies a user of waiting to finish the scanning process. 1751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko new Handler().postDelayed(new Runnable() { 1761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void run() { 1786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (mChannelScanTask != null) { 1796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mChannelScanTask.showFinishingProgressDialog(); 1806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 182ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko }, SHOW_PROGRESS_DIALOG_DELAY_MS); 1831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Hides the cancel button. 185ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mCancelButton.setEnabled(false); 1861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private class ChannelAdapter extends BaseAdapter { 1901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final ArrayList<TunerChannel> mChannels; 1911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public ChannelAdapter() { 1931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannels = new ArrayList<>(); 1941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean areAllItemsEnabled() { 1981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return false; 1991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isEnabled(int pos) { 2031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return false; 2041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public int getCount() { 2081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return mChannels.size(); 2091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public Object getItem(int pos) { 2131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return pos; 2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public long getItemId(int pos) { 2181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return pos; 2191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public View getView(int position, View convertView, ViewGroup parent) { 2231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko final Context context = parent.getContext(); 2241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (convertView == null) { 2261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko LayoutInflater inflater = (LayoutInflater) context 2271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 2281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko convertView = inflater.inflate(R.layout.ut_channel_list, parent, false); 2291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko TextView channelNum = (TextView) convertView.findViewById(R.id.channel_num); 2321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko channelNum.setText(mChannels.get(position).getDisplayNumber()); 2331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko TextView channelName = (TextView) convertView.findViewById(R.id.channel_name); 2351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko channelName.setText(mChannels.get(position).getName()); 2361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return convertView; 2371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void add(TunerChannel channel) { 2401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannels.add(channel); 2411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko notifyDataSetChanged(); 2421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 245ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private class ChannelScanTask extends AsyncTask<Void, Integer, Void> 246d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko implements EventDetector.EventListener, ChannelDataManager.ChannelScanListener { 2471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final int MAX_PROGRESS = 100; 2481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 249ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final Activity mActivity; 2501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final int mChannelMapId; 25165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final TsStreamer mScanTsStreamer; 25265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final TsStreamer mFileTsStreamer; 2531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final ConditionVariable mConditionStopped; 2541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 25565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final List<ChannelScanFileParser.ScanChannel> mScanChannelList = new ArrayList<>(); 256ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private boolean mIsCanceled; 2571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private boolean mIsFinished; 2581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private ProgressDialog mFinishingProgressDialog; 25965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private CountDownLatch mLatch; 2601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public ChannelScanTask(int channelMapId) { 262ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mActivity = getActivity(); 2631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelMapId = channelMapId; 26465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (FAKE_MODE) { 26565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mScanTsStreamer = new FakeTsStreamer(this); 26665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } else { 2676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko TunerHal hal = ((TunerSetupActivity) mActivity).getTunerHal(); 26865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (hal == null) { 26965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko throw new RuntimeException("Failed to open a DVB device"); 27065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 27165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mScanTsStreamer = new TunerTsStreamer(hal, this); 27265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 2736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mFileTsStreamer = SCAN_LOCAL_STREAMS ? new FileTsStreamer(this, mActivity) : null; 2741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mConditionStopped = new ConditionVariable(); 275d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mChannelDataManager.setChannelScanListener(this, new Handler()); 2761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void maybeSetChannelListVisible() { 279ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mActivity.runOnUiThread(new Runnable() { 2801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void run() { 2821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int channelsFound = mAdapter.getCount(); 2831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mChannelListVisible && channelsFound > 0) { 2841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko String format = getResources().getQuantityString( 2851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko R.plurals.ut_channel_scan_message, channelsFound, channelsFound); 2861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mScanningMessage.setText(String.format(format, channelsFound)); 2871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelHolder.setVisibility(View.VISIBLE); 2881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelListVisible = true; 2891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }); 2921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void addChannel(final TunerChannel channel) { 295ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mActivity.runOnUiThread(new Runnable() { 2961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void run() { 2981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAdapter.add(channel); 2991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mChannelListVisible) { 3001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int channelsFound = mAdapter.getCount(); 3011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko String format = getResources().getQuantityString( 3021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko R.plurals.ut_channel_scan_message, channelsFound, channelsFound); 3031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mScanningMessage.setText(String.format(format, channelsFound)); 3041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }); 3071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 3101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko protected Void doInBackground(Void... params) { 31165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mScanChannelList.clear(); 3121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (SCAN_LOCAL_STREAMS) { 31365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko FileTsStreamer.addLocalStreamFiles(mScanChannelList); 3141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 31565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mScanChannelList.addAll(ChannelScanFileParser.parseScanFile( 31665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko getResources().openRawResource(mChannelMapId))); 3171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko scanChannels(); 3181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return null; 3191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 32265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko protected void onCancelled() { 32365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko SoftPreconditions.checkState(false, TAG, "call cancelScan instead of cancel"); 32465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 32565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 32665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Override 3271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko protected void onProgressUpdate(Integer... values) { 3286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 3296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mProgressBar.setProgress(values[0], true); 3306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } else { 3316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mProgressBar.setProgress(values[0]); 3326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void stopScan() { 3366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (mLatch != null) { 3376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mLatch.countDown(); 3386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mConditionStopped.open(); 3401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 342ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private void cancelScan(boolean cancel) { 343ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mIsCanceled = cancel; 344ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko stopScan(); 345ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 346ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 3471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void scanChannels() { 3481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) Log.i(TAG, "Channel scan starting"); 3491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelDataManager.notifyScanStarted(); 3501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko long startMs = System.currentTimeMillis(); 3521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int i = 1; 35365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (ChannelScanFileParser.ScanChannel scanChannel : mScanChannelList) { 3541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int frequency = scanChannel.frequency; 3551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko String modulation = scanChannel.modulation; 3561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.i(TAG, "Tuning to " + frequency + " " + modulation); 3571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 35865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko TsStreamer streamer = getStreamer(scanChannel.type); 3596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko SoftPreconditions.checkNotNull(streamer); 3606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (streamer != null && streamer.startStream(scanChannel)) { 36165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mLatch = new CountDownLatch(1); 36265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko try { 36365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mLatch.await(CHANNEL_SCAN_PERIOD_MS, TimeUnit.MILLISECONDS); 36465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } catch (InterruptedException e) { 36565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko Log.e(TAG, "The current thread is interrupted during scanChannels(). " + 36665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko "The TS stream is stopped earlier than expected.", e); 36765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 36865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko streamer.stopStream(); 3691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 37065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko addChannelsWithoutVct(scanChannel); 3711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (System.currentTimeMillis() > startMs + CHANNEL_SCAN_SHOW_DELAY_MS 3721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko && !mChannelListVisible) { 373ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko maybeSetChannelListVisible(); 3741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mConditionStopped.block(-1)) { 3771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko break; 3781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko publishProgress(MAX_PROGRESS * i++ / mScanChannelList.size()); 38065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 3811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelDataManager.notifyScanCompleted(); 3821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mConditionStopped.block(-1)) { 3831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko publishProgress(MAX_PROGRESS); 3841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) Log.i(TAG, "Channel scan ended"); 3861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 38965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private void addChannelsWithoutVct(ChannelScanFileParser.ScanChannel scanChannel) { 39065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (scanChannel.radioFrequencyNumber == null 39165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko || !(mScanTsStreamer instanceof TunerTsStreamer)) { 39265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return; 39365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 39465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (TunerChannel tunerChannel 39565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko : ((TunerTsStreamer) mScanTsStreamer).getMalFormedChannels()) { 39665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if ((tunerChannel.getVideoPid() != TunerChannel.INVALID_PID) 39765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko && (tunerChannel.getAudioPid() != TunerChannel.INVALID_PID)) { 39865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko tunerChannel.setFrequency(scanChannel.frequency); 39965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko tunerChannel.setModulation(scanChannel.modulation); 40065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko tunerChannel.setShortName(String.format(Locale.US, VCTLESS_CHANNEL_NAME_FORMAT, 40165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko scanChannel.radioFrequencyNumber, 40265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko tunerChannel.getProgramNumber())); 40365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko tunerChannel.setVirtualMajor(scanChannel.radioFrequencyNumber); 40465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko tunerChannel.setVirtualMinor(tunerChannel.getProgramNumber()); 405d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko onChannelDetected(tunerChannel, true); 40665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 40765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 40865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 40965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 41065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private TsStreamer getStreamer(int type) { 4111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko switch (type) { 4121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko case Channel.TYPE_TUNER: 41365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return mScanTsStreamer; 4141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko case Channel.TYPE_FILE: 41565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return mFileTsStreamer; 4161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko default: 4171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return null; 4181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 4211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 422ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public void onEventDetected(TunerChannel channel, List<PsipData.EitItem> items) { 4231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelDataManager.notifyEventDetected(channel, items); 4241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 4261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 42765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onChannelScanDone() { 42865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (mLatch != null) { 42965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mLatch.countDown(); 4301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 43165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 43265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 43365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Override 43465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime) { 4351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (channelArrivedAtFirstTime) { 43665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko Log.i(TAG, "Found channel " + channel); 43765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 43865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (channelArrivedAtFirstTime && channel.hasAudio()) { 43965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko // Playbacks with video-only stream have not been tested yet. 44065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko // No video-only channel has been found. 4411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko addChannel(channel); 4426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mChannelDataManager.notifyChannelDetected(channel, channelArrivedAtFirstTime); 4431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 4451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 44665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void showFinishingProgressDialog() { 4471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Show a progress dialog to wait for the scanning process if it's not done yet. 448ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (!mIsFinished && mFinishingProgressDialog == null) { 449ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mFinishingProgressDialog = ProgressDialog.show(mActivity, "", 450ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko getString(R.string.ut_setup_cancel), true, false); 451ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 452ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 453d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko 454d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko @Override 455d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko public void onChannelHandlingDone() { 456d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mChannelDataManager.setCurrentVersion(mActivity); 457d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mChannelDataManager.releaseSafely(); 458d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mIsFinished = true; 459d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko TunerPreferences.setScannedChannelCount(mActivity.getApplicationContext(), 460d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mChannelDataManager.getScannedChannelCount()); 4616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // Cancel a previously shown notification. 4626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko TunerSetupActivity.cancelNotification(mActivity.getApplicationContext()); 463d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko // Mark scan as done 464d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko TunerPreferences.setScanDone(mActivity.getApplicationContext()); 465d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko // finishing will be done manually. 466d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko if (mFinishingProgressDialog != null) { 467d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mFinishingProgressDialog.dismiss(); 468d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko } 4696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // If the fragment is not resumed, the next fragment (scan result page) can't be 4706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // displayed. In that case, just close the activity. 4716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (isResumed()) { 4726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko onActionClick(ACTION_CATEGORY, mIsCanceled ? ACTION_CANCEL : ACTION_FINISH); 4736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } else if (getActivity() != null) { 4746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko getActivity().finish(); 4756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 476d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko mChannelScanTask = null; 477d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko } 478ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 479ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 48065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private static class FakeTsStreamer implements TsStreamer { 481ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final EventDetector.EventListener mEventListener; 482ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private int mProgramNumber = 0; 483ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 48465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko FakeTsStreamer(EventDetector.EventListener eventListener) { 485ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mEventListener = eventListener; 486ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 487ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 488ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 48965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public boolean startStream(ChannelScanFileParser.ScanChannel channel) { 490ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (++mProgramNumber % 2 == 1) { 49165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return true; 4921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 493ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko final String displayNumber = Integer.toString(mProgramNumber); 494ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko final String name = "Channel-" + mProgramNumber; 49565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mEventListener.onChannelDetected(new TunerChannel(mProgramNumber, new ArrayList<>()) { 496ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 497ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public String getDisplayNumber() { 498ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return displayNumber; 499ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 500ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 501ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 502ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public String getName() { 503ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return name; 504ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 505ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko }, true); 50665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return true; 507ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 508ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 509ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 51065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public boolean startStream(TunerChannel channel) { 51165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return false; 512ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 513ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 514ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 51565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void stopStream() { 516ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 517ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 518ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 519d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko public TsDataSource createDataSource() { 52065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return null; 5211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 5221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 5231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 524