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 package com.android.car.audio;
17 
18 import android.car.Car;
19 import android.car.media.CarAudioManager;
20 import android.content.pm.PackageManager;
21 import android.media.AudioFocusInfo;
22 import android.media.AudioManager;
23 import android.os.Bundle;
24 
25 import androidx.annotation.NonNull;
26 
27 import com.android.car.audio.CarAudioContext.AudioContext;
28 
29 import java.io.PrintWriter;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Objects;
33 
34 final class FocusEntry {
35     private final AudioFocusInfo mAudioFocusInfo;
36     private final int mAudioContext;
37 
38     private final List<FocusEntry> mBlockers;
39     private final PackageManager mPackageManager;
40     private boolean mIsDucked;
41 
FocusEntry(@onNull AudioFocusInfo audioFocusInfo, @AudioContext int context, @NonNull PackageManager packageManager)42     FocusEntry(@NonNull AudioFocusInfo audioFocusInfo, @AudioContext int context,
43             @NonNull PackageManager packageManager) {
44         Objects.requireNonNull(audioFocusInfo, "AudioFocusInfo cannot be null");
45         Objects.requireNonNull(packageManager, "PackageManager cannot be null");
46         mAudioFocusInfo = audioFocusInfo;
47         mAudioContext = context;
48         mBlockers = new ArrayList<>();
49         mPackageManager = packageManager;
50     }
51 
52     @AudioContext
getAudioContext()53     int getAudioContext() {
54         return mAudioContext;
55     }
56 
getAudioFocusInfo()57     AudioFocusInfo getAudioFocusInfo() {
58         return mAudioFocusInfo;
59     }
60 
isUnblocked()61     boolean isUnblocked() {
62         return mBlockers.isEmpty();
63     }
64 
addBlocker(FocusEntry blocker)65     void addBlocker(FocusEntry blocker) {
66         mBlockers.add(blocker);
67     }
68 
removeBlocker(FocusEntry blocker)69     void removeBlocker(FocusEntry blocker) {
70         mBlockers.remove(blocker);
71     }
72 
getClientId()73     String getClientId() {
74         return mAudioFocusInfo.getClientId();
75     }
76 
isDucked()77     boolean isDucked() {
78         return mIsDucked;
79     }
80 
setDucked(boolean ducked)81     void setDucked(boolean ducked) {
82         mIsDucked = ducked;
83     }
84 
wantsPauseInsteadOfDucking()85     boolean wantsPauseInsteadOfDucking() {
86         return (mAudioFocusInfo.getFlags() & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
87                 != 0;
88     }
89 
receivesDuckEvents()90     boolean receivesDuckEvents() {
91         Bundle bundle = mAudioFocusInfo.getAttributes().getBundle();
92 
93         if (bundle == null) {
94             return false;
95         }
96 
97         if (!bundle.getBoolean(CarAudioManager.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS)) {
98             return false;
99         }
100 
101         return (mPackageManager.checkPermission(
102                 Car.PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS,
103                 mAudioFocusInfo.getPackageName())
104                 == PackageManager.PERMISSION_GRANTED);
105     }
106 
getUsageName()107     String getUsageName() {
108         return mAudioFocusInfo.getAttributes().usageToString();
109     }
110 
dump(String indent, PrintWriter writer)111     public void dump(String indent, PrintWriter writer) {
112         writer.printf("%s%s - %s\n", indent, getClientId(), getUsageName());
113         // Prints in single line
114         writer.printf("%s\tReceives Duck Events: %b, ", indent, receivesDuckEvents());
115         writer.printf("Wants Pause Instead of Ducking: %b, ", wantsPauseInsteadOfDucking());
116         writer.printf("Is Ducked: %b\n", isDucked());
117     }
118 }
119