aboutsummaryrefslogtreecommitdiff
path: root/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java')
-rw-r--r--tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java462
1 files changed, 462 insertions, 0 deletions
diff --git a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java
new file mode 100644
index 00000000..54b3a9e7
--- /dev/null
+++ b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.tuner.sample.dvb.setup;
+
+import android.app.FragmentManager;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.media.tv.TvInputInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.view.KeyEvent;
+import com.android.tv.common.BaseApplication;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.ui.setup.SetupFragment;
+import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
+import com.android.tv.common.util.PostalCodeUtils;
+import com.android.tv.tuner.TunerHal;
+import com.android.tv.tuner.sample.dvb.R;
+import com.android.tv.tuner.setup.BaseTunerSetupActivity;
+import com.android.tv.tuner.setup.ConnectionTypeFragment;
+import com.android.tv.tuner.setup.LineupFragment;
+import com.android.tv.tuner.setup.PostalCodeFragment;
+import com.android.tv.tuner.setup.ScanFragment;
+import com.android.tv.tuner.setup.ScanResultFragment;
+import com.android.tv.tuner.setup.WelcomeFragment;
+import com.google.android.tv.partner.support.EpgContract;
+import com.google.android.tv.partner.support.EpgInput;
+import com.google.android.tv.partner.support.EpgInputs;
+import com.google.android.tv.partner.support.Lineup;
+import com.google.android.tv.partner.support.Lineups;
+import com.google.android.tv.partner.support.TunerSetupUtils;
+import java.util.ArrayList;
+import java.util.List;
+
+/** An activity that serves Live TV tuner setup process. */
+public class SampleDvbTunerSetupActivity extends BaseTunerSetupActivity {
+ private static final String TAG = "SampleDvbTunerSetupActivity";
+ private static final boolean DEBUG = false;
+
+ private static final int FETCH_LINEUP_TIMEOUT_MS = 10000; // 10 seconds
+ private static final int FETCH_LINEUP_RETRY_TIMEOUT_MS = 20000; // 20 seconds
+ private static final String OTAD_PREFIX = "OTAD";
+ private static final String STRING_BROADCAST_DIGITAL = "Broadcast Digital";
+
+ private LineupFragment currentLineupFragment;
+
+ private List<String> channelNumbers;
+ private List<Lineup> lineups;
+ private Lineup selectedLineup;
+ private List<Pair<Lineup, Integer>> lineupMatchCountPair;
+ private FetchLineupTask fetchLineupTask;
+ private EpgInput epgInput;
+ private String postalCode;
+ private final Handler handler = new Handler();
+ private final Runnable cancelFetchLineupTaskRunnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ cancelFetchLineup();
+ }
+ };
+ private String embeddedInputId;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ if (DEBUG) {
+ Log.d(TAG, "onCreate");
+ }
+ embeddedInputId = BaseApplication.getSingletons(this).getEmbeddedTunerInputId();
+ new QueryEpgInputTask(embeddedInputId).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void executeGetTunerTypeAndCountAsyncTask() {
+ new AsyncTask<Void, Void, Integer>() {
+ @Override
+ protected Integer doInBackground(Void... arg0) {
+ return TunerHal.getTunerTypeAndCount(SampleDvbTunerSetupActivity.this).first;
+ }
+
+ @Override
+ protected void onPostExecute(Integer result) {
+ if (!SampleDvbTunerSetupActivity.this.isDestroyed()) {
+ mTunerType = result;
+ if (result == null) {
+ finish();
+ } else if (!mActivityStopped) {
+ showInitialFragment();
+ } else {
+ mPendingShowInitialFragment = true;
+ }
+ }
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ @Override
+ protected boolean executeAction(String category, int actionId, Bundle params) {
+ switch (category) {
+ case WelcomeFragment.ACTION_CATEGORY:
+ switch (actionId) {
+ case SetupMultiPaneFragment.ACTION_DONE:
+ super.executeAction(category, actionId, params);
+ break;
+ default:
+ String postalCode = PostalCodeUtils.getLastPostalCode(this);
+ if (mNeedToShowPostalCodeFragment
+ || (CommonFeatures.ENABLE_CLOUD_EPG_REGION.isEnabled(
+ getApplicationContext())
+ && TextUtils.isEmpty(postalCode))) {
+ // We cannot get postal code automatically. Postal code input fragment
+ // should always be shown even if users have input some valid postal
+ // code in this activity before.
+ mNeedToShowPostalCodeFragment = true;
+ showPostalCodeFragment();
+ } else {
+ lineups = null;
+ selectedLineup = null;
+ this.postalCode = postalCode;
+ restartFetchLineupTask();
+ showConnectionTypeFragment();
+ }
+ break;
+ }
+ return true;
+ case PostalCodeFragment.ACTION_CATEGORY:
+ lineups = null;
+ selectedLineup = null;
+ switch (actionId) {
+ case SetupMultiPaneFragment.ACTION_DONE:
+ String postalCode = params.getString(PostalCodeFragment.KEY_POSTAL_CODE);
+ if (postalCode != null) {
+ this.postalCode = postalCode;
+ restartFetchLineupTask();
+ }
+ // fall through
+ case SetupMultiPaneFragment.ACTION_SKIP:
+ showConnectionTypeFragment();
+ break;
+ default: // fall out
+ }
+ return true;
+ case ConnectionTypeFragment.ACTION_CATEGORY:
+ channelNumbers = null;
+ lineupMatchCountPair = null;
+ return super.executeAction(category, actionId, params);
+ case ScanFragment.ACTION_CATEGORY:
+ switch (actionId) {
+ case ScanFragment.ACTION_CANCEL:
+ getFragmentManager().popBackStack();
+ return true;
+ case ScanFragment.ACTION_FINISH:
+ clearTunerHal();
+ channelNumbers =
+ params.getStringArrayList(ScanFragment.KEY_CHANNEL_NUMBERS);
+ selectedLineup = null;
+ if (CommonFeatures.ENABLE_CLOUD_EPG_REGION.isEnabled(
+ getApplicationContext())
+ && channelNumbers != null
+ && !channelNumbers.isEmpty()
+ && !TextUtils.isEmpty(this.postalCode)) {
+ showLineupFragment();
+ } else {
+ showScanResultFragment();
+ }
+ return true;
+ default: // fall out
+ }
+ break;
+ case LineupFragment.ACTION_CATEGORY:
+ switch (actionId) {
+ case LineupFragment.ACTION_SKIP:
+ selectedLineup = null;
+ currentLineupFragment = null;
+ showScanResultFragment();
+ break;
+ case LineupFragment.ACTION_ID_RETRY:
+ currentLineupFragment.onRetry();
+ restartFetchLineupTask();
+ handler.postDelayed(
+ cancelFetchLineupTaskRunnable, FETCH_LINEUP_RETRY_TIMEOUT_MS);
+ break;
+ default:
+ if (actionId >= 0 && actionId < lineupMatchCountPair.size()) {
+ if (DEBUG) {
+ if (selectedLineup != null) {
+ Log.d(
+ TAG,
+ "Lineup " + selectedLineup.getName() + " is selected.");
+ }
+ }
+ selectedLineup = lineupMatchCountPair.get(actionId).first;
+ }
+ currentLineupFragment = null;
+ showScanResultFragment();
+ break;
+ }
+ return true;
+ case ScanResultFragment.ACTION_CATEGORY:
+ switch (actionId) {
+ case SetupMultiPaneFragment.ACTION_DONE:
+ new SampleDvbTunerSetupActivity.InsertOrModifyEpgInputTask(
+ selectedLineup, embeddedInputId)
+ .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ break;
+ default:
+ // scan again
+ if (lineups == null || lineups.isEmpty()) {
+ lineups = null;
+ restartFetchLineupTask();
+ }
+ super.executeAction(category, actionId, params);
+ break;
+ }
+ return true;
+ default: // fall out
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ FragmentManager manager = getFragmentManager();
+ int count = manager.getBackStackEntryCount();
+ if (count > 0) {
+ String lastTag = manager.getBackStackEntryAt(count - 1).getName();
+ if (LineupFragment.class.getCanonicalName().equals(lastTag) && count >= 2) {
+ // Pops fragment including ScanFragment.
+ manager.popBackStack(
+ manager.getBackStackEntryAt(count - 2).getName(),
+ FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ return true;
+ }
+ if (ScanResultFragment.class.getCanonicalName().equals(lastTag) && count >= 2) {
+ String secondLastTag = manager.getBackStackEntryAt(count - 2).getName();
+ if (ScanFragment.class.getCanonicalName().equals(secondLastTag)) {
+ // Pops fragment including ScanFragment.
+ manager.popBackStack(
+ secondLastTag, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ return true;
+ }
+ if (LineupFragment.class.getCanonicalName().equals(secondLastTag)) {
+ currentLineupFragment =
+ (LineupFragment) manager.findFragmentByTag(secondLastTag);
+ if (lineups == null || lineups.isEmpty()) {
+ lineups = null;
+ restartFetchLineupTask();
+ }
+ }
+ } else if (ScanFragment.class.getCanonicalName().equals(lastTag)) {
+ mLastScanFragment.finishScan(true);
+ return true;
+ }
+ }
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ private void showLineupFragment() {
+ if (lineupMatchCountPair == null && lineups != null) {
+ lineupMatchCountPair = TunerSetupUtils.lineupChannelMatchCount(lineups, channelNumbers);
+ }
+ currentLineupFragment = new LineupFragment();
+ currentLineupFragment.setArguments(getArgsForLineupFragment());
+ currentLineupFragment.setShortDistance(
+ SetupFragment.FRAGMENT_ENTER_TRANSITION | SetupFragment.FRAGMENT_RETURN_TRANSITION);
+ handler.removeCallbacksAndMessages(null);
+ showFragment(currentLineupFragment, true);
+ handler.postDelayed(cancelFetchLineupTaskRunnable, FETCH_LINEUP_TIMEOUT_MS);
+ }
+
+ private Bundle getArgsForLineupFragment() {
+ Bundle args = new Bundle();
+ if (lineupMatchCountPair == null) {
+ return args;
+ }
+ ArrayList<String> lineupNames = new ArrayList<>(lineupMatchCountPair.size());
+ ArrayList<Integer> matchNumbers = new ArrayList<>(lineupMatchCountPair.size());
+ int defaultLineupIndex = 0;
+ for (Pair<Lineup, Integer> pair : lineupMatchCountPair) {
+ Lineup lineup = pair.first;
+ String name;
+ if (!TextUtils.isEmpty(lineup.getName())) {
+ name = lineup.getName();
+ } else {
+ name = lineup.getId();
+ }
+ if (name.equals(OTAD_PREFIX + postalCode) || name.equals(STRING_BROADCAST_DIGITAL)) {
+ // rename OTA / antenna lineups
+ name = getString(R.string.ut_lineup_name_antenna);
+ }
+ lineupNames.add(name);
+ matchNumbers.add(pair.second);
+ if (epgInput != null && TextUtils.equals(lineup.getId(), epgInput.getLineupId())) {
+ // The last index is the current one.
+ defaultLineupIndex = lineupNames.size() - 1;
+ }
+ }
+ args.putStringArrayList(LineupFragment.KEY_LINEUP_NAMES, lineupNames);
+ args.putIntegerArrayList(LineupFragment.KEY_MATCH_NUMBERS, matchNumbers);
+ args.putInt(LineupFragment.KEY_DEFAULT_LINEUP, defaultLineupIndex);
+ return args;
+ }
+
+ private void cancelFetchLineup() {
+ if (fetchLineupTask == null) {
+ return;
+ }
+ AsyncTask.Status status = fetchLineupTask.getStatus();
+ if (status == AsyncTask.Status.RUNNING || status == AsyncTask.Status.PENDING) {
+ fetchLineupTask.cancel(true);
+ fetchLineupTask = null;
+ if (currentLineupFragment != null) {
+ currentLineupFragment.onLineupNotFound();
+ }
+ }
+ }
+
+ private void restartFetchLineupTask() {
+ if (!CommonFeatures.ENABLE_CLOUD_EPG_REGION.isEnabled(getApplicationContext())
+ || TextUtils.isEmpty(postalCode)) {
+ return;
+ }
+ if (fetchLineupTask != null) {
+ fetchLineupTask.cancel(true);
+ }
+ handler.removeCallbacksAndMessages(null);
+ fetchLineupTask = new FetchLineupTask(getContentResolver(), postalCode);
+ fetchLineupTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private class FetchLineupTask extends AsyncTask<Void, Void, List<Lineup>> {
+ private final ContentResolver contentResolver;
+ private final String postalCode;
+
+ FetchLineupTask(ContentResolver contentResolver, String postalCode) {
+ this.contentResolver = contentResolver;
+ this.postalCode = postalCode;
+ }
+
+ @Override
+ protected List<Lineup> doInBackground(Void... args) {
+ if (contentResolver == null || TextUtils.isEmpty(postalCode)) {
+ return new ArrayList<>();
+ }
+ return new ArrayList<>(Lineups.query(contentResolver, postalCode));
+ }
+
+ @Override
+ protected void onPostExecute(List<Lineup> lineups) {
+ if (DEBUG) {
+ if (lineups != null) {
+ Log.d(TAG, "FetchLineupTask fetched " + lineups.size() + " lineups");
+ } else {
+ Log.d(TAG, "FetchLineupTask returned null");
+ }
+ }
+ SampleDvbTunerSetupActivity.this.lineups = lineups;
+ if (currentLineupFragment != null) {
+ if (lineups == null || lineups.isEmpty()) {
+ currentLineupFragment.onLineupNotFound();
+ } else {
+ lineupMatchCountPair =
+ TunerSetupUtils.lineupChannelMatchCount(
+ SampleDvbTunerSetupActivity.this.lineups, channelNumbers);
+ currentLineupFragment.onLineupFound(getArgsForLineupFragment());
+ }
+ }
+ }
+ }
+
+ private class InsertOrModifyEpgInputTask extends AsyncTask<Void, Void, Void> {
+ private final Lineup lineup;
+ private final String inputId;
+
+ InsertOrModifyEpgInputTask(@Nullable Lineup lineup, String inputId) {
+ this.lineup = lineup;
+ this.inputId = inputId;
+ }
+
+ @Override
+ protected Void doInBackground(Void... args) {
+ if (lineup == null
+ || (SampleDvbTunerSetupActivity.this.epgInput != null
+ && TextUtils.equals(
+ lineup.getId(),
+ SampleDvbTunerSetupActivity.this.epgInput.getLineupId()))) {
+ return null;
+ }
+ ContentValues values = new ContentValues();
+ values.put(EpgContract.EpgInputs.COLUMN_INPUT_ID, inputId);
+ values.put(EpgContract.EpgInputs.COLUMN_LINEUP_ID, lineup.getId());
+
+ ContentResolver contentResolver = getContentResolver();
+ if (SampleDvbTunerSetupActivity.this.epgInput != null) {
+ values.put(
+ EpgContract.EpgInputs.COLUMN_ID,
+ SampleDvbTunerSetupActivity.this.epgInput.getId());
+ EpgInputs.update(contentResolver, EpgInput.createEpgChannel(values));
+ return null;
+ }
+ EpgInput epgInput = EpgInputs.queryEpgInput(contentResolver, inputId);
+ if (epgInput == null) {
+ contentResolver.insert(EpgContract.EpgInputs.CONTENT_URI, values);
+ } else {
+ values.put(EpgContract.EpgInputs.COLUMN_ID, epgInput.getId());
+ EpgInputs.update(contentResolver, EpgInput.createEpgChannel(values));
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ Intent data = new Intent();
+ data.putExtra(TvInputInfo.EXTRA_INPUT_ID, inputId);
+ data.putExtra(EpgContract.EXTRA_USE_CLOUD_EPG, true);
+ setResult(RESULT_OK, data);
+ finish();
+ }
+ }
+
+ private class QueryEpgInputTask extends AsyncTask<Void, Void, EpgInput> {
+ private final String inputId;
+
+ QueryEpgInputTask(String inputId) {
+ this.inputId = inputId;
+ }
+
+ @Override
+ protected EpgInput doInBackground(Void... args) {
+ ContentResolver contentResolver = getContentResolver();
+ return EpgInputs.queryEpgInput(contentResolver, inputId);
+ }
+
+ @Override
+ protected void onPostExecute(EpgInput result) {
+ epgInput = result;
+ }
+ }
+}