/* * Copyright (C) 2015 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; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.android.tv.Features; import com.android.tv.R; import com.android.tv.TvApplication; import com.android.tv.common.SoftPreconditions; import com.android.tv.tuner.setup.TunerSetupActivity; import com.android.tv.tuner.tvinput.TunerTvInputService; import com.android.tv.tuner.util.SystemPropertiesProxy; import com.android.tv.tuner.util.TunerInputInfoUtils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Controls the package visibility of {@link TunerTvInputService}. *
* Listens to broadcast intent for {@link Intent#ACTION_BOOT_COMPLETED},
* {@code UsbManager.ACTION_USB_DEVICE_ATTACHED}, and {@code UsbManager.ACTION_USB_DEVICE_ATTACHED}
* to update the connection status of the supported USB TV tuners.
*/
public class TunerInputController {
private static final boolean DEBUG = true;
private static final String TAG = "TunerInputController";
private static final String PREFERENCE_IS_NETWORK_TUNER_ATTACHED = "network_tuner";
private static final String SECURITY_PATCH_LEVEL_KEY = "ro.build.version.security_patch";
private static final String SECURITY_PATCH_LEVEL_FORMAT = "yyyy-MM-dd";
/**
* Action of {@link Intent} to check network connection repeatedly when it is necessary.
*/
private static final String CHECKING_NETWORK_CONNECTION =
"com.android.tv.action.CHECKING_NETWORK_CONNECTION";
private static final String EXTRA_CHECKING_DURATION =
"com.android.tv.action.extra.CHECKING_DURATION";
private static final long INITIAL_CHECKING_DURATION_MS = TimeUnit.SECONDS.toMillis(10);
private static final long MAXIMUM_CHECKING_DURATION_MS = TimeUnit.MINUTES.toMillis(10);
private static final TunerDevice[] TUNER_DEVICES = {
new TunerDevice(0x2040, 0xb123, null), // WinTV-HVR-955Q
new TunerDevice(0x07ca, 0x0837, null), // AverTV Volar Hybrid Q
// WinTV-dualHD (bulk) will be supported after 2017 April security patch.
new TunerDevice(0x2040, 0x826d, "2017-04-01"), // WinTV-dualHD (bulk)
// STOPSHIP: Add WinTV-soloHD (Isoc) temporary for test. Remove this after test complete.
new TunerDevice(0x2040, 0x0264, null),
};
private static final int MSG_ENABLE_INPUT_SERVICE = 1000;
private static final long DVB_DRIVER_CHECK_DELAY_MS = 300;
/**
* Checks status of USB devices to see if there are available USB tuners connected.
*/
public static void onCheckingUsbTunerStatus(Context context, String action) {
onCheckingUsbTunerStatus(context, action, new CheckDvbDeviceHandler());
}
private static void onCheckingUsbTunerStatus(Context context, String action,
@NonNull CheckDvbDeviceHandler handler) {
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context);
if (TunerHal.useBuiltInTuner(context)) {
enableTunerTvInputService(context, true, false, TunerHal.TUNER_TYPE_BUILT_IN);
return;
}
// Falls back to the below to check USB tuner devices.
boolean enabled = isUsbTunerConnected(context);
handler.removeMessages(MSG_ENABLE_INPUT_SERVICE);
if (enabled) {
// Need to check if DVB driver is accessible. Since the driver creation
// could be happen after the USB event, delay the checking by
// DVB_DRIVER_CHECK_DELAY_MS.
handler.sendMessageDelayed(handler.obtainMessage(MSG_ENABLE_INPUT_SERVICE, context),
DVB_DRIVER_CHECK_DELAY_MS);
} else {
if (sharedPreferences.getBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, false)) {
// Since network tuner is attached, do not disable TunerTvInput,
// just updates the TvInputInfo.
TunerInputInfoUtils.updateTunerInputInfo(context);
return;
}
enableTunerTvInputService(context, false, false, TextUtils
.equals(action, UsbManager.ACTION_USB_DEVICE_DETACHED) ?
TunerHal.TUNER_TYPE_USB : null);
}
}
private static void onNetworkTunerChanged(Context context, boolean enabled) {
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context);
if (enabled) {
// Network tuner detection is initiated by UI. So the app should not
// be killed.
sharedPreferences.edit().putBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, true).apply();
enableTunerTvInputService(context, true, true, TunerHal.TUNER_TYPE_NETWORK);
} else {
sharedPreferences.edit()
.putBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, false).apply();
if(!isUsbTunerConnected(context) && !TunerHal.useBuiltInTuner(context)) {
// Network tuner detection is initiated by UI. So the app should not
// be killed.
enableTunerTvInputService(context, false, true, TunerHal.TUNER_TYPE_NETWORK);
} else {
// Since USB tuner is attached, do not disable TunerTvInput,
// just updates the TvInputInfo.
TunerInputInfoUtils.updateTunerInputInfo(context);
}
}
}
/**
* See if any USB tuner hardware is attached in the system.
*
* @param context {@link Context} instance
* @return {@code true} if any tuner device we support is plugged in
*/
private static boolean isUsbTunerConnected(Context context) {
UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
Map