/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v4.media; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.media.RemoteControlClient; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.ViewTreeObserver; class TransportMediatorJellybeanMR2 implements RemoteControlClient.OnGetPlaybackPositionListener, RemoteControlClient.OnPlaybackPositionUpdateListener { final Context mContext; final AudioManager mAudioManager; final View mTargetView; final TransportMediatorCallback mTransportCallback; final String mReceiverAction; final IntentFilter mReceiverFilter; final Intent mIntent; final ViewTreeObserver.OnWindowAttachListener mWindowAttachListener = new ViewTreeObserver.OnWindowAttachListener() { @Override public void onWindowAttached() { windowAttached(); } @Override public void onWindowDetached() { windowDetached(); } }; final ViewTreeObserver.OnWindowFocusChangeListener mWindowFocusListener = new ViewTreeObserver.OnWindowFocusChangeListener() { @Override public void onWindowFocusChanged(boolean hasFocus) { if (hasFocus) gainFocus(); else loseFocus(); } }; final BroadcastReceiver mMediaButtonReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { try { KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); mTransportCallback.handleKey(event); } catch (ClassCastException e) { Log.w("TransportController", e); } } }; AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { mTransportCallback.handleAudioFocusChange(focusChange); } }; PendingIntent mPendingIntent; RemoteControlClient mRemoteControl; boolean mFocused; int mPlayState = 0; boolean mAudioFocused; public TransportMediatorJellybeanMR2(Context context, AudioManager audioManager, View view, TransportMediatorCallback transportCallback) { mContext = context; mAudioManager = audioManager; mTargetView = view; mTransportCallback = transportCallback; mReceiverAction = context.getPackageName() + ":transport:" + System.identityHashCode(this); mIntent = new Intent(mReceiverAction); mIntent.setPackage(context.getPackageName()); mReceiverFilter = new IntentFilter(); mReceiverFilter.addAction(mReceiverAction); mTargetView.getViewTreeObserver().addOnWindowAttachListener(mWindowAttachListener); mTargetView.getViewTreeObserver().addOnWindowFocusChangeListener(mWindowFocusListener); } public Object getRemoteControlClient() { return mRemoteControl; } public void destroy() { windowDetached(); mTargetView.getViewTreeObserver().removeOnWindowAttachListener(mWindowAttachListener); mTargetView.getViewTreeObserver().removeOnWindowFocusChangeListener(mWindowFocusListener); } void windowAttached() { mContext.registerReceiver(mMediaButtonReceiver, mReceiverFilter); mPendingIntent = PendingIntent.getBroadcast(mContext, 0, mIntent, PendingIntent.FLAG_CANCEL_CURRENT); mRemoteControl = new RemoteControlClient(mPendingIntent); mRemoteControl.setOnGetPlaybackPositionListener(this); mRemoteControl.setPlaybackPositionUpdateListener(this); } void gainFocus() { if (!mFocused) { mFocused = true; mAudioManager.registerMediaButtonEventReceiver(mPendingIntent); mAudioManager.registerRemoteControlClient(mRemoteControl); if (mPlayState == RemoteControlClient.PLAYSTATE_PLAYING) { takeAudioFocus(); } } } void takeAudioFocus() { if (!mAudioFocused) { mAudioFocused = true; mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); } } public void startPlaying() { if (mPlayState != RemoteControlClient.PLAYSTATE_PLAYING) { mPlayState = RemoteControlClient.PLAYSTATE_PLAYING; mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); } if (mFocused) { takeAudioFocus(); } } @Override public long onGetPlaybackPosition() { return mTransportCallback.getPlaybackPosition(); } @Override public void onPlaybackPositionUpdate(long newPositionMs) { mTransportCallback.playbackPositionUpdate(newPositionMs); } public void refreshState(boolean playing, long position, int transportControls) { if (mRemoteControl != null) { mRemoteControl.setPlaybackState(playing ? RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_STOPPED, position, playing ? 1 : 0); mRemoteControl.setTransportControlFlags(transportControls); } } public void pausePlaying() { if (mPlayState == RemoteControlClient.PLAYSTATE_PLAYING) { mPlayState = RemoteControlClient.PLAYSTATE_PAUSED; mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED); } dropAudioFocus(); } public void stopPlaying() { if (mPlayState != RemoteControlClient.PLAYSTATE_STOPPED) { mPlayState = RemoteControlClient.PLAYSTATE_STOPPED; mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); } dropAudioFocus(); } void dropAudioFocus() { if (mAudioFocused) { mAudioFocused = false; mAudioManager.abandonAudioFocus(mAudioFocusChangeListener); } } void loseFocus() { dropAudioFocus(); if (mFocused) { mFocused = false; mAudioManager.unregisterRemoteControlClient(mRemoteControl); mAudioManager.unregisterMediaButtonEventReceiver(mPendingIntent); } } void windowDetached() { loseFocus(); if (mPendingIntent != null) { mContext.unregisterReceiver(mMediaButtonReceiver); mPendingIntent.cancel(); mPendingIntent = null; mRemoteControl = null; } } }