1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.tuner.hdhomerun;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.preference.PreferenceManager;
22 import android.support.annotation.WorkerThread;
23 import android.util.Log;
24 import java.util.HashSet;
25 import java.util.Set;
26 
27 /**
28  * A class to manage tuner resources of HDHomeRun devices. It handles tuner resource acquisition and
29  * release.
30  */
31 class HdHomeRunTunerManager {
32     private static final String TAG = "HdHomeRunTunerManager";
33     private static final boolean DEBUG = false;
34 
35     private static final String PREF_KEY_SCANNED_DEVICE_ID = "scanned_device_id";
36 
37     private static HdHomeRunTunerManager sInstance;
38 
39     private final Set<HdHomeRunDevice> mHdHomeRunDevices = new HashSet<>();
40     private final Set<HdHomeRunDevice> mUsedDevices = new HashSet<>();
41 
HdHomeRunTunerManager()42     private HdHomeRunTunerManager() {}
43 
44     /** Returns the instance of this manager. */
getInstance()45     public static synchronized HdHomeRunTunerManager getInstance() {
46         if (sInstance == null) {
47             sInstance = new HdHomeRunTunerManager();
48         }
49         return sInstance;
50     }
51 
52     /** Returns number of tuners. */
53     @WorkerThread
getTunerCount()54     synchronized int getTunerCount() {
55         updateDevicesLocked(null);
56         if (DEBUG) Log.d(TAG, "getTunerCount: " + mHdHomeRunDevices.size());
57         return mHdHomeRunDevices.size();
58     }
59 
60     /** Creates an HDHomeRun device. If there is no available one, returns {@code null}. */
61     @WorkerThread
acquireDevice(Context context)62     synchronized HdHomeRunDevice acquireDevice(Context context) {
63         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
64         int scannedDeviceId = sp.getInt(PREF_KEY_SCANNED_DEVICE_ID, 0);
65         updateDevicesLocked(scannedDeviceId == 0 ? null : scannedDeviceId);
66         if (DEBUG) Log.d(TAG, "createDevice: device count = " + mHdHomeRunDevices.size());
67         HdHomeRunDevice availableDevice = null;
68         // Use the device used for scanning first since other devices might have different line-up.
69         if (scannedDeviceId != 0) {
70             for (HdHomeRunDevice device : mHdHomeRunDevices) {
71                 if (!mUsedDevices.contains(device) && scannedDeviceId == device.getDeviceId()) {
72                     if (!HdHomeRunInterface.isDeviceAvailable(
73                             device.getDeviceId(), device.getIpAddress(), device.getTunerIndex())) {
74                         if (DEBUG) Log.d(TAG, "Device not available: " + device);
75                         continue;
76                     }
77                     availableDevice = device;
78                     break;
79                 }
80             }
81         }
82         if (availableDevice == null) {
83             for (HdHomeRunDevice device : mHdHomeRunDevices) {
84                 if (!mUsedDevices.contains(device)) {
85                     if (!HdHomeRunInterface.isDeviceAvailable(
86                             device.getDeviceId(), device.getIpAddress(), device.getTunerIndex())) {
87                         if (DEBUG) Log.d(TAG, "Device not available: " + device);
88                         continue;
89                     }
90                     availableDevice = device;
91                     break;
92                 }
93             }
94         }
95         if (availableDevice != null) {
96             if (DEBUG) Log.d(TAG, "created device " + availableDevice);
97             mUsedDevices.add(availableDevice);
98             return availableDevice;
99         }
100         return null;
101     }
102 
103     /** Releases a created device by {@link #acquireDevice(Context)}. */
releaseDevice(HdHomeRunDevice device)104     synchronized void releaseDevice(HdHomeRunDevice device) {
105         if (DEBUG) Log.d(TAG, "releaseDevice: " + device);
106         mUsedDevices.remove(device);
107     }
108 
109     /**
110      * Marks the device associated to this instance as a scanned device. Scanned device has higher
111      * priority among multiple HDHomeRun devices.
112      */
markAsScannedDevice(Context context, HdHomeRunDevice device)113     static void markAsScannedDevice(Context context, HdHomeRunDevice device) {
114         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
115         sp.edit().putInt(PREF_KEY_SCANNED_DEVICE_ID, device.getDeviceId()).apply();
116     }
117 
updateDevicesLocked(Integer deviceId)118     private void updateDevicesLocked(Integer deviceId) {
119         mHdHomeRunDevices.clear();
120         mHdHomeRunDevices.addAll(HdHomeRunInterface.scanDevices(deviceId));
121     }
122 }
123