• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2018 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.car.radio.bands;
18 
19 import android.hardware.radio.ProgramSelector;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 
23 import androidx.annotation.IntDef;
24 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable;
26 import androidx.annotation.StringRes;
27 
28 import com.android.car.broadcastradio.support.platform.ProgramSelectorExt;
29 import com.android.car.radio.platform.RadioTunerExt;
30 import com.android.car.radio.platform.RadioTunerExt.TuneCallback;
31 import com.android.car.radio.util.Log;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 import java.util.Objects;
36 
37 /**
38  * Representation of program type (band); i.e. AM, FM, DAB.
39  *
40  * It's OK to use == operator between these objects, as a given program type
41  * has only one instance per process.
42  */
43 public abstract class ProgramType implements Parcelable {
44     private static final String TAG = "BcRadioApp.ProgramType";
45 
46     /** {@see #TypeId} */
47     public static final int ID_AM = 1;
48 
49     /** {@see #TypeId} */
50     public static final int ID_FM = 2;
51 
52     /** {@see #TypeId} */
53     public static final int ID_DAB = 3;
54 
55     /**
56      * Numeric identifier of program type, for use with switch statements.
57      */
58     @IntDef(value = {
59         ID_AM,
60         ID_FM,
61         ID_DAB,
62     })
63     @Retention(RetentionPolicy.SOURCE)
64     public @interface TypeId {}
65 
66     /** AM program type */
67     public static final ProgramType AM = new AMProgramType(ID_AM);
68 
69     /** FM program type */
70     public static final ProgramType FM = new FMProgramType(ID_FM);
71 
72     /** DAB program type */
73     public static final ProgramType DAB = new DABProgramType(ID_DAB);
74 
75     /** Identifier of this program type.
76      *
77      * {@see #TypeId}
78      */
79     @TypeId
80     public final int id;
81 
ProgramType(@ypeId int id)82     protected ProgramType(@TypeId int id) {
83         this.id = id;
84     }
85 
86     /**
87      * Retrieves non-localized, english name of this program type.
88      */
89     @NonNull
getEnglishName()90     public abstract String getEnglishName();
91 
92     /**
93      * Retrieves localized name of this program type.
94      */
95     @StringRes
getLocalizedName()96     public abstract int getLocalizedName();
97 
98     /**
99      * Tunes to a default channel from this band.
100      *
101      * @param tuner Tuner to take action on.
102      * @param config Region config (i.e. frequency ranges).
103      * @param result Callback for tune success/failure.
104      */
tuneToDefault(@onNull RadioTunerExt tuner, @NonNull RegionConfig config, @Nullable TuneCallback result)105     public abstract void tuneToDefault(@NonNull RadioTunerExt tuner, @NonNull RegionConfig config,
106             @Nullable TuneCallback result);
107 
108     /**
109      * Returns program type for a given selector.
110      *
111      * @param sel ProgramSelector to check.
112      * @return program type of a given selector
113      */
fromSelector(@ullable ProgramSelector sel)114     public static @Nullable ProgramType fromSelector(@Nullable ProgramSelector sel) {
115         if (sel == null) return null;
116 
117         int priType = sel.getPrimaryId().getType();
118         if (priType == ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT) {
119             return DAB;
120         }
121         if (!ProgramSelectorExt.isAmFmProgram(sel)) return null;
122 
123         // this is an AM/FM program; let's check whether it's AM or FM
124         if (!ProgramSelectorExt.hasId(sel, ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)) {
125             Log.e(TAG, "AM/FM program selector with missing frequency");
126             return FM;
127         }
128 
129         long freq = sel.getFirstId(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY);
130         if (ProgramSelectorExt.isAmFrequency(freq)) return AM;
131         if (ProgramSelectorExt.isFmFrequency(freq)) return FM;
132 
133         Log.e(TAG, "AM/FM program selector with frequency out of range: " + freq);
134         return FM;
135     }
136 
137     /**
138      * Checks, if the partial channel number is actually complete.
139      *
140      * This takes display format (see {@link #format}) into account, i.e. doesn't require
141      * FM trailing zeros (95.5 MHz, not 95500 kHz).
142      */
isComplete(@onNull RegionConfig config, int leadingDigits)143     public abstract boolean isComplete(@NonNull RegionConfig config, int leadingDigits);
144 
145     /**
146      * Generates full channel selector from its leading digits.
147      *
148      * The argument must be validated with {@link #isComplete} prior.
149      */
150     @NonNull
parseDigits(int leadingDigits)151     public abstract ProgramSelector parseDigits(int leadingDigits);
152 
153     /**
154      * Generates an array stating whether certain digits are append-able to a given channel prefix
155      * (so that it's still possible to type in a valid channel afterwards).
156      *
157      * @param config Regional config.
158      * @param leadingDigits Channel prefix.
159      * @return an array of length 10, where {@code arr[i] == true} states that it's possible to
160      *         append {@code i} to {@code leadingDigits}
161      */
162     @NonNull
getValidAppendices(@onNull RegionConfig config, int leadingDigits)163     public abstract boolean[] getValidAppendices(@NonNull RegionConfig config, int leadingDigits);
164 
165     /**
166      * Format partial channel number.
167      *
168      * This is used by manual tuner dialpad to display channel number entered by the user.
169      */
format(int leadingDigits)170     public String format(int leadingDigits) {
171         if (leadingDigits < 0) throw new IllegalArgumentException();
172         if (leadingDigits == 0) return "";
173         return Integer.toString(leadingDigits);
174     }
175 
176     @Override
toString()177     public String toString() {
178         return getEnglishName();
179     }
180 
181     @Override
hashCode()182     public int hashCode() {
183         return Objects.hash(id);
184     }
185 
186     @Override
equals(Object obj)187     public boolean equals(Object obj) {
188         if (this == obj) return true;
189         if (!(obj instanceof ProgramType)) return false;
190         ProgramType other = (ProgramType) obj;
191         return other.id == id;
192     }
193 
194     @Override
writeToParcel(Parcel dest, int flags)195     public void writeToParcel(Parcel dest, int flags) {
196         dest.writeInt(id);
197     }
198 
199     @Override
describeContents()200     public int describeContents() {
201         return 0;
202     }
203 
204     public static final Parcelable.Creator<ProgramType> CREATOR =
205             new Parcelable.Creator<ProgramType>() {
206         public ProgramType createFromParcel(Parcel in) {
207             int id = in.readInt();
208             switch (id) {
209                 case ID_AM:
210                     return AM;
211                 case ID_FM:
212                     return FM;
213                 case ID_DAB:
214                     return DAB;
215                 default:
216                     Log.w(TAG, "Unknown ProgramType ID: " + id);
217                     return null;
218             }
219         }
220 
221         public ProgramType[] newArray(int size) {
222             return new ProgramType[size];
223         }
224     };
225 }
226