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;
18 
19 import android.media.AudioDeviceCallback;
20 import android.media.AudioDeviceInfo;
21 import android.media.AudioManager;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.util.Log;
25 import android.widget.TextView;
26 
27 import com.android.cts.verifier.audio.peripheralprofile.PeripheralProfile;
28 import com.android.cts.verifier.audio.peripheralprofile.ProfileManager;
29 
30 import com.android.cts.verifier.PassFailButtons;
31 import com.android.cts.verifier.R;  // needed to access resource in CTSVerifier project namespace.
32 
33 public abstract class USBAudioPeripheralActivity extends PassFailButtons.Activity {
34     private static final String TAG = "USBAudioPeripheralActivity";
35     private static final boolean DEBUG = false;
36 
37     // Profile
38     protected ProfileManager mProfileManager = new ProfileManager();
39     protected PeripheralProfile mSelectedProfile;
40 
41     // Peripheral
42     AudioManager mAudioManager;
43     protected boolean mIsPeripheralAttached;
44     protected AudioDeviceInfo mOutputDevInfo;
45     protected AudioDeviceInfo mInputDevInfo;
46 
47     protected final boolean mIsMandatedRequired;
48 
49     // This will be overriden...
50     protected  int mSystemSampleRate = 48000;
51 
52     // Widgets
53     private TextView mProfileNameTx;
54     private TextView mProfileDescriptionTx;
55 
56     private TextView mPeripheralNameTx;
57 
USBAudioPeripheralActivity(boolean mandatedRequired)58     public USBAudioPeripheralActivity(boolean mandatedRequired) {
59         super();
60 
61         // determine if to show "UNSUPPORTED" if the mandated peripheral is required.
62         mIsMandatedRequired = mandatedRequired;
63 
64         mProfileManager.loadProfiles();
65     }
66 
67     @Override
onCreate(Bundle savedInstanceState)68     protected void onCreate(Bundle savedInstanceState) {
69         super.onCreate(savedInstanceState);
70 
71         mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
72         mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler());
73 
74         mSystemSampleRate = Integer.parseInt(
75             mAudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
76     }
77 
connectPeripheralStatusWidgets()78     protected void connectPeripheralStatusWidgets() {
79         mProfileNameTx = (TextView)findViewById(R.id.uap_profileNameTx);
80         mProfileDescriptionTx =
81             (TextView)findViewById(R.id.uap_profileDescriptionTx);
82         mPeripheralNameTx = (TextView)findViewById(R.id.uap_peripheralNameTx);
83     }
84 
showProfileStatus()85     private void showProfileStatus() {
86         if (DEBUG) {
87             Log.d(TAG, "showProfileStatus()" + (mSelectedProfile != null));
88         }
89         if (mSelectedProfile != null) {
90             mProfileNameTx.setText(mSelectedProfile.getName());
91             mProfileDescriptionTx.setText(mSelectedProfile.getDescription());
92         } else {
93             mProfileNameTx.setText("");
94             mProfileDescriptionTx.setText("");
95         }
96     }
97 
showPeripheralStatus()98     private void showPeripheralStatus() {
99         if (mIsPeripheralAttached) {
100             String productName = "";
101             if (mOutputDevInfo != null) {
102                 productName = mOutputDevInfo.getProductName().toString();
103             } else if (mInputDevInfo != null) {
104                 productName = mInputDevInfo.getProductName().toString();
105             }
106             String ctrlText;
107             if (mSelectedProfile == null && mIsMandatedRequired) {
108                 ctrlText = productName + " - UNSUPPORTED";
109             } else {
110                 ctrlText = productName;
111             }
112             mPeripheralNameTx.setText(ctrlText);
113         } else {
114             mPeripheralNameTx.setText("Disconnected");
115         }
116     }
117 
scanPeripheralList(AudioDeviceInfo[] devices)118     private void scanPeripheralList(AudioDeviceInfo[] devices) {
119         // Can't just use the first record because then we will only get
120         // Source OR sink, not both even on devices that are both.
121         mOutputDevInfo = null;
122         mInputDevInfo = null;
123 
124         // Any valid peripherals
125         for(AudioDeviceInfo devInfo : devices) {
126             if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE ||
127                 devInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) {
128                 if (devInfo.isSink()) {
129                     mOutputDevInfo = devInfo;
130                 }
131                 if (devInfo.isSource()) {
132                     mInputDevInfo = devInfo;
133                 }
134             }
135         }
136         mIsPeripheralAttached = mOutputDevInfo != null || mInputDevInfo != null;
137         if (DEBUG) {
138             Log.d(TAG, "mIsPeripheralAttached: " + mIsPeripheralAttached);
139         }
140 
141         // any associated profiles?
142         if (mIsPeripheralAttached) {
143             if (mOutputDevInfo != null) {
144                 mSelectedProfile =
145                     mProfileManager.getProfile(mOutputDevInfo.getProductName().toString());
146             } else if (mInputDevInfo != null) {
147                 mSelectedProfile =
148                     mProfileManager.getProfile(mInputDevInfo.getProductName().toString());
149             }
150         } else {
151             mSelectedProfile = null;
152         }
153 
154     }
155 
156     private class ConnectListener extends AudioDeviceCallback {
ConnectListener()157         /*package*/ ConnectListener() {}
158 
159         //
160         // AudioDevicesManager.OnDeviceConnectionListener
161         //
162         @Override
onAudioDevicesAdded(AudioDeviceInfo[] addedDevices)163         public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
164             // Log.i(TAG, "onAudioDevicesAdded() num:" + addedDevices.length);
165 
166             scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
167 
168             showProfileStatus();
169             showPeripheralStatus();
170             updateConnectStatus();
171         }
172 
173         @Override
onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices)174         public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
175             // Log.i(TAG, "onAudioDevicesRemoved() num:" + removedDevices.length);
176 
177             scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
178 
179             showProfileStatus();
180             showPeripheralStatus();
181             updateConnectStatus();
182         }
183     }
184 
updateConnectStatus()185     abstract public void updateConnectStatus();
186 }
187 
188