TransportController.java revision c76d76a0d92a9dca5c91c68b86666d403ac0fd3c
1d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn/* 2d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Copyright (C) 2013 The Android Open Source Project 3d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * 4d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 5d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * you may not use this file except in compliance with the License. 6d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * You may obtain a copy of the License at 7d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * 8d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 9d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * 10d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Unless required by applicable law or agreed to in writing, software 11d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 12d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * See the License for the specific language governing permissions and 14d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * limitations under the License. 15d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 16d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 17d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornpackage android.support.v4.media; 18d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 19d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.app.Activity; 20d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.content.Context; 21d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.media.AudioManager; 22d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.os.Build; 23d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.support.v4.view.KeyEventCompat; 24d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.view.KeyEvent; 25d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornimport android.view.View; 26d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 27d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn/** 28d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Helper for implementing a media transport control (with play, pause, skip, and 29d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * other media actions). Takes care of both key events and advanced features 30d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * like {@link android.media.RemoteControlClient}. 31d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 32d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornpublic class TransportController { 33d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final Context mContext; 34d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final Callbacks mCallbacks; 35d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final AudioManager mAudioManager; 36d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final View mView; 37d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final Object mDispatcherState; 38d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final TransportControllerJellybeanMR2 mController; 39c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn final TransportControllerJellybeanMR2.TransportCallback mTransportKeyCallback 40c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn = new TransportControllerJellybeanMR2.TransportCallback() { 41c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn @Override 42d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public void handleKey(KeyEvent key) { 43d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn key.dispatch(mKeyEventCallback); 44d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 45c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn @Override 46c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn public void handleAudioFocusChange(int focusChange) { 47c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn mCallbacks.onAudioFocusChange(TransportController.this, focusChange); 48c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 49d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn }; 50d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 51d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** Synonym for {@link KeyEvent#KEYCODE_MEDIA_PLAY KeyEvent.KEYCODE_MEDIA_PLAY} */ 52d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static final int KEYCODE_MEDIA_PLAY = 126; 53d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** Synonym for {@link KeyEvent#KEYCODE_MEDIA_PAUSE KeyEvent.KEYCODE_MEDIA_PAUSE} */ 54d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static final int KEYCODE_MEDIA_PAUSE = 127; 55d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** Synonym for {@link KeyEvent#KEYCODE_MEDIA_RECORD KeyEvent.KEYCODE_MEDIA_RECORD} */ 56d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static final int KEYCODE_MEDIA_RECORD = 130; 57d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 58d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn static boolean isMediaKey(int keyCode) { 59d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn switch (keyCode) { 60d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_PLAY: 61d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_PAUSE: 62d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 63d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MUTE: 64d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_HEADSETHOOK: 65d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_STOP: 66d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_NEXT: 67d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 68d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_REWIND: 69d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_RECORD: 70d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { 71d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 72d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 73d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 74d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return false; 75d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 76d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 77d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final KeyEvent.Callback mKeyEventCallback = new KeyEvent.Callback() { 78d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn @Override 79d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyDown(int keyCode, KeyEvent event) { 80d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return isMediaKey(keyCode) ? mCallbacks.onMediaButtonDown(keyCode, event) : false; 81d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 82d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 83d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyLongPress(int keyCode, KeyEvent event) { 84d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return false; 85d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 86d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 87d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn @Override 88d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyUp(int keyCode, KeyEvent event) { 89d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return isMediaKey(keyCode) ? mCallbacks.onMediaButtonUp(keyCode, event) : false; 90d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 91d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 92d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn @Override 93d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { 94d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return false; 95d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 96d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn }; 97d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 98d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 99d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Class through which you receive information about media transport actions. 100d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * These may either come from key events dispatched directly to your UI, or 101d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * events sent over a media button event receiver that this class keeps active 102d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * while your window is in focus. 103d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 104d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static class Callbacks { 105c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn /** 106c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * Report that a media button has been pressed. This is like 107c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent)} but 108c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * will only deliver media keys. 109c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * @param keyCode The code of the media key. 110c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * @param event The full key event. 111c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * @return Indicate whether the key has been consumed. The default 112c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * implementation always returns true. This only matters for keys 113c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * being dispatched here from 114c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link TransportController#dispatchKeyEvent(android.view.KeyEvent) 115c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * TransportController.dispatchKeyEvent}, and determines whether the key 116c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * continues on to its default key handling (which for media keys means 117c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * being delivered to the current media remote control, which should 118c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * be us). 119c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn */ 120d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onMediaButtonDown(int keyCode, KeyEvent event) { 121d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 122d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 123c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn 124c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn /** 125c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * Report that a media button has been pressed. This is like 126c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link KeyEvent.Callback#onKeyUp(int, android.view.KeyEvent)} but 127c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * will only deliver media keys. 128c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * @param keyCode The code of the media key. 129c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * @param event The full key event. 130c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * @return Indicate whether the key has been consumed. The default 131c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * implementation always returns true. This only matters for keys 132c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * being dispatched here from 133c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link TransportController#dispatchKeyEvent(android.view.KeyEvent) 134c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * TransportController.dispatchKeyEvent}, and determines whether the key 135c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * continues on to its default key handling (which for media keys means 136c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * being delivered to the current media remote control, which should 137c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * be us). 138c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn */ 139d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onMediaButtonUp(int keyCode, KeyEvent event) { 140d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 141d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 142c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn 143c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn /** 144c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * Report that audio focus has changed on the app. This only happens if 145c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * you have indicated you have started playing with 146c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link TransportController#startPlaying TransportController.startPlaying}, 147c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * which takes audio focus for you. 148c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * @param focusChange The type of focus change, as per 149c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link android.media.AudioManager.OnAudioFocusChangeListener#onAudioFocusChange(int) 150c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * OnAudioFocusChangeListener.onAudioFocusChange}. The default implementation will 151c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * deliver a {@link KeyEvent#KEYCODE_MEDIA_STOP} 152c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * when receiving {@link android.media.AudioManager#AUDIOFOCUS_LOSS}, 153c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link KeyEvent#KEYCODE_MEDIA_PAUSE} 154c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * when receiving {@link android.media.AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} 155c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * or {@link android.media.AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, and 156c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * {@link KeyEvent#KEYCODE_MEDIA_PLAY} 157c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * when receiving {@link android.media.AudioManager#AUDIOFOCUS_GAIN}. 158c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn */ 159c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn public void onAudioFocusChange(TransportController transport, int focusChange) { 160c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn transport.handleAudioFocusChange(focusChange); 161c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 162d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 163d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 164d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public TransportController(Activity activity, Callbacks callbacks) { 165d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn this(activity, null, callbacks); 166d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 167d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 168d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public TransportController(View view, Callbacks callbacks) { 169d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn this(null, view, callbacks); 170d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 171d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 172d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn private TransportController(Activity activity, View view, Callbacks callbacks) { 173d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mContext = activity != null ? activity : view.getContext(); 174d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mCallbacks = callbacks; 175d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 176d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mView = activity != null ? activity.getWindow().getDecorView() : view; 177d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mDispatcherState = KeyEventCompat.getKeyDispatcherState(mView); 178d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn if (Build.VERSION.SDK_INT >= 18 || Build.VERSION.CODENAME.equals("JellyBeanMR2")) { 179d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mController = new TransportControllerJellybeanMR2(mContext, mAudioManager, 180d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mView, mTransportKeyCallback); 181d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } else { 182d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mController = null; 183d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 184d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 185d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 186d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 187d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Return the {@link android.media.RemoteControlClient} associated with this transport. 188d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * This returns a generic Object since the RemoteControlClient is not availble before 189d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}. Further, this class 190d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * will not use RemoteControlClient in its implementation until 191d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}. You should always check for 192d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * null here and not do anything with the RemoteControlClient if none is given; this 193d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * way you don't need to worry about the current platform API version. 194d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 195d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public Object getRemoteControlClient() { 196d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return mController != null ? mController.getRemoteControlClient() : null; 197d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 198d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 199d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 200d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Must call from {@link Activity#dispatchKeyEvent Activity.dispatchKeyEvent} to give 201d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * the transport an opportunity to intercept media keys. Any such keys will show up 202d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * in {@link Callbacks}. 203d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * @param event 204d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * @return 205d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 206d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 207d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return KeyEventCompat.dispatch(event, mKeyEventCallback, mDispatcherState, this); 208d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 209d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 210d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 211c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * Move the controller into the playing state. This updates the remote control 212c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * client to indicate it is playing, and takes audio focus for the app. 213c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn */ 214c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn public void startPlaying() { 215c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn if (mController != null) { 216c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn mController.startPlaying(); 217c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 218c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 219c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn 220c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn /** 221c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * Move the controller into the paused state. This updates the remote control 222c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * client to indicate it is paused, but keeps audio focus. 223c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn */ 224c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn public void pausePlaying() { 225c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn if (mController != null) { 226c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn mController.pausePlaying(); 227c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 228c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 229c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn 230c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn /** 231c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * Move the controller into the stopped state. This updates the remote control 232c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn * client to indicate it is stopped, and removes audio focus from the app. 233c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn */ 234c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn public void stopPlaying() { 235c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn if (mController != null) { 236c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn mController.stopPlaying(); 237c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 238c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 239c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn 240c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn /** 241d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Optionally call when no longer using the TransportController. Its resources 242d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * will also be automatically cleaned up when your activity/view is detached from 243d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * its window, so you don't normally need to call this explicitly. 244d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 245d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public void destroy() { 246d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mController.destroy(); 247d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 248c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn 249c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn void handleAudioFocusChange(int focusChange) { 250c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn if (mController != null) { 251c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn mController.handleAudioFocusChange(focusChange); 252c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 253c76d76a0d92a9dca5c91c68b86666d403ac0fd3cDianne Hackborn } 254d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn} 255