| /* |
| * 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.os.SystemClock; |
| import android.view.KeyEvent; |
| |
| /** |
| * Implemented by the playback side of the media system, to respond to |
| * requests to perform actions and to retrieve its current state. These |
| * requests may either come from key events dispatched directly to your UI, or |
| * events sent over a media button event receiver that this class keeps active |
| * while your window is in focus. |
| */ |
| public abstract class TransportPerformer { |
| /** |
| * Request to start playback on the media, resuming from whatever current state |
| * (position etc) it is in. |
| */ |
| public abstract void onStart(); |
| |
| /** |
| * Request to pause playback of the media, staying at the current playback position |
| * and other state so a later call to {@link #onStart()} will resume at the same place. |
| */ |
| public abstract void onPause(); |
| |
| /** |
| * Request to completely stop playback of the media, clearing whatever state the |
| * player thinks is appropriate. |
| */ |
| public abstract void onStop(); |
| |
| /** |
| * Request to return the duration of the current media, in milliseconds. |
| */ |
| public abstract long onGetDuration(); |
| |
| /** |
| * Request to return the current playback position, in milliseconds. |
| */ |
| public abstract long onGetCurrentPosition(); |
| |
| /** |
| * Request to move the current playback position. |
| * @param pos New position to move to, in milliseconds. |
| */ |
| public abstract void onSeekTo(long pos); |
| |
| /** |
| * Request to find out whether the player is currently playing its media. |
| */ |
| public abstract boolean onIsPlaying(); |
| |
| /** |
| * Request to find out how much of the media has been buffered on the local device. |
| * @return Return a percentage (0-100) indicating how much of the total data |
| * has been buffered. The default implementation returns 100, meaning the content |
| * is always on the local device. |
| */ |
| public int onGetBufferPercentage() { |
| return 100; |
| } |
| |
| /** |
| * Retrieves the flags for the media transport control buttons that this transport supports. |
| * Result is a combination of the following flags: |
| * {@link TransportMediator#FLAG_KEY_MEDIA_PREVIOUS}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_REWIND}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_PLAY}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_PLAY_PAUSE}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_PAUSE}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_STOP}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_FAST_FORWARD}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_NEXT} |
| * |
| * <p>The default implementation returns: |
| * {@link TransportMediator#FLAG_KEY_MEDIA_PLAY}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_PLAY_PAUSE}, |
| * {@link TransportMediator#FLAG_KEY_MEDIA_PAUSE}, and |
| * {@link TransportMediator#FLAG_KEY_MEDIA_STOP}</p> |
| */ |
| public int onGetTransportControlFlags() { |
| return TransportMediator.FLAG_KEY_MEDIA_PLAY |
| | TransportMediator.FLAG_KEY_MEDIA_PLAY_PAUSE |
| | TransportMediator.FLAG_KEY_MEDIA_PAUSE |
| | TransportMediator.FLAG_KEY_MEDIA_STOP; |
| } |
| |
| /** |
| * Report that a media button has been pressed. This is like |
| * {@link android.view.KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent)} but |
| * will only deliver media keys. The default implementation handles these keys: |
| * <ul> |
| * <li>KEYCODE_MEDIA_PLAY: call {@link #onStart}</li> |
| * <li>KEYCODE_MEDIA_PAUSE: call {@link #onPause}</li> |
| * <li>KEYCODE_MEDIA_STOP: call {@link #onStop}</li> |
| * <li>KEYCODE_MEDIA_PLAY_PAUSE and KEYCODE_HEADSETHOOK: call {@link #onPause} |
| * if {@link #onIsPlaying()} returns true, otherwise call {@link #onStart}</li> |
| * </ul> |
| * @param keyCode The code of the media key. |
| * @param event The full key event. |
| * @return Indicate whether the key has been consumed. The default |
| * implementation always returns true. This only matters for keys |
| * being dispatched here from |
| * {@link TransportMediator#dispatchKeyEvent(android.view.KeyEvent) |
| * TransportController.dispatchKeyEvent}, and determines whether the key |
| * continues on to its default key handling (which for media keys means |
| * being delivered to the current media remote control, which should |
| * be us). |
| */ |
| public boolean onMediaButtonDown(int keyCode, KeyEvent event) { |
| switch (keyCode) { |
| case TransportMediator.KEYCODE_MEDIA_PLAY: |
| onStart(); |
| return true; |
| case TransportMediator.KEYCODE_MEDIA_PAUSE: |
| onPause(); |
| return true; |
| case KeyEvent.KEYCODE_MEDIA_STOP: |
| onStop(); |
| return true; |
| case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: |
| case KeyEvent.KEYCODE_HEADSETHOOK: |
| if (onIsPlaying()) { |
| onPause(); |
| } else { |
| onStart(); |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Report that a media button has been released. This is like |
| * {@link KeyEvent.Callback#onKeyUp(int, android.view.KeyEvent)} but |
| * will only deliver media keys. The default implementation does nothing. |
| * @param keyCode The code of the media key. |
| * @param event The full key event. |
| * @return Indicate whether the key has been consumed. The default |
| * implementation always returns true. This only matters for keys |
| * being dispatched here from |
| * {@link TransportMediator#dispatchKeyEvent(android.view.KeyEvent) |
| * TransportController.dispatchKeyEvent}, and determines whether the key |
| * continues on to its default key handling (which for media keys means |
| * being delivered to the current media remote control, which should |
| * be us). |
| */ |
| public boolean onMediaButtonUp(int keyCode, KeyEvent event) { |
| return true; |
| } |
| |
| // Copy constants from framework since we can't link to them. |
| static final int AUDIOFOCUS_GAIN = 1; |
| static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; |
| static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; |
| static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN; |
| static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT; |
| static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = |
| -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; |
| |
| /** |
| * Report that audio focus has changed on the app. This only happens if |
| * you have indicated you have started playing with |
| * {@link TransportMediator#startPlaying TransportController.startPlaying}, |
| * which takes audio focus for you. |
| * @param focusChange The type of focus change, as per |
| * {@link android.media.AudioManager.OnAudioFocusChangeListener#onAudioFocusChange(int) |
| * OnAudioFocusChangeListener.onAudioFocusChange}. The default implementation will |
| * deliver a {@link KeyEvent#KEYCODE_MEDIA_STOP} |
| * when receiving {@link android.media.AudioManager#AUDIOFOCUS_LOSS}. |
| */ |
| public void onAudioFocusChange(int focusChange) { |
| int keyCode = 0; |
| switch (focusChange) { |
| case AUDIOFOCUS_LOSS: |
| // This will cause us to stop playback, which means we drop audio focus |
| // so we will not get any further audio focus gain. |
| keyCode = TransportMediator.KEYCODE_MEDIA_PAUSE; |
| break; |
| } |
| if (keyCode != 0) { |
| final long now = SystemClock.uptimeMillis(); |
| onMediaButtonDown(keyCode, new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0)); |
| onMediaButtonUp(keyCode, new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0)); |
| } |
| } |
| } |