Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 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.googlecode.android_scripting.facade.bluetooth.media;
     18 
     19 import android.media.browse.MediaBrowser.MediaItem;
     20 import android.media.session.*;
     21 import android.os.Bundle;
     22 import android.service.media.MediaBrowserService;
     23 
     24 import com.googlecode.android_scripting.facade.bluetooth.BluetoothMediaFacade;
     25 import com.googlecode.android_scripting.Log;
     26 
     27 import java.util.ArrayList;
     28 import java.util.List;
     29 
     30 /**
     31  * A {@link MediaBrowserService} implemented in the SL4A App to intercept Media keys and
     32  * commands.
     33  * This would be running on the Phone (AVRCP TG device) and whenever the device receives a media
     34  * command from Car (a AVRCP CT), this MediaBrowserService's MediaSession would intercept it.
     35  * Helps to verify the commands received by the Phone (AVRCP TG) are the same as what was sent from
     36  * Car (AVRCP CT).
     37  */
     38 public class BluetoothSL4AAudioSrcMBS extends MediaBrowserService {
     39     private static final String TAG = "BluetoothSL4AAudioSrcMBS";
     40     private static final String MEDIA_ROOT_ID = "__ROOT__";
     41 
     42     private MediaSession mMediaSession = null;
     43     private MediaSession.Token mSessionToken = null;
     44     private BluetoothMediaPlayback mPlayback = null;
     45     private static BluetoothSL4AAudioSrcMBS sAvrcpMediaBrowserService;
     46     private static final String CMD_MEDIA_PLAY = "play";
     47     private static final String CMD_MEDIA_PAUSE = "pause";
     48     private static final String CMD_MEDIA_SKIP_NEXT = "skipNext";
     49     private static final String CMD_MEDIA_SKIP_PREV = "skipPrev";
     50 
     51     /**
     52      * MediaSession callback dispatching the corresponding <code>PlaybackState</code> to
     53      * {@link BluetoothMediaFacade}
     54      */
     55     private MediaSession.Callback mMediaSessionCallback =
     56             new MediaSession.Callback() {
     57                 @Override
     58                 public void onPlay() {
     59                     Log.d(TAG + " onPlay");
     60                     mPlayback.play();
     61                 }
     62 
     63                 @Override
     64                 public void onPause() {
     65                     Log.d(TAG + " onPause");
     66                     mPlayback.pause();
     67                 }
     68 
     69                 @Override
     70                 public void onRewind() {
     71                     Log.d(TAG + " onRewind");
     72                 }
     73 
     74                 @Override
     75                 public void onFastForward() {
     76                     Log.d(TAG + " onFastForward");
     77                 }
     78 
     79                 @Override
     80                 public void onSkipToNext() {
     81                     Log.d(TAG + " onSkipToNext");
     82                     mPlayback.skipNext();
     83                 }
     84 
     85                 @Override
     86                 public void onSkipToPrevious() {
     87                     Log.d(TAG + " onSkipToPrevious");
     88                     mPlayback.skipPrev();
     89                 }
     90 
     91                 @Override
     92                 public void onStop() {
     93                     Log.d(TAG + " onStop");
     94                     mPlayback.stop();
     95                 }
     96             };
     97 
     98     /**
     99      * Returns the currently set instance of {@link BluetoothSL4AAudioSrcMBS}
    100      *
    101      * @return current instance of {@link BluetoothSL4AAudioSrcMBS}
    102      */
    103     public static synchronized BluetoothSL4AAudioSrcMBS getAvrcpMediaBrowserService() {
    104         return sAvrcpMediaBrowserService;
    105     }
    106 
    107     /**
    108      * Handle a Media Playback Command.
    109      * Pass it to the appropriate {@link BluetoothMediaPlayback} method
    110      *
    111      * @param command - command to handle
    112      */
    113     public void handleMediaCommand(String command) {
    114         if (mPlayback == null) {
    115             Log.d(TAG + " handleMediaCommand Failed since Playback is null");
    116             return;
    117         }
    118         switch (command) {
    119             case CMD_MEDIA_PLAY:
    120                 mPlayback.play();
    121                 break;
    122             case CMD_MEDIA_PAUSE:
    123                 mPlayback.pause();
    124                 break;
    125             case CMD_MEDIA_SKIP_NEXT:
    126                 mPlayback.skipNext();
    127                 break;
    128             case CMD_MEDIA_SKIP_PREV:
    129                 mPlayback.skipPrev();
    130                 break;
    131             default:
    132                 Log.d(TAG + " Unknown command " + command);
    133         }
    134         return;
    135     }
    136 
    137     /**
    138      * We do the following on the BluetoothSL4AAudioSrcMBS onCreate():
    139      * 1. Create a new MediaSession
    140      * 2. Register a callback with the created MediaSession
    141      * 3. Set its playback state and set the session to active.
    142      * 4. Create a new BluetoothMediaPlayback instance to handle all the "music playing"
    143      * 5. Set the created MediaSession active
    144      */
    145     @Override
    146     public void onCreate() {
    147         Log.d(TAG + " onCreate");
    148         super.onCreate();
    149         sAvrcpMediaBrowserService = this;
    150         mMediaSession = new MediaSession(this, TAG);
    151         mSessionToken = mMediaSession.getSessionToken();
    152         setSessionToken(mSessionToken);
    153         mMediaSession.setCallback(mMediaSessionCallback);
    154         mMediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS
    155                 | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
    156         // Note - MediaButton Intent is not received until the session has a PlaybackState
    157         // whose state is set to something other than STATE_STOPPED or STATE_NONE
    158         mPlayback = new BluetoothMediaPlayback();
    159         if (mPlayback == null) {
    160             Log.e(TAG + "Playback alloc error");
    161         }
    162         mPlayback.setMediaSession(mMediaSession);
    163         PlaybackState state = new PlaybackState.Builder()
    164                 .setActions(PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE
    165                         | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS
    166                         | PlaybackState.ACTION_STOP)
    167                 .setState(PlaybackState.STATE_PLAYING, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1)
    168                 .build();
    169         mMediaSession.setPlaybackState(state);
    170         mMediaSession.setActive(true);
    171     }
    172 
    173     @Override
    174     public void onDestroy() {
    175         Log.d(TAG + " onDestroy");
    176         mPlayback.releaseMediaPlayer();
    177         mMediaSession.release();
    178         mMediaSession = null;
    179         mSessionToken = null;
    180         sAvrcpMediaBrowserService = null;
    181         super.onDestroy();
    182     }
    183 
    184     @Override
    185     public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
    186         BrowserRoot mediaRoot = new BrowserRoot(MEDIA_ROOT_ID, null);
    187         return mediaRoot;
    188     }
    189 
    190     @Override
    191     public void onLoadChildren(String parentId, Result<List<MediaItem>> result) {
    192         List<MediaItem> mediaList = new ArrayList<MediaItem>();
    193         result.sendResult(mediaList);
    194     }
    195 
    196     /**
    197      * Returns the TAG string
    198      *
    199      * @return <code>BluetoothSL4AAudioSrcMBS</code>'s tag
    200      */
    201     public static String getTag() {
    202         return TAG;
    203     }
    204 }
    205 
    206 
    207