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 17package android.support.v4.media; 18 19import android.app.PendingIntent; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.media.AudioManager; 25import android.media.RemoteControlClient; 26import android.util.Log; 27import android.view.KeyEvent; 28import android.view.View; 29import android.view.ViewTreeObserver; 30 31class TransportMediatorJellybeanMR2 { 32 final Context mContext; 33 final AudioManager mAudioManager; 34 final View mTargetView; 35 final TransportMediatorCallback mTransportCallback; 36 final String mReceiverAction; 37 final IntentFilter mReceiverFilter; 38 final Intent mIntent; 39 final ViewTreeObserver.OnWindowAttachListener mWindowAttachListener = 40 new ViewTreeObserver.OnWindowAttachListener() { 41 @Override 42 public void onWindowAttached() { 43 windowAttached(); 44 } 45 @Override 46 public void onWindowDetached() { 47 windowDetached(); 48 } 49 }; 50 final ViewTreeObserver.OnWindowFocusChangeListener mWindowFocusListener = 51 new ViewTreeObserver.OnWindowFocusChangeListener() { 52 @Override 53 public void onWindowFocusChanged(boolean hasFocus) { 54 if (hasFocus) gainFocus(); 55 else loseFocus(); 56 } 57 }; 58 final BroadcastReceiver mMediaButtonReceiver = new BroadcastReceiver() { 59 @Override 60 public void onReceive(Context context, Intent intent) { 61 try { 62 KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 63 mTransportCallback.handleKey(event); 64 } catch (ClassCastException e) { 65 Log.w("TransportController", e); 66 } 67 } 68 }; 69 AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener 70 = new AudioManager.OnAudioFocusChangeListener() { 71 @Override 72 public void onAudioFocusChange(int focusChange) { 73 mTransportCallback.handleAudioFocusChange(focusChange); 74 } 75 }; 76 final RemoteControlClient.OnGetPlaybackPositionListener mGetPlaybackPositionListener 77 = new RemoteControlClient.OnGetPlaybackPositionListener() { 78 @Override 79 public long onGetPlaybackPosition() { 80 return mTransportCallback.getPlaybackPosition(); 81 } 82 }; 83 final RemoteControlClient.OnPlaybackPositionUpdateListener mPlaybackPositionUpdateListener 84 = new RemoteControlClient.OnPlaybackPositionUpdateListener() { 85 public void onPlaybackPositionUpdate(long newPositionMs) { 86 mTransportCallback.playbackPositionUpdate(newPositionMs); 87 } 88 }; 89 90 PendingIntent mPendingIntent; 91 RemoteControlClient mRemoteControl; 92 boolean mFocused; 93 int mPlayState = 0; 94 boolean mAudioFocused; 95 96 public TransportMediatorJellybeanMR2(Context context, AudioManager audioManager, 97 View view, TransportMediatorCallback transportCallback) { 98 mContext = context; 99 mAudioManager = audioManager; 100 mTargetView = view; 101 mTransportCallback = transportCallback; 102 mReceiverAction = context.getPackageName() + ":transport:" + System.identityHashCode(this); 103 mIntent = new Intent(mReceiverAction); 104 mIntent.setPackage(context.getPackageName()); 105 mReceiverFilter = new IntentFilter(); 106 mReceiverFilter.addAction(mReceiverAction); 107 mTargetView.getViewTreeObserver().addOnWindowAttachListener(mWindowAttachListener); 108 mTargetView.getViewTreeObserver().addOnWindowFocusChangeListener(mWindowFocusListener); 109 } 110 111 public Object getRemoteControlClient() { 112 return mRemoteControl; 113 } 114 115 public void destroy() { 116 windowDetached(); 117 mTargetView.getViewTreeObserver().removeOnWindowAttachListener(mWindowAttachListener); 118 mTargetView.getViewTreeObserver().removeOnWindowFocusChangeListener(mWindowFocusListener); 119 } 120 121 void windowAttached() { 122 mContext.registerReceiver(mMediaButtonReceiver, mReceiverFilter); 123 mPendingIntent = PendingIntent.getBroadcast(mContext, 0, mIntent, 124 PendingIntent.FLAG_CANCEL_CURRENT); 125 mRemoteControl = new RemoteControlClient(mPendingIntent); 126 mRemoteControl.setOnGetPlaybackPositionListener(mGetPlaybackPositionListener); 127 mRemoteControl.setPlaybackPositionUpdateListener(mPlaybackPositionUpdateListener); 128 } 129 130 void gainFocus() { 131 if (!mFocused) { 132 mFocused = true; 133 mAudioManager.registerMediaButtonEventReceiver(mPendingIntent); 134 mAudioManager.registerRemoteControlClient(mRemoteControl); 135 if (mPlayState == RemoteControlClient.PLAYSTATE_PLAYING) { 136 takeAudioFocus(); 137 } 138 } 139 } 140 141 void takeAudioFocus() { 142 if (!mAudioFocused) { 143 mAudioFocused = true; 144 mAudioManager.requestAudioFocus(mAudioFocusChangeListener, 145 AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); 146 } 147 } 148 149 public void startPlaying() { 150 if (mPlayState != RemoteControlClient.PLAYSTATE_PLAYING) { 151 mPlayState = RemoteControlClient.PLAYSTATE_PLAYING; 152 mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); 153 } 154 if (mFocused) { 155 takeAudioFocus(); 156 } 157 } 158 159 public void refreshState(boolean playing, long position, int transportControls) { 160 if (mRemoteControl != null) { 161 mRemoteControl.setPlaybackState(playing ? RemoteControlClient.PLAYSTATE_PLAYING 162 : RemoteControlClient.PLAYSTATE_STOPPED, position, playing ? 1 : 0); 163 mRemoteControl.setTransportControlFlags(transportControls); 164 } 165 } 166 167 public void pausePlaying() { 168 if (mPlayState == RemoteControlClient.PLAYSTATE_PLAYING) { 169 mPlayState = RemoteControlClient.PLAYSTATE_PAUSED; 170 mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED); 171 } 172 dropAudioFocus(); 173 } 174 175 public void stopPlaying() { 176 if (mPlayState != RemoteControlClient.PLAYSTATE_STOPPED) { 177 mPlayState = RemoteControlClient.PLAYSTATE_STOPPED; 178 mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); 179 } 180 dropAudioFocus(); 181 } 182 183 void dropAudioFocus() { 184 if (mAudioFocused) { 185 mAudioFocused = false; 186 mAudioManager.abandonAudioFocus(mAudioFocusChangeListener); 187 } 188 } 189 190 void loseFocus() { 191 dropAudioFocus(); 192 if (mFocused) { 193 mFocused = false; 194 mAudioManager.unregisterRemoteControlClient(mRemoteControl); 195 mAudioManager.unregisterMediaButtonEventReceiver(mPendingIntent); 196 } 197 } 198 199 void windowDetached() { 200 loseFocus(); 201 if (mPendingIntent != null) { 202 mContext.unregisterReceiver(mMediaButtonReceiver); 203 mPendingIntent.cancel(); 204 mPendingIntent = null; 205 mRemoteControl = null; 206 } 207 } 208} 209