1 /*
2  * Copyright (C) 2020 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.google.android.car.kitchensink.audio;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.car.Car;
22 import android.car.media.CarAudioManager;
23 import android.content.Context;
24 import android.media.AudioManager;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.SystemProperties;
29 import android.util.Log;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.ViewGroup;
33 
34 import androidx.fragment.app.Fragment;
35 import androidx.viewpager.widget.ViewPager;
36 
37 import com.google.android.car.kitchensink.R;
38 import com.google.android.material.tabs.TabLayout;
39 
40 import java.util.List;
41 
42 public class CarAudioInputTestFragment extends Fragment {
43 
44     public static final String FRAGMENT_NAME = "audio bus input";
45     private static final String TAG = "CAR.AUDIO.INPUT.KS";
46     private static final boolean DEBUG = true;
47     private static final String PROPERTY_RO_ENABLE_AUDIO_PATCH =
48             "ro.android.car.audio.enableaudiopatch";
49 
50 
51     private Handler mHandler;
52     private Context mContext;
53 
54     private Car mCar;
55     private AudioManager mAudioManager;
56     private CarAudioManager mCarAudioManager;
57     private TabLayout mZonesTabLayout;
58     private CarAudioZoneTabAdapter mInputAudioZoneAdapter;
59     private ViewPager mViewPager;
60 
connectCar()61     private void connectCar() {
62         mContext = getContext();
63         mHandler = new Handler(Looper.getMainLooper());
64         mCar = Car.createCar(mContext, /* handler= */ null,
65                 Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mCarServiceLifecycleListener);
66     }
67 
68     private Car.CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
69         if (!ready) {
70             if (DEBUG) {
71                 Log.d(TAG, "Disconnect from Car Service");
72             }
73             return;
74         }
75         if (DEBUG) {
76             Log.d(TAG, "Connected to Car Service");
77         }
78         mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
79 
80         mAudioManager = mContext.getSystemService(AudioManager.class);
81     };
82 
83 
84     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle)85     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
86         Log.i(TAG, "onCreateView");
87         View view = inflater.inflate(R.layout.audio_input, container, false);
88         connectCar();
89         return view;
90     }
91 
92     @Override
onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)93     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
94         Log.i(TAG, "onViewCreated ");
95         mZonesTabLayout = view.findViewById(R.id.zones_input_tab);
96         mViewPager = view.findViewById(R.id.zones_input_view_pager);
97 
98         mInputAudioZoneAdapter = new CarAudioZoneTabAdapter(getChildFragmentManager());
99         mViewPager.setAdapter(mInputAudioZoneAdapter);
100         initInputInfo();
101         mZonesTabLayout.setupWithViewPager(mViewPager);
102     }
103 
104     @Override
onDestroyView()105     public void onDestroyView() {
106         Log.i(TAG, "onDestroyView");
107 
108         if (mCar != null && mCar.isConnected()) {
109             mCar.disconnect();
110             mCar = null;
111         }
112         super.onDestroyView();
113     }
114 
initInputInfo()115     private void initInputInfo() {
116         if (!mCarAudioManager.isAudioFeatureEnabled(
117                 CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING)) {
118             return;
119         }
120         if (!areAudioPatchAPIsEnabled()) {
121             return;
122         }
123         List<Integer> audioZoneList = mCarAudioManager.getAudioZoneIds();
124         for (int audioZoneId : audioZoneList) {
125             if (mCarAudioManager.getInputDevicesForZoneId(audioZoneId).isEmpty()) {
126                 if (DEBUG) {
127                     Log.d(TAG, "Audio Zone " + audioZoneId + " has no input devices");
128                 }
129                 continue;
130             }
131             addAudioZoneInputDevices(audioZoneId);
132         }
133         mInputAudioZoneAdapter.notifyDataSetChanged();
134     }
135 
areAudioPatchAPIsEnabled()136     private boolean areAudioPatchAPIsEnabled() {
137         return SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, /* default= */ false);
138     }
139 
addAudioZoneInputDevices(int audioZoneId)140     private void addAudioZoneInputDevices(int audioZoneId) {
141         String title = "Audio Zone " + audioZoneId;
142         if (DEBUG) {
143             Log.d(TAG, title + " adding devices");
144         }
145         CarAudioZoneInputFragment fragment = new CarAudioZoneInputFragment(audioZoneId,
146                 mCarAudioManager, mAudioManager);
147 
148         mZonesTabLayout.addTab(mZonesTabLayout.newTab().setText(title));
149         mInputAudioZoneAdapter.addFragment(fragment, title);
150     }
151 
getAudioInputLogTag(Class clazz)152     static String getAudioInputLogTag(Class clazz) {
153         return TAG + clazz.getSimpleName();
154     }
155 }
156