1 /* 2 * Copyright (C) 2014 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 android.support.v4.media.session; 17 18 import android.app.PendingIntent; 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.media.AudioManager; 22 import android.media.RemoteControlClient; 23 import android.util.Log; 24 import android.os.SystemClock; 25 26 class MediaSessionCompatApi18 { 27 private static final String TAG = "MediaSessionCompatApi18"; 28 29 /***** PlaybackState actions *****/ 30 private static final long ACTION_SEEK_TO = 1 << 8; 31 32 private static boolean sIsMbrPendingIntentSupported = true; 33 createPlaybackPositionUpdateListener(Callback callback)34 public static Object createPlaybackPositionUpdateListener(Callback callback) { 35 return new OnPlaybackPositionUpdateListener<Callback>(callback); 36 } 37 registerMediaButtonEventReceiver(Context context, PendingIntent pi, ComponentName cn)38 public static void registerMediaButtonEventReceiver(Context context, PendingIntent pi, 39 ComponentName cn) { 40 AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 41 42 // Some Android implementations are not able to register a media button event receiver 43 // using a PendingIntent but need a ComponentName instead. These will raise a 44 // NullPointerException. 45 if (sIsMbrPendingIntentSupported) { 46 try { 47 am.registerMediaButtonEventReceiver(pi); 48 } catch (NullPointerException e) { 49 Log.w(TAG, "Unable to register media button event receiver with " 50 + "PendingIntent, falling back to ComponentName."); 51 sIsMbrPendingIntentSupported = false; 52 } 53 } 54 55 if (!sIsMbrPendingIntentSupported) { 56 am.registerMediaButtonEventReceiver(cn); 57 } 58 } 59 unregisterMediaButtonEventReceiver(Context context, PendingIntent pi, ComponentName cn)60 public static void unregisterMediaButtonEventReceiver(Context context, PendingIntent pi, 61 ComponentName cn) { 62 AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 63 if (sIsMbrPendingIntentSupported) { 64 am.unregisterMediaButtonEventReceiver(pi); 65 } else { 66 am.unregisterMediaButtonEventReceiver(cn); 67 } 68 } 69 setState(Object rccObj, int state, long position, float speed, long updateTime)70 public static void setState(Object rccObj, int state, long position, float speed, 71 long updateTime) { 72 long currTime = SystemClock.elapsedRealtime(); 73 if (state == MediaSessionCompatApi14.STATE_PLAYING && position > 0) { 74 long diff = 0; 75 if (updateTime > 0) { 76 diff = currTime - updateTime; 77 if (speed > 0 && speed != 1f) { 78 diff *= speed; 79 } 80 } 81 position += diff; 82 } 83 state = MediaSessionCompatApi14.getRccStateFromState(state); 84 ((RemoteControlClient) rccObj).setPlaybackState(state, position, speed); 85 } 86 setTransportControlFlags(Object rccObj, long actions)87 public static void setTransportControlFlags(Object rccObj, long actions) { 88 ((RemoteControlClient) rccObj).setTransportControlFlags( 89 getRccTransportControlFlagsFromActions(actions)); 90 } 91 setOnPlaybackPositionUpdateListener(Object rccObj, Object onPositionUpdateObj)92 public static void setOnPlaybackPositionUpdateListener(Object rccObj, 93 Object onPositionUpdateObj) { 94 ((RemoteControlClient) rccObj).setPlaybackPositionUpdateListener( 95 (RemoteControlClient.OnPlaybackPositionUpdateListener) onPositionUpdateObj); 96 } 97 getRccTransportControlFlagsFromActions(long actions)98 static int getRccTransportControlFlagsFromActions(long actions) { 99 int transportControlFlags = 100 MediaSessionCompatApi14.getRccTransportControlFlagsFromActions(actions); 101 if ((actions & ACTION_SEEK_TO) != 0) { 102 transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE; 103 } 104 return transportControlFlags; 105 } 106 107 static class OnPlaybackPositionUpdateListener<T extends Callback> 108 implements RemoteControlClient.OnPlaybackPositionUpdateListener { 109 protected final T mCallback; 110 OnPlaybackPositionUpdateListener(T callback)111 public OnPlaybackPositionUpdateListener(T callback) { 112 mCallback = callback; 113 } 114 115 @Override onPlaybackPositionUpdate(long newPositionMs)116 public void onPlaybackPositionUpdate(long newPositionMs) { 117 mCallback.onSeekTo(newPositionMs); 118 } 119 } 120 121 interface Callback { onSeekTo(long pos)122 public void onSeekTo(long pos); 123 } 124 } 125