1 /* 2 * Copyright (C) 2013 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 android.media; 18 19 import android.media.MediaFocusControl.AudioFocusDeathHandler; 20 import android.os.IBinder; 21 import android.util.Log; 22 23 import java.io.PrintWriter; 24 25 /** 26 * @hide 27 * Class to handle all the information about a user of audio focus. The lifecycle of each 28 * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus 29 * stack to its release. 30 */ 31 class FocusRequester { 32 33 // on purpose not using this classe's name, as it will only be used from MediaFocusControl 34 private static final String TAG = "MediaFocusControl"; 35 private static final boolean DEBUG = false; 36 37 private AudioFocusDeathHandler mDeathHandler; 38 private final IAudioFocusDispatcher mFocusDispatcher; // may be null 39 private final IBinder mSourceRef; 40 private final String mClientId; 41 private final String mPackageName; 42 private final int mCallingUid; 43 /** 44 * the audio focus gain request that caused the addition of this object in the focus stack. 45 */ 46 private final int mFocusGainRequest; 47 /** 48 * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if 49 * it never lost focus. 50 */ 51 private int mFocusLossReceived; 52 /** 53 * the stream type associated with the focus request 54 */ 55 private final int mStreamType; 56 57 FocusRequester(int streamType, int focusRequest, 58 IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, 59 String pn, int uid) { 60 mStreamType = streamType; 61 mFocusDispatcher = afl; 62 mSourceRef = source; 63 mClientId = id; 64 mDeathHandler = hdlr; 65 mPackageName = pn; 66 mCallingUid = uid; 67 mFocusGainRequest = focusRequest; 68 mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; 69 } 70 71 72 boolean hasSameClient(String otherClient) { 73 try { 74 return mClientId.compareTo(otherClient) == 0; 75 } catch (NullPointerException e) { 76 return false; 77 } 78 } 79 80 boolean hasSameBinder(IBinder ib) { 81 return (mSourceRef != null) && mSourceRef.equals(ib); 82 } 83 84 boolean hasSamePackage(String pack) { 85 try { 86 return mPackageName.compareTo(pack) == 0; 87 } catch (NullPointerException e) { 88 return false; 89 } 90 } 91 92 boolean hasSameUid(int uid) { 93 return mCallingUid == uid; 94 } 95 96 97 int getGainRequest() { 98 return mFocusGainRequest; 99 } 100 101 int getStreamType() { 102 return mStreamType; 103 } 104 105 106 private static String focusChangeToString(int focus) { 107 switch(focus) { 108 case AudioManager.AUDIOFOCUS_NONE: 109 return "none"; 110 case AudioManager.AUDIOFOCUS_GAIN: 111 return "GAIN"; 112 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: 113 return "GAIN_TRANSIENT"; 114 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 115 return "GAIN_TRANSIENT_MAY_DUCK"; 116 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 117 return "GAIN_TRANSIENT_EXCLUSIVE"; 118 case AudioManager.AUDIOFOCUS_LOSS: 119 return "LOSS"; 120 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 121 return "LOSS_TRANSIENT"; 122 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 123 return "LOSS_TRANSIENT_CAN_DUCK"; 124 default: 125 return "[invalid focus change" + focus + "]"; 126 } 127 } 128 129 private String focusGainToString() { 130 return focusChangeToString(mFocusGainRequest); 131 } 132 133 private String focusLossToString() { 134 return focusChangeToString(mFocusLossReceived); 135 } 136 137 void dump(PrintWriter pw) { 138 pw.println(" source:" + mSourceRef 139 + " -- pack: " + mPackageName 140 + " -- client: " + mClientId 141 + " -- gain: " + focusGainToString() 142 + " -- loss: " + focusLossToString() 143 + " -- uid: " + mCallingUid 144 + " -- stream: " + mStreamType); 145 } 146 147 148 void release() { 149 try { 150 if (mSourceRef != null && mDeathHandler != null) { 151 mSourceRef.unlinkToDeath(mDeathHandler, 0); 152 mDeathHandler = null; 153 } 154 } catch (java.util.NoSuchElementException e) { 155 Log.e(TAG, "FocusRequester.release() hit ", e); 156 } 157 } 158 159 @Override 160 protected void finalize() throws Throwable { 161 release(); 162 super.finalize(); 163 } 164 165 /** 166 * For a given audio focus gain request, return the audio focus loss type that will result 167 * from it, taking into account any previous focus loss. 168 * @param gainRequest 169 * @return the audio focus loss type that matches the gain request 170 */ 171 private int focusLossForGainRequest(int gainRequest) { 172 switch(gainRequest) { 173 case AudioManager.AUDIOFOCUS_GAIN: 174 switch(mFocusLossReceived) { 175 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 176 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 177 case AudioManager.AUDIOFOCUS_LOSS: 178 case AudioManager.AUDIOFOCUS_NONE: 179 return AudioManager.AUDIOFOCUS_LOSS; 180 } 181 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 182 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: 183 switch(mFocusLossReceived) { 184 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 185 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 186 case AudioManager.AUDIOFOCUS_NONE: 187 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT; 188 case AudioManager.AUDIOFOCUS_LOSS: 189 return AudioManager.AUDIOFOCUS_LOSS; 190 } 191 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 192 switch(mFocusLossReceived) { 193 case AudioManager.AUDIOFOCUS_NONE: 194 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 195 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK; 196 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 197 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT; 198 case AudioManager.AUDIOFOCUS_LOSS: 199 return AudioManager.AUDIOFOCUS_LOSS; 200 } 201 default: 202 Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest); 203 return AudioManager.AUDIOFOCUS_NONE; 204 } 205 } 206 207 void handleExternalFocusGain(int focusGain) { 208 int focusLoss = focusLossForGainRequest(focusGain); 209 handleFocusLoss(focusLoss); 210 } 211 212 void handleFocusGain(int focusGain) { 213 try { 214 if (mFocusDispatcher != null) { 215 if (DEBUG) { 216 Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to " 217 + mClientId); 218 } 219 mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId); 220 } 221 mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; 222 } catch (android.os.RemoteException e) { 223 Log.e(TAG, "Failure to signal gain of audio focus due to: ", e); 224 } 225 } 226 227 void handleFocusLoss(int focusLoss) { 228 try { 229 if (focusLoss != mFocusLossReceived) { 230 if (mFocusDispatcher != null) { 231 if (DEBUG) { 232 Log.v(TAG, "dispatching " + focusChangeToString(focusLoss) + " to " 233 + mClientId); 234 } 235 mFocusDispatcher.dispatchAudioFocusChange(focusLoss, mClientId); 236 } 237 mFocusLossReceived = focusLoss; 238 } 239 } catch (android.os.RemoteException e) { 240 Log.e(TAG, "Failure to signal loss of audio focus due to:", e); 241 } 242 } 243 244 } 245