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.input;
18 
19 import android.net.Uri;
20 import android.support.annotation.Nullable;
21 import android.util.Log;
22 
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.List;
26 
27 /**
28  * A class to manage fake tuners for the tune and the recording.
29  */
30 public class TunerHelper {
31     private static final String TAG = "TunerHelper";
32     private static final boolean DEBUG = false;
33 
34     private final List<Tuner> mTuners = new ArrayList<>();
35     private final int mTunerCount;
36 
TunerHelper(int tunerCount)37     public TunerHelper(int tunerCount) {
38         mTunerCount = tunerCount;
39     }
40 
41     /**
42      * Checks whether there are available tuners for the recording.
43      */
tunerAvailableForRecording()44     public boolean tunerAvailableForRecording() {
45         if (mTuners.size() < mTunerCount) {
46             return true;
47         }
48         for (Tuner tuner : mTuners) {
49             if (!tuner.recording) {
50                 return true;
51             }
52         }
53         return false;
54     }
55 
56     /**
57      * Checks whether there is available tuner.
58      * If there's available tuner, it is assigned to the channel.
59      */
tune(@ullable Uri channelUri, boolean forRecording)60     public boolean tune(@Nullable Uri channelUri, boolean forRecording) {
61         if (channelUri == null) {
62             return false;
63         }
64         for (Tuner tuner : mTuners) {
65             // Find available tuner which is used only for the recording.
66             if (tuner.channelUri.equals(channelUri)) {
67                 if (!forRecording && !tuner.tuning) {
68                     tuner.tuning = true;
69                     return true;
70                 } else if (forRecording && !tuner.recording) {
71                     tuner.recording = true;
72                     return true;
73                 }
74             }
75         }
76         if (mTuners.size() < mTunerCount) {
77             // Assign new tuner.
78             mTuners.add(new Tuner(channelUri, forRecording));
79             return true;
80         }
81         Log.i(TAG, "No available tuners. tuner count: " + mTunerCount);
82         return false;
83     }
84 
85     /**
86      * Releases the tuner which was being used for the tune.
87      */
stopTune(@ullable Uri channelUri)88     public void stopTune(@Nullable Uri channelUri) {
89         if (channelUri == null) {
90             return;
91         }
92         Tuner candidate = null;
93         Iterator<Tuner> iterator = mTuners.iterator();
94         while (iterator.hasNext()) {
95             Tuner tuner = iterator.next();
96             if (tuner.channelUri.equals(channelUri) && tuner.tuning) {
97                 if (tuner.recording) {
98                     // A tuner which is used both for the tune and recording is the candidate.
99                     candidate = tuner;
100                 } else {
101                     // Remove the tuner which is used only for the tune.
102                     if (DEBUG) Log.d(TAG, "Removed tuner for tune");
103                     iterator.remove();
104                     return;
105                 }
106             }
107         }
108         if (candidate != null) {
109             candidate.tuning = false;
110         }
111     }
112 
113     /**
114      * Releases the tuner which was being used for the recording.
115      */
stopRecording(@ullable Uri channelUri)116     public void stopRecording(@Nullable Uri channelUri) {
117         if (channelUri == null) {
118             return;
119         }
120         Tuner candidate = null;
121         Iterator<Tuner> iterator = mTuners.iterator();
122         while (iterator.hasNext()) {
123             Tuner tuner = iterator.next();
124             if (tuner.channelUri.equals(channelUri)) {
125                 if (tuner.recording) {
126                     if (tuner.tuning) {
127                         // A tuner which is used both for the tune and recording is the candidate.
128                         candidate = tuner;
129                     } else {
130                         // Remove the tuner which is used only for the recording.
131                         iterator.remove();
132                         return;
133                     }
134                 } else {
135                     Log.w(TAG, "Tuner found for " + channelUri + ", but not used for recording");
136                 }
137             }
138         }
139         if (candidate != null) {
140             candidate.recording = false;
141         }
142     }
143 
144     private static class Tuner {
145         public final Uri channelUri;
146         public boolean tuning;
147         public boolean recording;
148 
Tuner(Uri channelUri, boolean forRecording)149         public Tuner (Uri channelUri, boolean forRecording) {
150             this.channelUri = channelUri;
151             this.tuning = !forRecording;
152             this.recording = forRecording;
153         }
154     }
155 }
156