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 171abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopackage com.android.usbtuner; 181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.BroadcastReceiver; 201abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.ComponentName; 211abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Intent; 231abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.pm.PackageManager; 241abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.hardware.usb.UsbDevice; 251abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.hardware.usb.UsbManager; 2648dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.media.tv.TvInputInfo; 2748dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.media.tv.TvInputManager; 2848dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.media.tv.TvInputService; 291abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.Build; 301abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.Handler; 311abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.Looper; 321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.Message; 3348dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.support.v4.os.BuildCompat; 341abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Log; 351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 361abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.Features; 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.TvApplication; 38ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.usbtuner.setup.TunerSetupActivity; 391abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.usbtuner.tvinput.UsbTunerTvInputService; 401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 411abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Map; 421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Controls the package visibility of {@link UsbTunerTvInputService}. 451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * <p> 461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Listens to broadcast intent for {@link Intent#ACTION_BOOT_COMPLETED}, 471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * {@code UsbManager.ACTION_USB_DEVICE_ATTACHED}, and {@code UsbManager.ACTION_USB_DEVICE_ATTACHED} 481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * to update the connection status of the supported USB TV tuners. 491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 501abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class UsbInputController extends BroadcastReceiver { 5148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final boolean DEBUG = true; 521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final String TAG = "UsbInputController"; 531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final TunerDevice[] TUNER_DEVICES = { 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko new TunerDevice(0x2040, 0xb123), // WinTV-HVR-955Q 561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko new TunerDevice(0x07ca, 0x0837) // AverTV Volar Hybrid Q 571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }; 581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final boolean IS_MNC_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; 601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final int MSG_ENABLE_INPUT_SERVICE = 1000; 621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final long DVB_DRIVER_CHECK_DELAY_MS = 300; 631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private DvbDeviceAccessor mDvbDeviceAccessor; 6548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final Handler mHandler = new Handler(Looper.getMainLooper()) { 661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void handleMessage(Message msg) { 681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko switch (msg.what) { 691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko case MSG_ENABLE_INPUT_SERVICE: 701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Context context = (Context) msg.obj; 711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mDvbDeviceAccessor == null) { 721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mDvbDeviceAccessor = new DvbDeviceAccessor(context); 731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko enableUsbTunerTvInputService(context, 751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mDvbDeviceAccessor.isDvbDeviceAvailable()); 761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko break; 771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }; 801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Simple data holder for a USB device. Used to represent a tuner model, and compare 831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * against {@link UsbDevice}. 841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static class TunerDevice { 861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final int vendorId; 871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final int productId; 881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private TunerDevice(int vendorId, int productId) { 901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this.vendorId = vendorId; 911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko this.productId = productId; 921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private boolean equals(UsbDevice device) { 951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return device.getVendorId() == vendorId && device.getProductId() == productId; 961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void onReceive(Context context, Intent intent) { 1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) Log.d(TAG, "Broadcast intent received:" + intent); 1021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!Features.USB_TUNER.isEnabled(context)) { 1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko enableUsbTunerTvInputService(context, false); 1051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 1061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko switch (intent.getAction()) { 1091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko case Intent.ACTION_BOOT_COMPLETED: 1101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko case UsbManager.ACTION_USB_DEVICE_ATTACHED: 1111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko case UsbManager.ACTION_USB_DEVICE_DETACHED: 1121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Tuner is supported on MNC and later version only. 1131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko boolean enabled = IS_MNC_OR_LATER && isTunerConnected(context); 1141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mHandler.removeMessages(MSG_ENABLE_INPUT_SERVICE); 1151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (enabled) { 1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Need to check if DVB driver is accessible. Since the driver creation 1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // could be happen after the USB event, delay the checking by 1181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // DVB_DRIVER_CHECK_DELAY_MS. 1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mHandler.sendMessageDelayed( 1201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mHandler.obtainMessage(MSG_ENABLE_INPUT_SERVICE, context), 1211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko DVB_DRIVER_CHECK_DELAY_MS); 1221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 1231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko enableUsbTunerTvInputService(context, false); 1241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko break; 1261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 1301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See if any USB tuner hardware is attached in the system. 1311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 1321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @param context {@link Context} instance 1331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @return {@code true} if any tuner device we support is plugged in 1341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 1351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private boolean isTunerConnected(Context context) { 1361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE); 1371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Map<String, UsbDevice> deviceList = manager.getDeviceList(); 1381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (UsbDevice device : deviceList.values()) { 1391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) { 1401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.d(TAG, "Device: " + device); 1411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (TunerDevice tuner : TUNER_DEVICES) { 1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (tuner.equals(device)) { 1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.i(TAG, "Tuner found"); 1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return true; 1461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return false; 1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Enable/disable the component {@link UsbTunerTvInputService}. 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @param context {@link Context} instance 1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @param enabled {@code true} to enable the service; otherwise {@code false} 1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void enableUsbTunerTvInputService(Context context, boolean enabled) { 1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko PackageManager pm = context.getPackageManager(); 1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko ComponentName USBTUNER = new ComponentName(context, UsbTunerTvInputService.class); 1611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 16248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // Don't kill app by enabling/disabling TvActivity. If LC is killed by enabling/disabling 16348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // TvActivity, the following pm.setComponentEnabledSetting doesn't work. 16448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ((TvApplication) context.getApplicationContext()).handleInputCountChanged( 16548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho true, enabled, true); 1661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Since PackageManager.DONT_KILL_APP delays the operation by 10 seconds 1671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // (PackageManagerService.BROADCAST_DELAY), we'd better avoid using it. It is used only 1681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // when the LiveChannels app is active since we don't want to kill the running app. 169ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko int flags = TvApplication.getSingletons(context).getMainActivityWrapper().isCreated() 1701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko ? PackageManager.DONT_KILL_APP : 0; 1711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int newState = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED 1721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (newState != pm.getComponentEnabledSetting(USBTUNER)) { 1741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Send/cancel the USB tuner TV input setup recommendation card. 1751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko TunerSetupActivity.onTvInputEnabled(context, enabled); 1761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Enable/disable the USB tuner TV input. 1771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko pm.setComponentEnabledSetting(USBTUNER, newState, flags); 1781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) Log.d(TAG, "Status updated:" + enabled); 1791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 18048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (enabled && BuildCompat.isAtLeastN()) { 18148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho TvInputInfo info = mDvbDeviceAccessor.buildTvInputInfo(context); 18248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (info != null) { 18348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.i(TAG, "TvInputInfo updated: " + info.toString()); 18448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ((TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE)) 18548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .updateTvInputInfo(info); 18648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 18748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 1881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 190