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.bluetooth.avrcpcontroller;
18 
19 import android.support.v4.media.session.PlaybackStateCompat;
20 import android.util.Log;
21 import android.util.SparseArray;
22 import android.util.SparseIntArray;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 
26 import java.util.ArrayList;
27 
28 /*
29  * Contains information Player Application Setting extended from BluetootAvrcpPlayerSettings
30  */
31 class PlayerApplicationSettings {
32     private static final String TAG = "PlayerApplicationSettings";
33 
34     /*
35      * Values for SetPlayerApplicationSettings from AVRCP Spec V1.6 Appendix F.
36      */
37     static final byte REPEAT_STATUS = 0x02;
38     static final byte SHUFFLE_STATUS = 0x03;
39 
40     @VisibleForTesting static final byte JNI_REPEAT_STATUS_OFF = 0x01;
41     @VisibleForTesting static final byte JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT = 0x02;
42     @VisibleForTesting static final byte JNI_REPEAT_STATUS_ALL_TRACK_REPEAT = 0x03;
43     @VisibleForTesting static final byte JNI_REPEAT_STATUS_GROUP_REPEAT = 0x04;
44 
45     @VisibleForTesting static final byte JNI_SHUFFLE_STATUS_OFF = 0x01;
46     @VisibleForTesting static final byte JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE = 0x02;
47     @VisibleForTesting static final byte JNI_SHUFFLE_STATUS_GROUP_SHUFFLE = 0x03;
48 
49     @VisibleForTesting static final byte JNI_STATUS_INVALID = -1;
50 
51     /*
52      * Hash map of current settings.
53      */
54     private SparseIntArray mSettings = new SparseIntArray();
55 
56     /*
57      * Hash map of supported values, a setting should be supported by the remote in order to enable
58      * in mSettings.
59      */
60     private SparseArray<ArrayList<Integer>> mSupportedValues =
61             new SparseArray<ArrayList<Integer>>();
62 
63     /* Convert from JNI array to Java classes. */
makeSupportedSettings(byte[] btAvrcpAttributeList)64     static PlayerApplicationSettings makeSupportedSettings(byte[] btAvrcpAttributeList) {
65         PlayerApplicationSettings newObj = new PlayerApplicationSettings();
66         try {
67             for (int i = 0; i < btAvrcpAttributeList.length; ) {
68                 byte attrId = btAvrcpAttributeList[i++];
69                 byte numSupportedVals = btAvrcpAttributeList[i++];
70                 ArrayList<Integer> supportedValues = new ArrayList<Integer>();
71 
72                 for (int j = 0; j < numSupportedVals; j++) {
73                     // Yes, keep using i for array indexing.
74                     supportedValues.add(
75                             mapAttribIdValtoAvrcpPlayerSetting(attrId, btAvrcpAttributeList[i++]));
76                 }
77                 newObj.mSupportedValues.put(attrId, supportedValues);
78             }
79         } catch (ArrayIndexOutOfBoundsException exception) {
80             Log.e(TAG, "makeSupportedSettings attributeList index error.");
81         }
82         return newObj;
83     }
84 
makeSettings(byte[] btAvrcpAttributeList)85     static PlayerApplicationSettings makeSettings(byte[] btAvrcpAttributeList) {
86         PlayerApplicationSettings newObj = new PlayerApplicationSettings();
87         try {
88             for (int i = 0; i < btAvrcpAttributeList.length; ) {
89                 byte attrId = btAvrcpAttributeList[i++];
90 
91                 newObj.mSettings.put(
92                         attrId,
93                         mapAttribIdValtoAvrcpPlayerSetting(attrId, btAvrcpAttributeList[i++]));
94             }
95         } catch (ArrayIndexOutOfBoundsException exception) {
96             Log.e(TAG, "makeSettings JNI_ATTRIButeList index error.");
97         }
98         return newObj;
99     }
100 
setSupport(PlayerApplicationSettings updates)101     public void setSupport(PlayerApplicationSettings updates) {
102         mSettings = updates.mSettings;
103         mSupportedValues = updates.mSupportedValues;
104     }
105 
supportsSetting(int settingType, int settingValue)106     public boolean supportsSetting(int settingType, int settingValue) {
107         if (null == mSupportedValues.get(settingType)) return false;
108         return mSupportedValues.valueAt(settingType).contains(settingValue);
109     }
110 
supportsSetting(int settingType)111     public boolean supportsSetting(int settingType) {
112         return (null != mSupportedValues.get(settingType));
113     }
114 
getSetting(int settingType)115     public int getSetting(int settingType) {
116         return mSettings.get(settingType, -1);
117     }
118 
119     // Convert a native Attribute Id/Value pair into the AVRCP equivalent value.
120     @VisibleForTesting
mapAttribIdValtoAvrcpPlayerSetting(byte attribId, byte attribVal)121     static int mapAttribIdValtoAvrcpPlayerSetting(byte attribId, byte attribVal) {
122         if (attribId == REPEAT_STATUS) {
123             switch (attribVal) {
124                 case JNI_REPEAT_STATUS_ALL_TRACK_REPEAT:
125                     return PlaybackStateCompat.REPEAT_MODE_ALL;
126                 case JNI_REPEAT_STATUS_GROUP_REPEAT:
127                     return PlaybackStateCompat.REPEAT_MODE_GROUP;
128                 case JNI_REPEAT_STATUS_OFF:
129                     return PlaybackStateCompat.REPEAT_MODE_NONE;
130                 case JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT:
131                     return PlaybackStateCompat.REPEAT_MODE_ONE;
132             }
133         } else if (attribId == SHUFFLE_STATUS) {
134             switch (attribVal) {
135                 case JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE:
136                     return PlaybackStateCompat.SHUFFLE_MODE_ALL;
137                 case JNI_SHUFFLE_STATUS_GROUP_SHUFFLE:
138                     return PlaybackStateCompat.SHUFFLE_MODE_GROUP;
139                 case JNI_SHUFFLE_STATUS_OFF:
140                     return PlaybackStateCompat.SHUFFLE_MODE_NONE;
141             }
142         }
143         return JNI_STATUS_INVALID;
144     }
145 
146     // Convert an AVRCP Setting/Value pair into the native equivalent value;
mapAvrcpPlayerSettingstoBTattribVal(int mSetting, int mSettingVal)147     static byte mapAvrcpPlayerSettingstoBTattribVal(int mSetting, int mSettingVal) {
148         if (mSetting == REPEAT_STATUS) {
149             switch (mSettingVal) {
150                 case PlaybackStateCompat.REPEAT_MODE_NONE:
151                     return JNI_REPEAT_STATUS_OFF;
152                 case PlaybackStateCompat.REPEAT_MODE_ONE:
153                     return JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT;
154                 case PlaybackStateCompat.REPEAT_MODE_ALL:
155                     return JNI_REPEAT_STATUS_ALL_TRACK_REPEAT;
156                 case PlaybackStateCompat.REPEAT_MODE_GROUP:
157                     return JNI_REPEAT_STATUS_GROUP_REPEAT;
158             }
159         } else if (mSetting == SHUFFLE_STATUS) {
160             switch (mSettingVal) {
161                 case PlaybackStateCompat.SHUFFLE_MODE_NONE:
162                     return JNI_SHUFFLE_STATUS_OFF;
163                 case PlaybackStateCompat.SHUFFLE_MODE_ALL:
164                     return JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE;
165                 case PlaybackStateCompat.SHUFFLE_MODE_GROUP:
166                     return JNI_SHUFFLE_STATUS_GROUP_SHUFFLE;
167             }
168         }
169         return JNI_STATUS_INVALID;
170     }
171 
repeatStatusToString(int repeatMode)172     public static String repeatStatusToString(int repeatMode) {
173         switch (repeatMode) {
174             case PlaybackStateCompat.REPEAT_MODE_ALL:
175                 return "ALL";
176             case PlaybackStateCompat.REPEAT_MODE_GROUP:
177                 return "GROUP";
178             case PlaybackStateCompat.REPEAT_MODE_NONE:
179                 return "NONE";
180             case PlaybackStateCompat.REPEAT_MODE_ONE:
181                 return "ONE";
182             default:
183                 return "Unsupported";
184         }
185     }
186 
shuffleStatusToString(int shuffleMode)187     public static String shuffleStatusToString(int shuffleMode) {
188         switch (shuffleMode) {
189             case PlaybackStateCompat.SHUFFLE_MODE_NONE:
190                 return "NONE";
191             case PlaybackStateCompat.SHUFFLE_MODE_ALL:
192                 return "ALL";
193             case PlaybackStateCompat.SHUFFLE_MODE_GROUP:
194                 return "GROUP";
195             default:
196                 return "Unsupported";
197         }
198     }
199 
200     @Override
toString()201     public String toString() {
202         return "<PlayerApplicationSettings"
203                 + " repeat="
204                 + repeatStatusToString(getSetting(REPEAT_STATUS))
205                 + " shuffle="
206                 + shuffleStatusToString(getSetting(SHUFFLE_STATUS))
207                 + ">";
208     }
209 }
210