TransportController.java revision d3a70800e5f2cc2855d53ebea82fb7568affe02a
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 Hackbornimport android.widget.MediaController; 27d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 28d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn/** 29d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Helper for implementing a media transport control (with play, pause, skip, and 30d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * other media actions). Takes care of both key events and advanced features 31d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * like {@link android.media.RemoteControlClient}. 32d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 33d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackbornpublic class TransportController { 34d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final Context mContext; 35d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final Callbacks mCallbacks; 36d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final AudioManager mAudioManager; 37d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final View mView; 38d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final Object mDispatcherState; 39d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final TransportControllerJellybeanMR2 mController; 40d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final TransportControllerJellybeanMR2.KeyCallback mTransportKeyCallback 41d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn = new TransportControllerJellybeanMR2.KeyCallback() { 42d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public void handleKey(KeyEvent key) { 43d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn key.dispatch(mKeyEventCallback); 44d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 45d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn }; 46d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 47d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** Synonym for {@link KeyEvent#KEYCODE_MEDIA_PLAY KeyEvent.KEYCODE_MEDIA_PLAY} */ 48d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static final int KEYCODE_MEDIA_PLAY = 126; 49d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** Synonym for {@link KeyEvent#KEYCODE_MEDIA_PAUSE KeyEvent.KEYCODE_MEDIA_PAUSE} */ 50d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static final int KEYCODE_MEDIA_PAUSE = 127; 51d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** Synonym for {@link KeyEvent#KEYCODE_MEDIA_RECORD KeyEvent.KEYCODE_MEDIA_RECORD} */ 52d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static final int KEYCODE_MEDIA_RECORD = 130; 53d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 54d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn static boolean isMediaKey(int keyCode) { 55d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn switch (keyCode) { 56d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_PLAY: 57d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_PAUSE: 58d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 59d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MUTE: 60d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_HEADSETHOOK: 61d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_STOP: 62d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_NEXT: 63d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 64d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_REWIND: 65d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_RECORD: 66d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { 67d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 68d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 69d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 70d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return false; 71d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 72d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 73d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn final KeyEvent.Callback mKeyEventCallback = new KeyEvent.Callback() { 74d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn @Override 75d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyDown(int keyCode, KeyEvent event) { 76d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return isMediaKey(keyCode) ? mCallbacks.onMediaButtonDown(keyCode, event) : false; 77d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 78d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 79d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyLongPress(int keyCode, KeyEvent event) { 80d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return false; 81d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 82d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 83d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn @Override 84d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyUp(int keyCode, KeyEvent event) { 85d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return isMediaKey(keyCode) ? mCallbacks.onMediaButtonUp(keyCode, event) : false; 86d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 87d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 88d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn @Override 89d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { 90d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return false; 91d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 92d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn }; 93d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 94d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 95d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Class through which you receive information about media transport actions. 96d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * These may either come from key events dispatched directly to your UI, or 97d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * events sent over a media button event receiver that this class keeps active 98d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * while your window is in focus. 99d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 100d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static class Callbacks { 101d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onMediaButtonDown(int keyCode, KeyEvent event) { 102d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 103d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 104d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onMediaButtonUp(int keyCode, KeyEvent event) { 105d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 106d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 107d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 108d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 109d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 110d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Convenience implementation of {@link Callbacks} that transforms key 111d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * actions to operations on a {@link MediaController.MediaPlayerControl}. 112d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 113d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public static class PlayerControlCallbacks extends Callbacks { 114d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn private final MediaController.MediaPlayerControl mPlayerControl; 115d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 116d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public PlayerControlCallbacks(MediaController.MediaPlayerControl playerControl) { 117d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mPlayerControl = playerControl; 118d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 119d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 120d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean onMediaButtonDown(int keyCode, KeyEvent event) { 121d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn switch (keyCode) { 122d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_PLAY: 123d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mPlayerControl.start(); 124d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 125d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KEYCODE_MEDIA_PAUSE: 126d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_STOP: 127d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mPlayerControl.pause(); 128d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 129d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 130d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn case KeyEvent.KEYCODE_HEADSETHOOK: 131d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn if (mPlayerControl.isPlaying()) { 132d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mPlayerControl.pause(); 133d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } else { 134d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mPlayerControl.start(); 135d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 136d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 137d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return true; 138d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 139d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 140d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 141d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public TransportController(Activity activity, Callbacks callbacks) { 142d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn this(activity, null, callbacks); 143d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 144d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 145d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public TransportController(View view, Callbacks callbacks) { 146d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn this(null, view, callbacks); 147d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 148d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 149d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn private TransportController(Activity activity, View view, Callbacks callbacks) { 150d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mContext = activity != null ? activity : view.getContext(); 151d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mCallbacks = callbacks; 152d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 153d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mView = activity != null ? activity.getWindow().getDecorView() : view; 154d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mDispatcherState = KeyEventCompat.getKeyDispatcherState(mView); 155d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn if (Build.VERSION.SDK_INT >= 18 || Build.VERSION.CODENAME.equals("JellyBeanMR2")) { 156d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mController = new TransportControllerJellybeanMR2(mContext, mAudioManager, 157d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mView, mTransportKeyCallback); 158d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } else { 159d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mController = null; 160d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 161d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 162d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 163d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 164d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Return the {@link android.media.RemoteControlClient} associated with this transport. 165d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * This returns a generic Object since the RemoteControlClient is not availble before 166d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}. Further, this class 167d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * will not use RemoteControlClient in its implementation until 168d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}. You should always check for 169d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * null here and not do anything with the RemoteControlClient if none is given; this 170d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * way you don't need to worry about the current platform API version. 171d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 172d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public Object getRemoteControlClient() { 173d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return mController != null ? mController.getRemoteControlClient() : null; 174d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 175d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 176d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 177d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Must call from {@link Activity#dispatchKeyEvent Activity.dispatchKeyEvent} to give 178d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * the transport an opportunity to intercept media keys. Any such keys will show up 179d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * in {@link Callbacks}. 180d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * @param event 181d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * @return 182d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 183d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 184d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn return KeyEventCompat.dispatch(event, mKeyEventCallback, mDispatcherState, this); 185d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 186d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn 187d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn /** 188d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * Optionally call when no longer using the TransportController. Its resources 189d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * will also be automatically cleaned up when your activity/view is detached from 190d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn * its window, so you don't normally need to call this explicitly. 191d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn */ 192d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn public void destroy() { 193d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn mController.destroy(); 194d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn } 195d3a70800e5f2cc2855d53ebea82fb7568affe02aDianne Hackborn} 196