1 /* 2 * Copyright (C) 2017 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.cts.verifier.audio.peripheralprofile; 18 19 import android.os.Environment; 20 import androidx.annotation.Nullable; 21 import android.util.Log; 22 import android.util.Xml; 23 24 import org.xml.sax.Attributes; 25 import org.xml.sax.InputSource; 26 import org.xml.sax.SAXException; 27 import org.xml.sax.XMLReader; 28 import org.xml.sax.helpers.DefaultHandler; 29 30 import java.io.ByteArrayInputStream; 31 import java.io.File; 32 import java.io.FileInputStream; 33 import java.io.FileNotFoundException; 34 import java.io.FileWriter; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.util.ArrayList; 38 39 import javax.xml.parsers.ParserConfigurationException; 40 import javax.xml.parsers.SAXParser; 41 import javax.xml.parsers.SAXParserFactory; 42 43 public class ProfileManager { 44 private static final String TAG = "ProfileManager"; 45 private static final boolean DEBUG = false; 46 47 private static final String mBuiltInprofiles = 48 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" + 49 "<ProfileList Version=\"1.0.0\">" + 50 "<PeripheralProfile ProfileName=\"Audio Interface\" ProfileDescription=\"Presonus AudioVox 44VSL\" ProductName=\"USB-Audio - AudioBox 44 VSL\">" + 51 "<OutputDevInfo ChanCounts=\"2,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 52 "<InputDevInfo ChanCounts=\"1,2,4\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 53 "</PeripheralProfile>" + 54 "<PeripheralProfile ProfileName=\"AudioBox 22VSL\" ProfileDescription=\"Presonus AudioBox 22VSL\" ProductName=\"USB-Audio - AudioBox 22 VSL\">" + 55 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 56 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" + 57 "</PeripheralProfile>" + 58 "<PeripheralProfile ProfileName=\"AudioBox USB\" ProfileDescription=\"Presonus AudioBox USB\" ProductName=\"USB-Audio - AudioBox USB\">" + 59 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" + 60 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" + 61 "</PeripheralProfile>" + 62 "<PeripheralProfile ProfileName=\"Pixel USB-C Dongle + Wired Analog Headset\" ProfileDescription=\"Reference USB Dongle\" ProductName=\"USB-Audio - USB-C to 3.5mm-Headphone Adapte\">" + 63 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" + 64 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" + 65 "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" />" + 66 "</PeripheralProfile>" + 67 "<PeripheralProfile ProfileName=\"HTC Dongle\" ProfileDescription=\"Type-C to 3.5mm Headphone\" ProductName=\"USB-Audio - HTC Type-C to 3.5mm Headphone J\">" + 68 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" + 69 "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\"/>" + 70 "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" />" + 71 "</PeripheralProfile>" + 72 "<PeripheralProfile ProfileName=\"JBL Reflect Aware\" ProfileDescription=\"JBL Reflect Aware\" ProductName=\"USB-Audio - JBL Reflect Aware\">" + 73 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"2\" SampleRates=\"44100,48000\" />" + 74 "<InputDevInfo ChanCounts=\"1\" ChanPosMasks=\"16\" ChanIndexMasks=\"1\" Encodings=\"2\" SampleRates=\"44100,48000\" />" + 75 "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" />" + 76 "</PeripheralProfile>" + 77 "</ProfileList>"; 78 79 // XML Tags and Attributes 80 private final static String kTag_ProfileList = "ProfileList"; 81 private final static String kAttrName_Version = "Version"; 82 private final static String kValueStr_Version = "1.0.0"; 83 84 private final ArrayList<PeripheralProfile> mProfiles = 85 new ArrayList<PeripheralProfile>(); 86 87 private PeripheralProfile mParsingProfile = null; 88 89 public boolean addProfile(PeripheralProfile profile) { 90 mProfiles.add(profile); 91 92 return true; 93 } 94 95 private class ProfileLoader extends DefaultHandler { 96 @Override 97 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 98 if (localName.equals(kTag_ProfileList)) { 99 // Maybe check the version here. 100 } else if (localName.equals(PeripheralProfile.kTag_Profile)){ 101 mParsingProfile = new PeripheralProfile(null, null, null, null, null); 102 mParsingProfile.startElement(namespaceURI, localName, qName, atts); 103 } else { 104 mParsingProfile.startElement(namespaceURI, localName, qName, atts); 105 } 106 } 107 108 @Override 109 public void endElement(String uri, String localName, String qName) { 110 if (localName.equals(kTag_ProfileList)) { 111 // Version Checking here maybe? 112 } else if (localName.equals(PeripheralProfile.kTag_Profile)){ 113 mProfiles.add(mParsingProfile); 114 mParsingProfile = null; 115 } 116 } 117 } 118 119 @Override 120 public String toString() { 121 return super.toString(); 122 } 123 124 public boolean loadProfiles(InputStream inStream) { 125 SAXParserFactory spf = SAXParserFactory.newInstance(); 126 SAXParser sp; 127 try { 128 sp = spf.newSAXParser(); 129 XMLReader xr = sp.getXMLReader(); 130 xr.setContentHandler(new ProfileLoader()); 131 xr.parse(new InputSource(inStream)); 132 } catch (ParserConfigurationException e) { 133 e.printStackTrace(); 134 } catch (SAXException e) { 135 e.printStackTrace(); 136 } catch (IOException e) { 137 e.printStackTrace(); 138 } 139 140 return true; 141 } 142 143 public boolean loadProfiles(String profilesXML) { 144 mProfiles.clear(); 145 146 return loadProfiles(new ByteArrayInputStream(profilesXML.getBytes())); 147 } 148 149 public boolean loadProfiles() { 150 return loadProfiles(mBuiltInprofiles); 151 } 152 153 // 154 // Access 155 // 156 public ArrayList<PeripheralProfile> getProfiles() { return mProfiles; } 157 158 public int getNumProfiles() { 159 return mProfiles.size(); 160 } 161 public PeripheralProfile getProfile(int index) { 162 return mProfiles.get(index); 163 } 164 165 @Nullable 166 public PeripheralProfile getProfile(String productName) { 167 for(PeripheralProfile profile : mProfiles) { 168 if (productName.equals(profile.getProductName())) { 169 return profile; 170 } 171 } 172 return null; 173 } 174 } 175