Home | History | Annotate | Download | only in service
      1 /*
      2  * Copyright 2017 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.example.android.mediasession.service;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.media.AudioManager;
     24 import android.net.wifi.WifiManager;
     25 import android.support.annotation.NonNull;
     26 import android.support.v4.media.MediaMetadataCompat;
     27 import android.support.v4.media.session.PlaybackStateCompat;
     28 
     29 /**
     30  * Abstract player implementation that handles playing music with proper handling of headphones
     31  * and audio focus.
     32  */
     33 public abstract class PlayerAdapter {
     34 
     35     private static final float MEDIA_VOLUME_DEFAULT = 1.0f;
     36     private static final float MEDIA_VOLUME_DUCK = 0.2f;
     37 
     38     private static final IntentFilter AUDIO_NOISY_INTENT_FILTER =
     39             new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
     40 
     41     private boolean mAudioNoisyReceiverRegistered = false;
     42     private final BroadcastReceiver mAudioNoisyReceiver =
     43             new BroadcastReceiver() {
     44                 @Override
     45                 public void onReceive(Context context, Intent intent) {
     46                     if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
     47                         if (isPlaying()) {
     48                             pause();
     49                         }
     50                     }
     51                 }
     52             };
     53 
     54     private final Context mApplicationContext;
     55     private final AudioManager mAudioManager;
     56     private final AudioFocusHelper mAudioFocusHelper;
     57 
     58     private boolean mPlayOnAudioFocus = false;
     59 
     60     public PlayerAdapter(@NonNull Context context) {
     61         mApplicationContext = context.getApplicationContext();
     62         mAudioManager = (AudioManager) mApplicationContext.getSystemService(Context.AUDIO_SERVICE);
     63         mAudioFocusHelper = new AudioFocusHelper();
     64     }
     65 
     66     public abstract void playFromMedia(MediaMetadataCompat metadata);
     67 
     68     public abstract MediaMetadataCompat getCurrentMedia();
     69 
     70     public abstract boolean isPlaying();
     71 
     72     public final void play() {
     73         if (mAudioFocusHelper.requestAudioFocus()) {
     74             registerAudioNoisyReceiver();
     75             onPlay();
     76         }
     77     }
     78 
     79     /**
     80      * Called when media is ready to be played and indicates the app has audio focus.
     81      */
     82     protected abstract void onPlay();
     83 
     84     public final void pause() {
     85         if (!mPlayOnAudioFocus) {
     86             mAudioFocusHelper.abandonAudioFocus();
     87         }
     88 
     89         unregisterAudioNoisyReceiver();
     90         onPause();
     91     }
     92 
     93     /**
     94      * Called when media must be paused.
     95      */
     96     protected abstract void onPause();
     97 
     98     public final void stop() {
     99         mAudioFocusHelper.abandonAudioFocus();
    100         unregisterAudioNoisyReceiver();
    101         onStop();
    102     }
    103 
    104     /**
    105      * Called when the media must be stopped. The player should clean up resources at this
    106      * point.
    107      */
    108     protected abstract void onStop();
    109 
    110     public abstract void seekTo(long position);
    111 
    112     public abstract void setVolume(float volume);
    113 
    114     private void registerAudioNoisyReceiver() {
    115         if (!mAudioNoisyReceiverRegistered) {
    116             mApplicationContext.registerReceiver(mAudioNoisyReceiver, AUDIO_NOISY_INTENT_FILTER);
    117             mAudioNoisyReceiverRegistered = true;
    118         }
    119     }
    120 
    121     private void unregisterAudioNoisyReceiver() {
    122         if (mAudioNoisyReceiverRegistered) {
    123             mApplicationContext.unregisterReceiver(mAudioNoisyReceiver);
    124             mAudioNoisyReceiverRegistered = false;
    125         }
    126     }
    127 
    128     /**
    129      * Helper class for managing audio focus related tasks.
    130      */
    131     private final class AudioFocusHelper
    132             implements AudioManager.OnAudioFocusChangeListener {
    133 
    134         private boolean requestAudioFocus() {
    135             final int result = mAudioManager.requestAudioFocus(this,
    136                     AudioManager.STREAM_MUSIC,
    137                     AudioManager.AUDIOFOCUS_GAIN);
    138             return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
    139         }
    140 
    141         private void abandonAudioFocus() {
    142             mAudioManager.abandonAudioFocus(this);
    143         }
    144 
    145         @Override
    146         public void onAudioFocusChange(int focusChange) {
    147             switch (focusChange) {
    148                 case AudioManager.AUDIOFOCUS_GAIN:
    149                     if (mPlayOnAudioFocus && !isPlaying()) {
    150                         play();
    151                     } else if (isPlaying()) {
    152                         setVolume(MEDIA_VOLUME_DEFAULT);
    153                     }
    154                     mPlayOnAudioFocus = false;
    155                     break;
    156                 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
    157                     setVolume(MEDIA_VOLUME_DUCK);
    158                     break;
    159                 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
    160                     if (isPlaying()) {
    161                         mPlayOnAudioFocus = true;
    162                         pause();
    163                     }
    164                     break;
    165                 case AudioManager.AUDIOFOCUS_LOSS:
    166                     mAudioManager.abandonAudioFocus(this);
    167                     mPlayOnAudioFocus = false;
    168                     stop();
    169                     break;
    170             }
    171         }
    172     }
    173 }
    174