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