Home | History | Annotate | Download | only in media
      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